From 73de0a12b33f8a03e07e5937d4fc52a05d3681ca Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Fri, 18 Sep 2020 15:21:44 +0200 Subject: [PATCH 1/9] make pip quiet and update submodule --- .circleci/config.yml | 2 +- common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2bc55843..3485e34b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,7 +43,7 @@ jobs: command: | python3 -m venv venv . venv/bin/activate - pip install -r ./common/build_tools/requirements.txt + pip install -q -r ./common/build_tools/requirements.txt - save_cache: paths: - ./venv diff --git a/common b/common index 9370eb97..c0df5ddb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 9370eb9719ba44e8a0e563187361a65d5d03c226 +Subproject commit c0df5ddb276278931e2263199514173e768c55dd From c05b1850d1cd4ec6f4b3198d93800158f53c512f Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Fri, 18 Sep 2020 15:39:34 +0200 Subject: [PATCH 2/9] fix spaces trailing and double spaces --- docs/Concepts/AccountManagement.md | 10 +- docs/Concepts/Architecture.md | 10 +- docs/Concepts/Cakeshop.md | 4 +- docs/Concepts/Consensus/Overview.md | 16 +- docs/Concepts/Consensus/Raft.md | 16 +- docs/Concepts/NetworkAndChainID.md | 6 +- .../Permissioning/BasicNetworkPermissions.md | 8 +- .../Permissioning/Enhanced/ContractDesign.md | 6 +- .../Enhanced/EnhancedPermissionsOverview.md | 10 +- .../Permissioning/PermissionsOverview.md | 4 +- docs/Concepts/Plugins/Plugins.md | 24 +- docs/Concepts/Privacy/ContractExtension.md | 2 +- docs/Concepts/Privacy/Privacy.md | 8 +- docs/Concepts/Privacy/PrivateAndPublic.md | 16 +- .../Privacy/PrivateTransactionLifecycle.md | 18 +- .../Privacy/PrivateTransactionManager.md | 4 +- docs/Concepts/Profiling.md | 14 +- .../FrontendComponents.md | 6 +- .../SmartContractsSecurity.md | 22 +- .../GoQuorumNetworkSecurity/Consortium.md | 8 +- .../Framework/GoQuorumNetworkSecurity/Node.md | 20 +- .../OpertionalConsiderations.md | 2 +- .../TransactionManager.md | 10 +- docs/Concepts/Security/Framework/Overview.md | 6 +- docs/HowTo/Configure/BasicPermissions.md | 4 +- docs/HowTo/Configure/EnhancedPermissions.md | 8 +- docs/HowTo/Configure/GenesisOptions.md | 4 +- docs/HowTo/Configure/HighAvailability.md | 16 +- docs/HowTo/Configure/dns.md | 14 +- docs/HowTo/DevelopPlugins.md | 18 +- docs/HowTo/GetStarted/Cakeshop.md | 12 +- .../GetStarted/GettingStartedOverview.md | 20 +- docs/HowTo/GetStarted/Install.md | 2 +- .../HowTo/GetStarted/Wizard/GettingStarted.md | 2 +- docs/HowTo/GetStarted/Wizard/Interacting.md | 22 +- docs/HowTo/GetStarted/migration.md | 8 +- docs/HowTo/ManageKeys/AccountPlugins.md | 12 +- docs/HowTo/ManageKeys/clef.md | 16 +- docs/HowTo/Use/AddingIBFTValidators.md | 128 +++++----- docs/HowTo/Use/DevelopingSmartContracts.md | 10 +- docs/HowTo/Use/EnhancedPermissions.md | 34 +-- docs/HowTo/Use/JSON-RPC-API-Security.md | 36 +-- docs/HowTo/Use/add_node_examples.md | 180 +++++++------- docs/HowTo/Use/adding_nodes.md | 78 +++--- docs/HowTo/Use/graphql.md | 4 +- docs/HowTo/Use/import-export.md | 14 +- docs/Reference/APIs/PermissioningAPIs.md | 2 +- docs/Reference/APIs/PrivacyAPI.md | 50 ++-- docs/Reference/CakeshopFAQ.md | 12 +- docs/Reference/Consensus/IBFTParameters.md | 20 +- docs/Reference/Consensus/Raft-RPC-API.md | 2 +- docs/Reference/FAQ.md | 36 +-- docs/Reference/GoQuorum-Projects.md | 4 +- .../Plugins/security/For-Developers.md | 8 +- docs/Reference/Plugins/security/For-Users.md | 14 +- docs/Reference/quorum.js/Overview.md | 2 +- .../quorum.js/RawTransactionManager.md | 32 +-- docs/Reference/quorum.js/extend.md | 2 +- docs/Tutorials/CreatePermissionedNetwork.md | 4 +- .../Creating-A-Network-From-Scratch.md | 230 +++++++++--------- docs/Tutorials/permissioned-nodes.md | 2 +- docs/index.md | 14 +- 62 files changed, 663 insertions(+), 663 deletions(-) diff --git a/docs/Concepts/AccountManagement.md b/docs/Concepts/AccountManagement.md index 9537e301..71d1477a 100644 --- a/docs/Concepts/AccountManagement.md +++ b/docs/Concepts/AccountManagement.md @@ -1,13 +1,13 @@ # Account/Key Management -Cryptographic keys are an essential component of a GoQuorum network. GoQuorum uses keys to create digital -signatures which verify a sender's identity and prevent message tampering. The Privacy Manager uses keys to encrypt private transaction data. +Cryptographic keys are an essential component of a GoQuorum network. GoQuorum uses keys to create digital +signatures which verify a sender's identity and prevent message tampering. The Privacy Manager uses keys to encrypt private transaction data. -Both GoQuorum and the Privacy Manager use user-provided asymmetric key pairs. Each key pair consists -of a public key and a private key. The public key can be shared freely, but **the private key should never be shared**. +Both GoQuorum and the Privacy Manager use user-provided asymmetric key pairs. Each key pair consists +of a public key and a private key. The public key can be shared freely, but **the private key should never be shared**. * GoQuorum derives the account address from the public key by taking the last 20 bytes of its keccak256 hash * The Privacy Manager uses the public key as an identifier for the target nodes of a private transaction (i.e. the `privateFor` transaction field) Key management determines how [GoQuorum](../HowTo/ManageKeys/ManagingKeys.md) and [Tessera](https://docs.tessera.consensys.net) -store and use private keys. +store and use private keys. diff --git a/docs/Concepts/Architecture.md b/docs/Concepts/Architecture.md index d33c8be3..44486e5b 100644 --- a/docs/Concepts/Architecture.md +++ b/docs/Concepts/Architecture.md @@ -1,8 +1,8 @@ --- -description: Overview of GoQuorum Architecture +description: Overview of GoQuorum Architecture --- -# Architecture +# Architecture ![](../images/Quorum%20Design.png) @@ -18,7 +18,7 @@ GoQuorum includes the following modifications to geth: * The block generation logic is modified to replace the `global state root` check with a `global public state root` check. * The block validation logic is modified to replace the ‘global state root’ in the block header with the ‘global public state root’ * The State Patricia trie has been split into two: a public state trie and a private state trie. - * Block validation logic is modified to handle private transactions. + * Block validation logic is modified to handle private transactions. * Transaction creation is modified to allow for transaction data to be replaced by encrypted hashes - to preserve private data where required. - * The pricing of gas is removed. Gas itself remains. + to preserve private data where required. + * The pricing of gas is removed. Gas itself remains. diff --git a/docs/Concepts/Cakeshop.md b/docs/Concepts/Cakeshop.md index a8522906..ca6fa80e 100644 --- a/docs/Concepts/Cakeshop.md +++ b/docs/Concepts/Cakeshop.md @@ -21,10 +21,10 @@ It provides tools for managing a local blockchain node, setting up clusters, exploring the state of the chain, and working with contracts. The Cakeshop package includes [Tessera](https://docs.tessera.consensys.net), a [Solidity](https://solidity.readthedocs.org/en/latest/) -compiler, and all dependencies. +compiler, and all dependencies. Cakeshop downloads the latest version of [GoQuorum](https://github.com/ConsenSys/quorum) and bootnode from [geth](https://github.com/ethereum/go-ethereum). To use a different version, see -[here](https://github.com/ConsenSys/cakeshop/blob/master/docs/configuration.md#custom-quorum-binaries). +[here](https://github.com/ConsenSys/cakeshop/blob/master/docs/configuration.md#custom-quorum-binaries). [Get started with Cakeshop.](../HowTo/GetStarted/Cakeshop.md) diff --git a/docs/Concepts/Consensus/Overview.md b/docs/Concepts/Consensus/Overview.md index b472cd8a..946b7e1b 100644 --- a/docs/Concepts/Consensus/Overview.md +++ b/docs/Concepts/Consensus/Overview.md @@ -1,19 +1,19 @@ -# Consensus Mechanisms +# Consensus Mechanisms With no need for Proof of Work (PoW) in a permissioned network, GoQuorum instead implements multiple -consensus mechanisms that are more appropriate for consortium chains: +consensus mechanisms that are more appropriate for consortium chains: * Raft-based - - A consensus model for faster blocktimes, transaction finality, and on-demand block creation. + + A consensus model for faster blocktimes, transaction finality, and on-demand block creation. See [Raft-based documentation](Raft.md) for more information * Istanbul BFT (Byzantine Fault Tolerance) - + A PBFT-inspired consensus algorithm with immediate transaction finality, by AMIS. See [IBFT documentation](IBFT.md), the [RPC API](../../Reference/Consensus/IBFT-RPC-API.md), - and this [technical web article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). + and this [technical web article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). * Clique Proof of Authority (PoA) - - A default POA consensus algorithm bundled with Go Ethereum. See [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://hackernoon.com/hands-on-creating-your-own-local-private-geth-node-beginner-friendly-3d45902cc612) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/) + + A default POA consensus algorithm bundled with Go Ethereum. See [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://hackernoon.com/hands-on-creating-your-own-local-private-geth-node-beginner-friendly-3d45902cc612) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/) diff --git a/docs/Concepts/Consensus/Raft.md b/docs/Concepts/Consensus/Raft.md index f862df23..ffc65519 100644 --- a/docs/Concepts/Consensus/Raft.md +++ b/docs/Concepts/Consensus/Raft.md @@ -8,7 +8,7 @@ When the `geth` binary is passed the `--raft` flag, the node will operate in "ra ## Some implementation basics -!!! note +!!! note Though we use the etcd implementation of the Raft protocol, we speak of "Raft" more broadly to refer to the Raft protocol, and its use to achieve consensus for Quorum/Ethereum. Both Raft and Ethereum have their own notion of a "node": @@ -18,7 +18,7 @@ In Raft, a node in normal operation can be a "leader", "follower" or "learner." ### Leader - mints blocks and sends the blocks to the verifier and learner nodes - takes part in voting during re-election and can become verifier if it does not win majority of votes -- the network triggers re-election if the leader node dies. +- the network triggers re-election if the leader node dies. - can add/remove learner/verifier and promote learner to verifier ### Verifier @@ -30,10 +30,10 @@ In Raft, a node in normal operation can be a "leader", "follower" or "learner." ### Learner - follows the leader -- applies the blocks minted by the leader +- applies the blocks minted by the leader - cannot take part in voting during re-election - cannot become a verifier on its own -- it needs to be promoted to be a verifier by a leader or verifier +- it needs to be promoted to be a verifier by a leader or verifier - it cannot add learner/verifier or promote learner to verifier - it cannot remove other learner/verifier but it can remove itself @@ -48,7 +48,7 @@ Ethereum | Raft minter | leader verifier | follower -A learner node is passive node that just syncs blocks and can initiate transactions. +A learner node is passive node that just syncs blocks and can initiate transactions. The main reasons we co-locate the leader and minter are (1) convenience, in that Raft ensures there is only one leader at a time, and (2) to avoid a network hop from a node minting blocks to the leader, through which all Raft writes must flow. Our implementation watches Raft leadership changes -- if a node becomes a leader it will start minting, and if a node loses its leadership, it will stop minting. @@ -174,7 +174,7 @@ We communicate blocks over the HTTP transport layer built in to etcd Raft. It's GoQuorum listens on port 50400 by default for the raft transport, but this is configurable with the `--raftport` flag. -Default number of peers is set to be 25. Max number of peers is configurable with the `--maxpeers N` where N is expected size of the cluster. +Default number of peers is set to be 25. Max number of peers is configurable with the `--maxpeers N` where N is expected size of the cluster. ## Initial configuration, and enacting membership changes @@ -183,8 +183,8 @@ Currently Raft-based consensus requires that all _initial_ nodes in the cluster To remove a node from the cluster, attach to a JS console and issue `raft.removePeer(raftId)`, where `raftId` is the number of the node you wish to remove. For initial nodes in the cluster, this number is the 1-indexed position of the node's enode ID in the static peers list. Once a node has been removed from the cluster, it is permanent; this raft ID can not ever re-connect to the cluster in the future, and the party must re-join the cluster with a new raft ID. * To add a verifier node to the cluster, attach to a JS console and issue `raft.addPeer(enodeId)` -* To add a learner node to the cluster, attach to a JS console and issue `raft.addLearner(enodeId)` -* To promote a learner to become verifier in the cluster, attach to a JS console of leader/verifier node and issue `raft.promoteToPeer(raftId)`. +* To add a learner node to the cluster, attach to a JS console and issue `raft.addLearner(enodeId)` +* To promote a learner to become verifier in the cluster, attach to a JS console of leader/verifier node and issue `raft.promoteToPeer(raftId)`. Note that like the enode IDs listed in the static peers JSON file, this enode ID should include a `raftport` querystring parameter. This call will allocate and return a raft ID that was not already in use. After `addPeer`, start the new geth node with the flag `--raftjoinexisting RAFTID` in addition to `--raft`. diff --git a/docs/Concepts/NetworkAndChainID.md b/docs/Concepts/NetworkAndChainID.md index f964376c..cc656212 100644 --- a/docs/Concepts/NetworkAndChainID.md +++ b/docs/Concepts/NetworkAndChainID.md @@ -4,19 +4,19 @@ An Ethereum network is run using a Network ID and a Chain ID. The network ID is a property of a peer, not of the chain the peer is managing. Network ID is passed in via the command line by `--networkid `. Its purpose is to separate peers that are running under a -different network ID. You cannot sync with anyone who is running a node with a different network ID. +different network ID. You cannot sync with anyone who is running a node with a different network ID. However, since it is trivial to change this, it is a less secure version of GoQuorum's `--permissioned` flag, and it only used for simple segregation. The chain ID is a property of the chain managed by the node. It is used for replay protection of transactions. Setting the chain ID has the effect of changing one of the parameters of a transaction, namely the `V` parameter. -The `v` parameter is set to `2*ChainID + 35/36`. For the Ethereum Mainnet, which has a chain ID of `1`, +The `v` parameter is set to `2*ChainID + 35/36`. For the Ethereum Mainnet, which has a chain ID of `1`, this means that all transactions have a value of either `37` or `38`. The chain ID set in the genesis configuration file, in the `config` section, and is only used when the block number is above the one set at `eip155Block`. See the [quorum-examples genesis files](../Reference/genesis.md) for an example. It can be changed as many times as needed while the chain is below the `eip155Block` number -and re-rerunning `geth init` - this will not delete or modify any current sync process or saved blocks. +and re-rerunning `geth init` - this will not delete or modify any current sync process or saved blocks. In GoQuorum, transactions are considered private if the `v` parameter is set to `37` or `38`, which clashes with networks which have a Chain ID of `1`. For this reason, GoQuorum will not run using chain ID `1` and will diff --git a/docs/Concepts/Permissioning/BasicNetworkPermissions.md b/docs/Concepts/Permissioning/BasicNetworkPermissions.md index 5ade159e..ef8f1f7e 100644 --- a/docs/Concepts/Permissioning/BasicNetworkPermissions.md +++ b/docs/Concepts/Permissioning/BasicNetworkPermissions.md @@ -13,16 +13,16 @@ file then this node can neither connect to any node nor accept any incoming conn The `permissioned-nodes.json` file follows the below pattern, which is similar to the `/static-nodes.json` file that is used to specify the list of static nodes a given node always connects to: ``` json - [ + [ "enode://remoteky1@ip1:port1", "enode://remoteky1@ip2:port2", - "enode://remoteky1@ip3:port3", + "enode://remoteky1@ip3:port3", ] ``` - + Sample file: (node id truncated for clarity) ``` json - [ + [ "enode://6598638ac5b15ee386210156a43f565fa8c485924894e2f3a967207c047470@127.0.0.1:30300", ] ``` diff --git a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md index a5f59b98..9da0b047 100644 --- a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md +++ b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md @@ -7,7 +7,7 @@ The permissions smart contract design follows the Proxy-Implementation-Storage p the implementation logic to change without changing the storage or interface layer. A brief description of the smart contracts is below: * `PermissionsUpgradable.sol`: This contract stores the address of current implementation contract and -is owned by a guardian (an Ethereum account). Only the guardian is allowed to change the implementation contract address. +is owned by a guardian (an Ethereum account). Only the guardian is allowed to change the implementation contract address. * `PermissionsInterface.sol`: This is the interface contract and holds the interfaces for permissions related actions. It has no business logic and forwards requests to the current implementation contract * `PermissionsImplementation.sol`: This contract has the business logic for the permissions actions. It @@ -23,12 +23,12 @@ status - `PendingApproval`, `Active`, `Suspended`, `Blacklisted` or `Revoked` in `PermissionsUpgradable.sol`. It stores the data of a node, its linkage to an organization or sub organization, and status of the node. The node can be in any one of the following status - `PendingApproval`, `Approved`, `Deactivated` or `Blacklisted` * `RoleManager.sol`: This contract receives requests from a valid implementation contract as defined in `PermissionsUpgradable.sol`. -It stores data for various roles and the organization to which it is linked. The access at role level can be any one of the following: +It stores data for various roles and the organization to which it is linked. The access at role level can be any one of the following: - `Readonly` which allows only read operations - `Transact` which allows value transfer but no contract deployment access - `ContractDeploy` which allows both value transfer and contract deployment access - `FullAccess` which allows additional network level accesses in addition to value transfer and contract deployment - + If a role is revoked all accounts which are linked to the role lose all access rights * `VoterManager.sol`: This contract receives requests from a valid implementation contract as defined in `PermissionsUpgradable.sol`. diff --git a/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md b/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md index 544904c4..ea37c34f 100644 --- a/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md +++ b/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md @@ -4,7 +4,7 @@ The Enhanced Permissions Model caters for enterprise-level needs by having a sma This allows for significant flexibility to manage nodes, accounts, and account-level access controls. An overview of the model is as depicted below: -![permissions mode](../../../images/PermissionsModel.png) +![permissions mode](../../../images/PermissionsModel.png) ### Key Definitions @@ -19,13 +19,13 @@ An overview of the model is as depicted below: As depicted above, in the enhanced permissions model, the network comprises a group of organizations. The network admin accounts defined at network level can propose and approve new organizations to join the network, and can assign an account as the organization administration account. The organization admin -account can create roles, create sub organizations, assign roles to its accounts, and add any other node -which is part of the organization. A sub organization can have its own set of roles, accounts and -suborganizations. The organization administration account manages and controls all activities at the +account can create roles, create sub organizations, assign roles to its accounts, and add any other node +which is part of the organization. A sub organization can have its own set of roles, accounts and +suborganizations. The organization administration account manages and controls all activities at the organization level. The organization administrator can create an admin role and assign the same to a different account to manage the administration of a sub organization. The access rights of an account are derived based on the role assigned to it. The account will be able to transact via any node linked to -the sub org or at overall organizations level. +the sub org or at overall organizations level. A sample network view is as depicted below: ![sample mode](../../../images/sampleNetwork.png) diff --git a/docs/Concepts/Permissioning/PermissionsOverview.md b/docs/Concepts/Permissioning/PermissionsOverview.md index 1c1f9a3e..b29910f3 100644 --- a/docs/Concepts/Permissioning/PermissionsOverview.md +++ b/docs/Concepts/Permissioning/PermissionsOverview.md @@ -1,10 +1,10 @@ # Permissioning -GoQuorum supports two network permissioning models. +GoQuorum supports two network permissioning models. * [Basic network permissioning](BasicNetworkPermissions.md) Controls which nodes can connect to a given node and also to which nodes the given node can dial out to. * [Enhanced network permissioning](Enhanced/EnhancedPermissionsOverview.md) - Caters for enterprise-level needs by having a **smart contract-based permissioning model**. This allows + Caters for enterprise-level needs by having a **smart contract-based permissioning model**. This allows for significant flexibility to manage nodes, accounts, and account-level access controls. diff --git a/docs/Concepts/Plugins/Plugins.md b/docs/Concepts/Plugins/Plugins.md index 82d017de..295a1cbc 100644 --- a/docs/Concepts/Plugins/Plugins.md +++ b/docs/Concepts/Plugins/Plugins.md @@ -1,11 +1,11 @@ # GoQuorum Plugins The GoQuorum client is a modified `geth` client. One of the unique enhancements -is the pluggable architecture which allows adding additional features as plugins to the core `geth`, +is the pluggable architecture which allows adding additional features as plugins to the core `geth`, providing extensibility, flexibility, and isolation of GoQuorum features. ## Benefits - + This enhancement provides a number of benefits, including: 1. Allowing the implementation of certain components of the GoQuorum client to be changed at configuration time. @@ -19,14 +19,14 @@ Plugins are executed as a separate process and communicate with the main GoQuoru over a [gRPC](https://grpc.io/) interface. The plugin implementation must adhere to certain gRPC services defined in a `.proto` file corresponding to the plugin interface. -Plugins can be written in different languages as gRPC provides a mechanism to generate stub code from `.proto` files. +Plugins can be written in different languages as gRPC provides a mechanism to generate stub code from `.proto` files. The network communication and RPC are handled automatically by the [high-level plugin library](https://github.com/hashicorp/go-plugin). ## Installing Plugins Currently plugins must be manually installed into a directory (defaults to `plugins` directory inside `geth` data directory - default can be overriden by setting `baseDir` in [plugins settings](../../HowTo/Configure/Plugins.md)). - + ## Using Plugins [Plugins settings file](../../HowTo/Configure/Plugins.md) contains a JSON that describes what plugins to be used. @@ -39,23 +39,23 @@ geth ... \ ## Plugin Integrity Verification -Plugin Central Server can be used to download and verify plugin integrity using [PGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy). -The architecture enables the same verification process locally via `--plugins.localverify` and `--plugins.publickey` flags or -remotely with custom plugin central - reference the [`Settings`](../../HowTo/Configure/Plugins.md) section for more information on how to support custom plugin central. +Plugin Central Server can be used to download and verify plugin integrity using [PGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy). +The architecture enables the same verification process locally via `--plugins.localverify` and `--plugins.publickey` flags or +remotely with custom plugin central - reference the [`Settings`](../../HowTo/Configure/Plugins.md) section for more information on how to support custom plugin central. If the flag `--plugins.skipverify` is provided at runtime the plugin verification process will be disabled. !!! warning - Using `--plugins.skipverify` is not advised for production settings and it should be avoided as it introduces security risks. + Using `--plugins.skipverify` is not advised for production settings and it should be avoided as it introduces security risks. ## Example: `HelloWorld` plugin -The plugin interface is implemented in Go and Java. In this example, `HelloWorld` plugin exposes a JSON RPC endpoint +The plugin interface is implemented in Go and Java. In this example, `HelloWorld` plugin exposes a JSON RPC endpoint to return a greeting message in the configured language. This plugin is [reloadable](../../Concepts/Plugins/PluginsArchitecture.md#plugin-reloading). It means -that the plugin can take changes from its JSON configuration. +that the plugin can take changes from its JSON configuration. -### Build plugin distribution file +### Build plugin distribution file 1. Clone plugin repository ```bash @@ -67,7 +67,7 @@ that the plugin can take changes from its JSON configuration. quorum-plugin-hello-world› cd go quorum-plugin-hello-world/go› make ``` - `quorum-plugin-hello-world-1.0.0.zip` is now created in `build` directory. + `quorum-plugin-hello-world-1.0.0.zip` is now created in `build` directory. Noticed that there's a file `hello-world-plugin-config.json` which is the JSON configuration file for the plugin. ### Start GoQuorum with plugin support diff --git a/docs/Concepts/Privacy/ContractExtension.md b/docs/Concepts/Privacy/ContractExtension.md index d5aaa043..af86864a 100644 --- a/docs/Concepts/Privacy/ContractExtension.md +++ b/docs/Concepts/Privacy/ContractExtension.md @@ -23,7 +23,7 @@ In this example, private contract is being extended from Nodes A to Node B. address of this extension, and node B's PTM public key as the target receiver. - **1a** - Node A creates the extension contract with user given inputs and Node B's PTM public key - **1b** - the private transaction payload is shared with Tessera of node B. - - **1c** - The public state is propagated across all nodes. Nodes A and B see an emitted log, + - **1c** - The public state is propagated across all nodes. Nodes A and B see an emitted log, and start watching the contract address that emitted the event for subsequent events that may happen 1. Node A automatically approves the contract extension by virtue of creating the extension contract. diff --git a/docs/Concepts/Privacy/Privacy.md b/docs/Concepts/Privacy/Privacy.md index beb63af7..4a629e7e 100644 --- a/docs/Concepts/Privacy/Privacy.md +++ b/docs/Concepts/Privacy/Privacy.md @@ -1,8 +1,8 @@ --- -description: Privacy +description: Privacy --- -# Privacy +# Privacy In GoQuorum, privacy refers to the ability to keep transactions private between the involved participants. Other participants cannot access the transaction content. @@ -11,7 +11,7 @@ Other participants cannot access the transaction content. [Tessera](https://docs.tessera.consensys.net) is private transaction manager for GoQuorum. Tessera stores and allows access to encrypted transaction data, and exchanges encrypted payloads with other Tessera nodes but does not -have access to any sensitive private keys. Tessera uses the enclave for cryptographic functionality. +have access to any sensitive private keys. Tessera uses the enclave for cryptographic functionality. The enclave can optionally be hosted by the private transaction manager itself. Tessera is restful/stateless and can be load balanced easily. @@ -22,7 +22,7 @@ Distributed ledger protocols leverage cryptographic techniques for transaction a authentication, and historical data preservation (that is, through a chain of cryptographically hashed data). To achieve a separation of concerns, as well as to provide performance improvements through parallelization of certain crypto-operations, much of the cryptographic work including symmetric key generation and data -encryption/decryption is delegated to the enclave. +encryption/decryption is delegated to the enclave. The enclave works with the private transaction manager to strengthen privacy by managing the encryption and decryption in isolation. The enclave holds private keys and is essentially a _virtual HSM_ isolated diff --git a/docs/Concepts/Privacy/PrivateAndPublic.md b/docs/Concepts/Privacy/PrivateAndPublic.md index a0750c69..559567c9 100644 --- a/docs/Concepts/Privacy/PrivateAndPublic.md +++ b/docs/Concepts/Privacy/PrivateAndPublic.md @@ -1,12 +1,12 @@ # Transaction and Contract Privacy GoQuorum achieves Transaction Privacy by: - + 1. Enabling transaction Senders to create a private transaction by marking who is privy to that transaction via the `privateFor` parameter 2. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction - 3. Storing encrypted private data off-chain in a separate component called the [Privacy Manager](PrivateTransactionManager.md). The Privacy Manager encrypts private data, distributes the encrypted data to other parties that are privy to the transaction, and returns the decrypted payload to those parties + 3. Storing encrypted private data off-chain in a separate component called the [Privacy Manager](PrivateTransactionManager.md). The Privacy Manager encrypts private data, distributes the encrypted data to other parties that are privy to the transaction, and returns the decrypted payload to those parties -GoQuorum introduces the notion of 'Public Transactions' and 'Private Transactions'. Note that this is a notional concept only and GoQuorum does not introduce new Transaction Types, but rather, the Ethereum Transaction Model has been extended to include an optional `privateFor` parameter (the population of which results in a Transaction being treated as private by GoQuorum) and the Transaction Type has a new `IsPrivate` method to identify such Transactions. +GoQuorum introduces the notion of 'Public Transactions' and 'Private Transactions'. Note that this is a notional concept only and GoQuorum does not introduce new Transaction Types, but rather, the Ethereum Transaction Model has been extended to include an optional `privateFor` parameter (the population of which results in a Transaction being treated as private by GoQuorum) and the Transaction Type has a new `IsPrivate` method to identify such Transactions. ## Public Transactions Public Transactions are those Transactions whose payload is visible to all participants of the same GoQuorum network. These are [created as standard Ethereum Transactions in the usual way](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethsendtransaction). @@ -14,23 +14,23 @@ Public Transactions are those Transactions whose payload is visible to all parti Examples of Public Transactions may include Market Data updates from some service provider, or some reference data update such as a correction to a Bond Security definition. !!! Note - GoQuorum Public Transactions are not Transactions from the public Ethereum network. Perhaps a more appropriate term would be 'common' or 'global' Transactions, but 'Public' is used to contrast with 'Private' Transactions. + GoQuorum Public Transactions are not Transactions from the public Ethereum network. Perhaps a more appropriate term would be 'common' or 'global' Transactions, but 'Public' is used to contrast with 'Private' Transactions. ## Private Transactions -Private Transactions are those Transactions whose payload is only visible to the network participants whose public keys are specified in the `privateFor` parameter of the Transaction . `privateFor` can take multiple addresses in a comma separated list. (See Creating Private Transactions under the [Developing Smart Contracts](../../HowTo/Use/DevelopingSmartContracts.md#creating-private-transactions/contracts) section). +Private Transactions are those Transactions whose payload is only visible to the network participants whose public keys are specified in the `privateFor` parameter of the Transaction . `privateFor` can take multiple addresses in a comma separated list. (See Creating Private Transactions under the [Developing Smart Contracts](../../HowTo/Use/DevelopingSmartContracts.md#creating-private-transactions/contracts) section). When the GoQuorum Node encounters a Transaction with a non-null `privateFor` value, it sets the `V` value of the Transaction Signature to be either `37` or `38` (as opposed to `27` or `28` which are the values used to indicate a Transaction is 'public' as per standard Ethereum as specified in the Ethereum yellow paper). ## Public vs Private Transaction Handling Public Transactions are executed in the standard Ethereum way, and so if a Public Transaction is sent to an Account that holds Contract code, each participant will execute the same code and their underlying StateDBs will be updated accordingly. -Private Transactions, however, are not executed per standard Ethereum: prior to the sender's GoQuorum Node propagating the Transaction to the rest of the network, it replaces the original Transaction Payload with a hash of the encrypted Payload that it receives from Constellation/Tessera. Participants that are party to the Transaction will be able to replace the hash with the actual payload via their Constellation/Tessera instance, whilst those Participants that are not party will only see the hash. +Private Transactions, however, are not executed per standard Ethereum: prior to the sender's GoQuorum Node propagating the Transaction to the rest of the network, it replaces the original Transaction Payload with a hash of the encrypted Payload that it receives from Constellation/Tessera. Participants that are party to the Transaction will be able to replace the hash with the actual payload via their Constellation/Tessera instance, whilst those Participants that are not party will only see the hash. The result is that if a Private Transaction is sent to an Account that holds Contract code, those participants who are not party to the Transaction will simply end up skipping the Transaction, and therefore not execute the Contract code. However those participants that are party to the Transaction will replace the hash with the original Payload -before calling the EVM for execution, and their StateDB will be updated accordingly. In absence of making corresponding +before calling the EVM for execution, and their StateDB will be updated accordingly. In absence of making corresponding changes to the geth client, these two sets of participants would therefore end up with different StateDBs and not be able to reach consensus. So in order to support this bifurcation of contract state, Quorum stores the state of Public contracts in a Public State Trie that is globally synchronised, and it stores the state of Private contracts -in a Private State Trie that is not synchronised globally. +in a Private State Trie that is not synchronised globally. diff --git a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md index d52e5b01..db4686a3 100644 --- a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md +++ b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md @@ -7,12 +7,12 @@ In this example, Party A and Party B are party to Transaction AB, whilst Party C 1. Party A sends a Transaction to their GoQuorum Node, specifying the Transaction payload and setting `privateFor` to be the public keys for Parties A and B (Party A is optional) 1. Party A's GoQuorum Node passes the Transaction on to its paired Transaction Manager, requesting that it encrypt and store the Transaction payload before forwarding it on to the recipients of the transaction (i.e. Party B) 1. Party A's Transaction Manager makes a call to its associated Enclave to encrypt the payload for the given recipients -1. Party A's Enclave encrypts the private transaction payload by: - - 1. generating a symmetric key (which will be referred to as *tx-key* from here on) and two random nonces +1. Party A's Enclave encrypts the private transaction payload by: + + 1. generating a symmetric key (which will be referred to as *tx-key* from here on) and two random nonces 1. encrypting the Transaction payload with this tx-key and one of the nonces 1. encrypting the tx-key separately for each recipient by: - + 1. deriving the ECDH (elliptic-curve Diffie-Hellman) shared symmetric key (*shared-key*) from the sender's (A's) private key and the recipient's (B's) public key 1. encrypting the tx-key with the shared-key and the other nonce 1. repeating this for all recipients (i.e. for *n* recipients there will be *n* unique encrypted tx-keys) (the nonce is unchanged for each recipient as the shared-key being used changes) @@ -26,11 +26,11 @@ In this example, Party A and Party B are party to Transaction AB, whilst Party C 1. serialising the data 1. pushing the serialised data to the recipient (in this case Party B's Transaction Manager) 1. ensuring the push was successful (if a single recipient fails to respond or returns an error then the process will stop here - i.e. it is a requirement that all recipients have stored the encrypted payload before the transaction can be propagated at the GoQuorum level and written to the blockchain) - 1. repeating this for all recipients -1. Party A's Transaction Manager returns the hash of the encrypted payload to the GoQuorum Node. GoQuorum replaces the `data` field of the Transaction with that hash, and changes the transaction's `v` value to `37` or `38`, thus marking the transaction as private and indicating that the transaction's `data` field represents the hash of an encrypted payload as opposed to executable EVM bytecode + 1. repeating this for all recipients +1. Party A's Transaction Manager returns the hash of the encrypted payload to the GoQuorum Node. GoQuorum replaces the `data` field of the Transaction with that hash, and changes the transaction's `v` value to `37` or `38`, thus marking the transaction as private and indicating that the transaction's `data` field represents the hash of an encrypted payload as opposed to executable EVM bytecode 1. The Transaction is then propagated to the rest of the network using the standard geth P2P Protocol 1. A block containing Transaction AB is created and distributed to each GoQuorum node in the network -1. In processing the block, all GoQuorum nodes attempt to process the Transaction. Recognising that the transaction `data` is a hash due to the `v` value of `37` or `38`, each node will make a call to its Transaction Manager to determine if it is party to the transaction (i.e. there is an entry for the given hash in its database). In this example, Party A & B's Transaction Managers will determine that they are party to the transaction whereas Party C's Transaction Manager will determine that it is not party +1. In processing the block, all GoQuorum nodes attempt to process the Transaction. Recognising that the transaction `data` is a hash due to the `v` value of `37` or `38`, each node will make a call to its Transaction Manager to determine if it is party to the transaction (i.e. there is an entry for the given hash in its database). In this example, Party A & B's Transaction Managers will determine that they are party to the transaction whereas Party C's Transaction Manager will determine that it is not party 1. Party A & B's Transaction Managers make a call to their associated Enclaves to decrypt the payload 1. Party A & B's Enclaves decrypt the private transaction by: 1. deriving the shared-key used in the encryption: @@ -40,7 +40,7 @@ In this example, Party A and Party B are party to Transaction AB, whilst Party C 1. decrypting the private transaction payload with the tx-key and the encrytped data and nonce retrieved from the database 1. returning to the Transaction Manager: the decrypted private transaction data 1. The Transaction Manager's return their results to their GoQuorum nodes: - 1. Party A & B's Transaction Managers return the decrypted private transaction data to their GoQuorum nodes which can now execute the transaction as normal, thus updating their respective Private StateDB. GoQuorum discards the decrypted private transaction data once used - 1. Party C's Transaction Manager returns a 404 NOT FOUND to its GoQuorum node as it is not a recipient of the transaction. Recognising that it is not party to this private transaction, the GoQuorum node will skip the execution of the transaction, so that no changes to its Private StateDB are made + 1. Party A & B's Transaction Managers return the decrypted private transaction data to their GoQuorum nodes which can now execute the transaction as normal, thus updating their respective Private StateDB. GoQuorum discards the decrypted private transaction data once used + 1. Party C's Transaction Manager returns a 404 NOT FOUND to its GoQuorum node as it is not a recipient of the transaction. Recognising that it is not party to this private transaction, the GoQuorum node will skip the execution of the transaction, so that no changes to its Private StateDB are made diff --git a/docs/Concepts/Privacy/PrivateTransactionManager.md b/docs/Concepts/Privacy/PrivateTransactionManager.md index fa7d8877..9dc8368b 100644 --- a/docs/Concepts/Privacy/PrivateTransactionManager.md +++ b/docs/Concepts/Privacy/PrivateTransactionManager.md @@ -1,7 +1,7 @@ # Private Transaction Manager GoQuorum uses a Private Transaction Manager, [Tessera](https://docs.tessera.consensys.net), to implement -private transactions. +private transactions. The Private Transaction Manager is a separate component that is concerned with the storing and distribution of encrypted private transaction data between recipients of a private transaction. @@ -11,7 +11,7 @@ node to provide the node with the path to the Privacy Manager's `.ipc` socket, e ```shell export PRIVATE_CONFIG=path/to/tm.ipc -``` +``` The Private Transaction Manager has two components: diff --git a/docs/Concepts/Profiling.md b/docs/Concepts/Profiling.md index baf600a9..51e5d431 100644 --- a/docs/Concepts/Profiling.md +++ b/docs/Concepts/Profiling.md @@ -1,9 +1,9 @@ # Quorum Profiling [Quorum Profiling](https://github.com/ConsenSys/quorum-profiling) is a custom toolset used to benchmark -transaction throughput and network statistics on any existing Quorum network using the -[Jmeter](https://github.com/ConsenSys/quorum-profiling/tree/master/jmeter-test) and -[TPS monitoring](https://github.com/ConsenSys/quorum-profiling/tree/master/tps-monitor) tool profiles. +transaction throughput and network statistics on any existing Quorum network using the +[Jmeter](https://github.com/ConsenSys/quorum-profiling/tree/master/jmeter-test) and +[TPS monitoring](https://github.com/ConsenSys/quorum-profiling/tree/master/tps-monitor) tool profiles. Alternatively, it could also be used to spin up an entire quorum network from scratch in AWS and benchmark the network for TPS, CPU/Memory usage. The various scenarios of usage is explained [here](https://github.com/ConsenSys/quorum-profiling) @@ -15,7 +15,7 @@ Key Components: metrics. Refer to Quorum Profilings config [here](https://github.com/ConsenSys/quorum-profiling/blob/master/scripts/telegraf/telegraf.conf). - [JMeter](https://jmeter.apache.org) - Load testing tool. The detail of various profiles and test execution, refer [here](https://github.com/ConsenSys/quorum-profiling/tree/master/jmeter-test) -- [TPS Monitor](https://github.com/ConsenSys/quorum-profiling/tree/master/tps-monitor) - Custom "go" project to monitor transactions per second, total transactions and total blocks in Quorum network. +- [TPS Monitor](https://github.com/ConsenSys/quorum-profiling/tree/master/tps-monitor) - Custom "go" project to monitor transactions per second, total transactions and total blocks in Quorum network. - [InfluxDB](https://www.influxdata.com/time-series-platform/influxdb/) - Open source time series database for monitoring metrics and events, providing real-time visibility. - [Prometheus](https://prometheus.io) - similar to influx prometheus records real-time metrics in a time series database built using a HTTP "pull" model, with flexible queries and real-time alerting - [Grafana](https://grafana.com) - Monitoring tool for metrics and logs consolidation @@ -29,10 +29,10 @@ The tool executes the stress test profile selected and then collects the followi These metrics could be configured to be stored in an InfluxDB or Prometheus for further analysis. Both databases integrate well with the open source dashboard editor Grafana to allow for easy creation of dashboards to visualise the data being captured from the profiling tool. Sample dashboards below: -### Sample Network Dashboard +### Sample Network Dashboard -![Quorum Network Dashboard](../images/quorumDashboard.jpeg) +![Quorum Network Dashboard](../images/quorumDashboard.jpeg) ### Sample JMeter Dashboard -![JMeter Dashboard](../images/jmeterDashboard.jpeg) +![JMeter Dashboard](../images/jmeterDashboard.jpeg) diff --git a/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md b/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md index b7c942c4..eb62ff31 100644 --- a/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md +++ b/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md @@ -1,11 +1,11 @@ ## Frontend -As any traditional application, dApps Client/Server component has to follow application security best practices. -Its recommended to use a Secure Software Development Lifecycle (SSDLC) to implement any application. +As any traditional application, dApps Client/Server component has to follow application security best practices. +Its recommended to use a Secure Software Development Lifecycle (SSDLC) to implement any application. In general Secure Development Lifecycle include the following phases : - Risk Assessment Phase. - Threat Modeling, and Secure Design Review Phase. - Static Source Code Analysis Phase. - Security Testing, and Manual Secure Source Review Phase. -- Security Assessment of Configuration of Deployment Pipeline Phase. +- Security Assessment of Configuration of Deployment Pipeline Phase. diff --git a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md index b092faba..a23e9cdf 100644 --- a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md +++ b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md @@ -1,52 +1,52 @@ **Smart Contracts Security** must be considered as any other application security. It might contain logical vulnerabilities, insecure design, and it might run on vulnerable components (ledgers). However, Smart Contracts are the core element of Ethereum Blockchain. Unlike other software it is constrained by several Blockchain technology primitives: -- Smart Contracts runtime is sandboxed; this means obtaining a secure randomness source is hard. +- Smart Contracts runtime is sandboxed; this means obtaining a secure randomness source is hard. - Smart Contracts can hold, transfer or destroy funds, making them an economic risk component. - Smart Contracts are not upgradeable unless an upgrade mechanism is introduced in the design phase. -- Smart Contracts are immutable and have an irrevocable self-destruction feature. +- Smart Contracts are immutable and have an irrevocable self-destruction feature. - Smart Contracts can have one or multiple owners. ### Ownership Unlike traditional software management process, Smart Contracts support the following technologically enforced ownership model: **Single Ownership**: -The contract has one owner who is responsible for the contract administration process. +The contract has one owner who is responsible for the contract administration process. **Shared Custody Ownership**: Suitable for agreement between two or more parties in a network of N parties; where any party can unilaterally perform administrative action over the contract. **Consortium Based Ownership**: -It is a form of expanded shared custody ownership that requires consensus over the administrative actions. +It is a form of expanded shared custody ownership that requires consensus over the administrative actions. ### Security Patterns: -**Checks-Effects-Interaction Pattern**: Interacting with other contracts should always be the last step in the contract function. It is crucial that the current contract has finished its functionality before handing control to another contract and does not depend on the execution of the other contract. +**Checks-Effects-Interaction Pattern**: Interacting with other contracts should always be the last step in the contract function. It is crucial that the current contract has finished its functionality before handing control to another contract and does not depend on the execution of the other contract. **Circuit Breaker**: It is a logical emergency stop execution logic. Implementing emergency stops in the logic of smart contract is a good security practice. A Circuit breaker can be triggered manually by trusted parties included in the contract like the contract owner or by using programmatic consensus rules that automatically trigger the circuit breaker when the defined conditions meet. **Rate Limit**: Smart contract operation within an interval allows better control of abusable resources. -**Speed Bumps**: Speed bumps introduce a delay in the action execution allowing time to act if action is considered malicious. +**Speed Bumps**: Speed bumps introduce a delay in the action execution allowing time to act if action is considered malicious. -### Common Contract Vulnerabilities +### Common Contract Vulnerabilities -**Reentrancy**: Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract, or the use of a low-level function with an external address. +**Reentrancy**: Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract, or the use of a low-level function with an external address. **Access Control**: While insecure visibility settings give attackers straightforward ways to access a contract's private values or logic, access control bypasses are sometimes more subtle. These vulnerabilities can occur when contracts use the deprecated "tx.origin" to validate callers, handle extensive authorization logic with lengthy "require" and make reckless use of "delegatecall" in proxy libraries or proxy contracts. **Arithmetic**: Integer overflows and underflows are not a new class of vulnerability, but they are especially dangerous in smart contracts, where unsigned integers are prevalent, and most developers are used to simple int types (which are often just signed integers). If overflows occur, many seemingly benign code paths become vectors for theft or denial of service. **Unchecked Low Level Calls**: One of the more in-depth features of Solidity are the low-level functions such as call(), callcode(), delegatecall() and send(). Their error handling behaviour is quite different from other Solidity functions. The errors will not surface immediately and will not lead to the total reversal of the current execution. Instead, they will return a boolean value set to false, and the code will continue to run. This scenario could surprise developers. If the return value of such low-level calls is not checked, it could lead to "fail open" situations and other unwanted outcomes. - + **Bad Randomness**: Randomness is hard to get right in Ethereum. While Solidity offers functions and variables that can access seemingly hard-to-predict values, they are generally either more public than they seem. Because randomness sources are predictable to an extent in Ethereum, malicious users can usually replicate them and attack the function relying on the unpredictability. This also applies to dApps built on top of Quorum. -**Front Running**: In public Ethereum, miners always get rewarded via gas fees for running code on behalf of externally owned addresses (EOA). Users can specify higher fees to have their transactions mined quicker. Since the Ethereum blockchain is public, everyone can see the contents of other user's pending transactions. This situation means that if a given user is revealing the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. If smart contract developers are not careful, this situation can lead to practical and devastating front-running attacks. On the other hand, since Quorum does not use Proof Of Work (PoW) as consensus algorithm and the gas cost is zero, vulnerabilities related to PoW mining are not applicable when building on top of Quorum. However, front-running remains a risk and will depend on the consensus algorithm in use. +**Front Running**: In public Ethereum, miners always get rewarded via gas fees for running code on behalf of externally owned addresses (EOA). Users can specify higher fees to have their transactions mined quicker. Since the Ethereum blockchain is public, everyone can see the contents of other user's pending transactions. This situation means that if a given user is revealing the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. If smart contract developers are not careful, this situation can lead to practical and devastating front-running attacks. On the other hand, since Quorum does not use Proof Of Work (PoW) as consensus algorithm and the gas cost is zero, vulnerabilities related to PoW mining are not applicable when building on top of Quorum. However, front-running remains a risk and will depend on the consensus algorithm in use. **Time Manipulation**: From locking a token sale to unlocking funds at a specific time, contracts sometimes need to rely on the current time. This is usually done via "block.timestamp "or it's alias "now" in Solidity. In public Ethereum, this value comes from the miners. However, in Quorum, it comes from the minter or validators. As a result, smart contracts should avoid relying strongly on the block time for critical decision making. Note that block.timestamp should not be used for the generation of random numbers. -**Short Addresses**: Short address attacks are a side effect of the EVM accepting incorrectly padded arguments. Attackers can exploit this by using specially crafted addresses to make poorly coded clients encode arguments incorrectly before including them in transactions. +**Short Addresses**: Short address attacks are a side effect of the EVM accepting incorrectly padded arguments. Attackers can exploit this by using specially crafted addresses to make poorly coded clients encode arguments incorrectly before including them in transactions. ### Security Checklist diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md index 99567db4..80b7e93e 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md @@ -1,24 +1,24 @@ When creating a Consortium the following elements should be taken in consideration: ### Governance -Chosen structure must not only be appropriate to permit efficient and effective operations of the Consortium, +Chosen structure must not only be appropriate to permit efficient and effective operations of the Consortium, but also fulfill the concerns of those that form part of it equally. ### Ownership The nature of blockchain technology also increases the risk of accidental data exposure. In order to manage this risk -ownership of Intellectual Properties (IP), and assets should be documented, and agreed upon. +ownership of Intellectual Properties (IP), and assets should be documented, and agreed upon. ### Liability Most network operational activities are benign, but this is not true in all cases, and even in otherwise low-risk Consortium, where the membership constitutes “market power” under the antitrust laws, a significant percentage of the competitors in a given product or service space might be members. The potential for inadvertent mistakes, as well as the level of potential scrutiny by government regulators, is higher. -In such a situation, individual members may wish to maintain tighter control over what can – and more importantly, what cannot – be done +In such a situation, individual members may wish to maintain tighter control over what can – and more importantly, what cannot – be done by the organization, and its members without proper prior consensus in order to reduce the risk and liability. ### Activities Interconnecting multiple independent networks comes with risk factors. In order to -build a controls to minimize a risk, the activities that are expected to be performed in the network must be documented. +build a controls to minimize a risk, the activities that are expected to be performed in the network must be documented. ### Security Checklist diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md index d4847c34..5284349a 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md @@ -1,26 +1,26 @@ -**GoQuorum Node**, aka GoQuorum Client, is a thick-client whose Private Transaction feature operation depends on a Transaction Manager Client that encrypts and decrypts -private transactions payload. Both Quorum client and its dependencies i.e, Transaction Manager, Peers, and Enclave use traditional TCP/UDP transport layer to communicate. +**GoQuorum Node**, aka GoQuorum Client, is a thick-client whose Private Transaction feature operation depends on a Transaction Manager Client that encrypts and decrypts +private transactions payload. Both Quorum client and its dependencies i.e, Transaction Manager, Peers, and Enclave use traditional TCP/UDP transport layer to communicate. -As any asset in a network its security depends on multiple elements (E.g the security of the Host, Data, and Accounts). In GoQuorum it will be the security of +As any asset in a network its security depends on multiple elements (E.g the security of the Host, Data, and Accounts). In GoQuorum it will be the security of the Client and Transaction Manager host/host-runtime, encryption keys, Consensus runtime and Network Access Controls. ### Host Security -Any asset in a GoQuorum network (Client Host, Transaction Manager Host, Private Transaction Storage Host, ..etc ) must be hardened following industry best practices. A host IDS should be used to detect any malicious activities on the host. Direct access to the host should not be allowed, instead a jump server should be used and access limited to small number of administrators. -Operating systems, software and services will have vulnerabilities. GoQuorum network hosts must implement a robust patch management program. +Any asset in a GoQuorum network (Client Host, Transaction Manager Host, Private Transaction Storage Host, ..etc ) must be hardened following industry best practices. A host IDS should be used to detect any malicious activities on the host. Direct access to the host should not be allowed, instead a jump server should be used and access limited to small number of administrators. +Operating systems, software and services will have vulnerabilities. GoQuorum network hosts must implement a robust patch management program. -### Client Security +### Client Security GoQuorum client instance exposes a JSON-Remote Procedure Call (RPC) interface through HTTP, Web Socket, or Inter-Process communication techniques. The JSON-RPC interfaces allows the remote interaction with the ledger features, and Smart Contracts. The JSON-RPC interface must be secured in order to preserve the integrity of the ledger runtime. Each client in the network must be uniquely identified. In GoQuorum this is done by using nodes identity. Node identity is represented through a public key/private key, where -the public key identifies the node in the network. GoQuorum Smart Contract Permissioning models depends on nodes identity to authorize TCP level communication between nodes, as such securing +the public key identifies the node in the network. GoQuorum Smart Contract Permissioning models depends on nodes identity to authorize TCP level communication between nodes, as such securing the private key of a node is a paramount activity required to prevent unauthorized node from joining the network. - + ### Users Security -Blockchain technology uses public key cryptography to protect the integrity of transactions and blocks. The security of a user’s Private keys is dependent on the security operation elements implemented to +Blockchain technology uses public key cryptography to protect the integrity of transactions and blocks. The security of a user’s Private keys is dependent on the security operation elements implemented to preserve the Private key from compromise. In Ethereum Accounts Private keys are encrypted with user specified seed (password). Users password should never be saved across the ecosystem or stored in ledger host in any form. - + ### Security Checklist #### Host diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md index 790be9b4..7c45ac07 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md @@ -5,7 +5,7 @@ The following parameters are of interest to be collected and analyzed: - Hosts access and events - Ethereum accounts on the network - Active ledger, transaction manager nodes in the network - - Public and Private transaction rates per account in the network. + - Public and Private transaction rates per account in the network. - Number of public Smart contracts in the network. - Network connections to ledger nodes and metadata. - Consensus protocol metadata (E.g Block creation rate, and source ...etc) diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md index 6e233c75..468db8a0 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md @@ -1,13 +1,13 @@ -### Tessera -[Tessera](https://docs.tessera.consensys.net) is GoQuorum's Transaction Manager. GoQuorum privacy features depends on Tessera to Encrypt/Decrypt, and broadcast the orchestrations of a private transaction payload. +### Tessera +[Tessera](https://docs.tessera.consensys.net) is GoQuorum's Transaction Manager. GoQuorum privacy features depends on Tessera to Encrypt/Decrypt, and broadcast the orchestrations of a private transaction payload. Tessera uses an enclave to perform the encryption/decryption of private transactions payload. The encryption keys should be stored in high secure environments such a hardware security module (HSM). Tessera communication with its dependencies (Enclave, GoQuorum node, Payload Storage Database, Secret Storage Service) must be secured. To ensure the privacy and authentication of the communication between Tessera the network must be configured to Certificate Based Mutual Authentication (MTLS). ### Encryption Keys Encryption keys is the most critical element of the privacy model, if the encryption key is compromised the network loses its privacy. Tessera support integration with Trusted Platform Modules (TPM) and Hardware Security Modules (HSM) to reduce surface attack and provide highly secure environment. -### Security Checklist - +### Security Checklist + !!! success "Tessera should run in independent network segment in production" !!! success "Tessera must leverage certificate based mutual authentication with its dependencies" @@ -16,7 +16,7 @@ Encryption keys is the most critical element of the privacy model, if the encryp !!! success "Depending on the deployment model Encryption Keys must be backed-up in offline secured locations." -!!! success "Secret storage service must be in complete isolation of external network." +!!! success "Secret storage service must be in complete isolation of external network." !!! success "Tessera connection strings must not be stored in clear text in configuration files. " diff --git a/docs/Concepts/Security/Framework/Overview.md b/docs/Concepts/Security/Framework/Overview.md index dabfb962..13284415 100644 --- a/docs/Concepts/Security/Framework/Overview.md +++ b/docs/Concepts/Security/Framework/Overview.md @@ -1,10 +1,10 @@ -## Objectives +## Objectives The **objective** of this framework is to provide an in-depth reference to Quorum and Decentralized Applications (dApps) security best practices. The following outlines the *scope* of the framework: -- Quorum architecture security +- Quorum architecture security - Quorum network security guidelines - Decentralized application (dApps) security best practices @@ -14,7 +14,7 @@ The following outlines the *scope* of the framework: + https://www.dasp.co/ + https://entethalliance.org/technical-documents/ + https://solidity.readthedocs.io/en/v0.5.7/# -+ https://nvlpubs.nist.gov/nistpubs/ir/2018/NIST.IR.8202.pdf ++ https://nvlpubs.nist.gov/nistpubs/ir/2018/NIST.IR.8202.pdf + https://ws680.nist.gov/publication/get_pdf.cfm?pub_id=925957 + https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE1TH5G + https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf diff --git a/docs/HowTo/Configure/BasicPermissions.md b/docs/HowTo/Configure/BasicPermissions.md index 384c7c15..867a6643 100644 --- a/docs/HowTo/Configure/BasicPermissions.md +++ b/docs/HowTo/Configure/BasicPermissions.md @@ -9,8 +9,8 @@ In the [basic permissions model](../../Concepts/Permissioning/BasicNetworkPermis is managed at the individual node level by using the `--permissioned` command line flag when starting the node. If a node is started with `--permissioned` set, the node looks for a `/permissioned-nodes.json` file. -This file contains the list of enodes that this node can connect to and accept connections from. In other -words, if permissioning is enabled, only the nodes that are listed in the `permissioned-nodes.json` file become part of the network. +This file contains the list of enodes that this node can connect to and accept connections from. In other +words, if permissioning is enabled, only the nodes that are listed in the `permissioned-nodes.json` file become part of the network. If `--permissioned` is set, a `permissioned-nodes.json` file must be provided. If the flag is set but no nodes are present in this file, the node is unable to make any outward connections or accept any diff --git a/docs/HowTo/Configure/EnhancedPermissions.md b/docs/HowTo/Configure/EnhancedPermissions.md index fb217e03..815322c9 100644 --- a/docs/HowTo/Configure/EnhancedPermissions.md +++ b/docs/HowTo/Configure/EnhancedPermissions.md @@ -1,4 +1,4 @@ -# Configure enhanced permissions +# Configure enhanced permissions The steps to enable the [enhanced permissions model](../../Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md) are described below: @@ -6,7 +6,7 @@ are described below: ## New network * Bring up the initial set of nodes which will be part of the network -* Deploy the `PermissionsUpgradable.sol` in the network. The deployment of this contract will require a guardian account to be given as a part of deployment. +* Deploy the `PermissionsUpgradable.sol` in the network. The deployment of this contract will require a guardian account to be given as a part of deployment. * Deploy the rest of the contracts. All the other contracts will require the address of `PermissionsUpgradable.sol` contract as a part of deployment. * Once all the contracts are deployed create a file `permission-config.json` which will have the following construct: ```json @@ -57,7 +57,7 @@ var intr = "0x4d3bfd7821e237ffe84209d8e638f9f309865b87" // address of the interf ## Migrating from an earlier version The following steps needs to be followed when migrating from a earlier version for enabling permissions feature -* Bring down the running network in the earlier version. +* Bring down the running network in the earlier version. * The `maxCodeSize` attribute in `genesis.json` need to be set to 35. Update `genesis.json` to reflect the same ```javascript "config": { @@ -76,4 +76,4 @@ The following steps needs to be followed when migrating from a earlier version f !!! Note * It should be noted that the new permission model will be in force only when `permission-config.json` is present in data directory. If this file is not there and the node is brought up with `--permissioned` flag, node level permissions as per the earlier model will be effective. - * Please ensure that `maxCodeSize` in `genesis.json` is set to 35 + * Please ensure that `maxCodeSize` in `genesis.json` is set to 35 diff --git a/docs/HowTo/Configure/GenesisOptions.md b/docs/HowTo/Configure/GenesisOptions.md index f3865e38..45736135 100644 --- a/docs/HowTo/Configure/GenesisOptions.md +++ b/docs/HowTo/Configure/GenesisOptions.md @@ -4,7 +4,7 @@ GoQuorum allows operators of blockchains to increase maximum transaction size of accepted transactions via the genesis block. The GoQuorum default is currently increased to `64kb` from Ethereum's default `32kb` -transaction size. This is configurable up to `128kb` by adding `txnSizeLimit` to the config section of the genesis file: +transaction size. This is configurable up to `128kb` by adding `txnSizeLimit` to the config section of the genesis file: ``` json "config": { @@ -19,7 +19,7 @@ transaction size. This is configurable up to `128kb` by adding `txnSizeLimit` t GoQuorum allows operators of blockchains to increase maximum contract code size of accepted smart contracts via the genesis block. The GoQuorum default is currently increased to `32kb` from Ethereum's default `24kb` -contract code size. This is configurable up to `128kb` by adding `maxCodeSize` to the config section of the genesis file: +contract code size. This is configurable up to `128kb` by adding `maxCodeSize` to the config section of the genesis file: ``` json "config": { diff --git a/docs/HowTo/Configure/HighAvailability.md b/docs/HowTo/Configure/HighAvailability.md index c9e8c997..59d9468b 100644 --- a/docs/HowTo/Configure/HighAvailability.md +++ b/docs/HowTo/Configure/HighAvailability.md @@ -4,7 +4,7 @@ GoQuorum architecture allows for end to end high availability on various i/o ope and compliance requirements. In this section we will go through an example configuration and setup: **WARNING**: Below high availability setup is an example of how to achieve end to end high availability -using proxy server but it should be noted that this hasn't been tested in a production environment setup. +using proxy server but it should be noted that this hasn't been tested in a production environment setup. ## GoQuorum Node Configuration Requirements: @@ -12,17 +12,17 @@ using proxy server but it should be noted that this hasn't been tested in a prod - The inbound RPC requests from clients will be load balanced to one of these Quorum nodes. - These nodes will need to share same key for transaction signing and should have shared access to key store directory or key vaults. - These nodes need to share the same private state. They could either connect to local Tessera node or -in 'full' HA setup using [proxy](#proxy-setup-on-both-quorum-nodes) running on each GoQuorum node +in 'full' HA setup using [proxy](#proxy-setup-on-both-quorum-nodes) running on each GoQuorum node listening on local ipc file and directing request to Tessera Q2T http but in both cases the Tessera node(s) share the same database. ## Tessera Node Configuration Requirements: -- Separate [Proxy](#standalone-proxy-server-setup) server to redirect/mirror requests to two or more Tessera nodes +- Separate [Proxy](#standalone-proxy-server-setup) server to redirect/mirror requests to two or more Tessera nodes - Two or more Tessera Nodes serve as Privacy manager for Client GoQuorum node. - These nodes share same public/private key pair (stored in password protected files or external vaults) and share same database. - In the server config, the bindingAddress should be the local addresses (their real addresses), but 'advertisedAddress' (serverAddress) needs to be configured to be the proxy - Add DB replication or mirroring for Tessera private data store and the JDBC connection string to include both Primary DB and DR DB connections to facilitate auto switchover on failure. - + ??? info "Quorum HA Setup 1" **Quorum Tessera pair share same machine/container in this setup** @@ -30,13 +30,13 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot ??? info "Quorum Full HA Setup " - **The change here is each Quorum and Tessera node run in separate machine/container** - - **Proxy running on each Quorum node to listen on local ipc file and load balance request to both Tessera nodes** + - **Proxy running on each Quorum node to listen on local ipc file and load balance request to both Tessera nodes** ![Quorum Tessera Full HA Mode](../../images/QT_HA_2.png) ??? info "Tessera HA Setup " **If HA is required only for Tessera, below setup could be adopted** ![Tessera HA Mode](../../images/Tessera_HA.png) - + ## Example Setup using nginx Proxy setup @@ -55,13 +55,13 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot listen unix:/home/ubuntu/tm.ipc; location / { # Below is added to avoid transaction failure if partyinfo gets out of sync. - proxy_next_upstream error timeout http_404 non_idempotent; + proxy_next_upstream error timeout http_404 non_idempotent; proxy_pass http://q2t; } } } ``` - + ### Standalone Proxy server setup ```c diff --git a/docs/HowTo/Configure/dns.md b/docs/HowTo/Configure/dns.md index 2d5642c7..2831d33c 100644 --- a/docs/HowTo/Configure/dns.md +++ b/docs/HowTo/Configure/dns.md @@ -1,14 +1,14 @@ # DNS for Quorum -DNS support in Quorum has two distinct areas, usage in the static nodes file and usage in the +DNS support in Quorum has two distinct areas, usage in the static nodes file and usage in the node discovery protocol. You are free to use one and not the other, or to mix them as the use case requires. ## Static nodes -Static nodes are nodes we keep reference to even if the node is not alive, so that is the nodes comes alive, +Static nodes are nodes we keep reference to even if the node is not alive, so that is the nodes comes alive, then we can connect to it. Hostnames are permitted here, and are resolved once at startup. If a static peer goes offline -and its IP address changes, then it is expected that that peer would re-establish the connection in a fully static +and its IP address changes, then it is expected that that peer would re-establish the connection in a fully static network, or have discovery enabled. ## Discovery @@ -17,15 +17,15 @@ DNS is not supported for the discovery protocol. Use a bootnode instead, which c resolved. ## Compatibility -For Raft, the whole network must be on version 2.4.0 of Quorum for DNS to function properly. DNS must +For Raft, the whole network must be on version 2.4.0 of Quorum for DNS to function properly. DNS must be explicitly enabled using the `--raftdnsenable` flag for each node once the node has migrated to version 2.4.0 of Quorum The network runs fine when some nodes are in 2.4.0 version and some in older version as long as this feature is not enabled. For safe migration the recommended approach is as below: * migrate the nodes to `geth` 2.4.0 version without using `--raftdnsenable` flag * once the network is fully migrated, restart the nodes with `--raftdnsenable` to enable the feature -Please note that in a partially migrated network (where some nodes are on version 2.4.0 and others on lower version) **with DNS feature enabled** for migrated nodes, `raft.addPeer` should not be invoked with Hostname till entire network migrates to 2.4.0 version. If invoked, this call will crash all nodes running in older version and these nodes will have to restarted with `geth` of version 2.4.0 of Quorum. `raft.addPeer` can still be invoked with IP address and network will work fine. +Please note that in a partially migrated network (where some nodes are on version 2.4.0 and others on lower version) **with DNS feature enabled** for migrated nodes, `raft.addPeer` should not be invoked with Hostname till entire network migrates to 2.4.0 version. If invoked, this call will crash all nodes running in older version and these nodes will have to restarted with `geth` of version 2.4.0 of Quorum. `raft.addPeer` can still be invoked with IP address and network will work fine. ### Note In a network where all nodes are running on Quorum version 2.4.0, with few nodes enabled for DNS, we recommend the - `--verbosity` to be 3 or below. We have observed that nodes which are not enabled for DNS fail to restart if - `raft.addPeer` is invoked with host name if `--verbosity` is set above 3. \ No newline at end of file + `--verbosity` to be 3 or below. We have observed that nodes which are not enabled for DNS fail to restart if + `raft.addPeer` is invoked with host name if `--verbosity` is set above 3. diff --git a/docs/HowTo/DevelopPlugins.md b/docs/HowTo/DevelopPlugins.md index 1e3ad214..6b3ab0db 100644 --- a/docs/HowTo/DevelopPlugins.md +++ b/docs/HowTo/DevelopPlugins.md @@ -9,7 +9,7 @@ Some advanced topics which are not available in the `go-plugin` documentation wi A plugin is started as a separate process and communicates with the GoQuorum client host process via gRPC service interfaces. This is done over a mutually-authenticated TLS connection on the local machine. The implementation is done inside `go-plugin` -library. Usage is simplest when developing plugins in Golang. For plugins written in other languages, plugin authors need to have +library. Usage is simplest when developing plugins in Golang. For plugins written in other languages, plugin authors need to have an understanding of the following lifecycle (see [Advanced topics for non-Go plugins](#advanced-topics-for-non-go-plugins) for more info): 1. `geth` looks for the plugin distribution file after reading the plugin definition from settings @@ -23,23 +23,23 @@ an understanding of the following lifecycle (see [Advanced topics for non-Go plu Each plugin must implement the [`PluginInitializer`](#plugininitializer) gRPC service interface. After the plugin process is successfully started and connection with the GoQuorum client is successfully established, -GoQuorum client invokes [`Init()`](#proto.PluginInitialization.Request) gRPC method in order to initialize the plugin with configuration data +GoQuorum client invokes [`Init()`](#proto.PluginInitialization.Request) gRPC method in order to initialize the plugin with configuration data read from the plugin definition's `config` field in [settings](Configure/Plugins.md) file. ## Distribution ### File format -Plugin distribution file must be a ZIP file. File name format is `-.zip`. +Plugin distribution file must be a ZIP file. File name format is `-.zip`. `` and `` must be the same as the values defined in the [`PluginDefinition` object](Configure/Plugins.md) in the settings file. -### Metadata +### Metadata A plugin metadata file `plugin-meta.json` must be included in the distribution ZIP file. `plugin-meta.json` contains a valid JSON object which has a flat structure with key value pairs. Although the JSON object can include any desired information. -There are mandatory key value pairs which must be present. +There are mandatory key value pairs which must be present. ```json { @@ -74,8 +74,8 @@ Some additional advanced topics are described here. ### Magic Cookie -Magic Cookie key and value are used as a very basic verification that a plugin is intended to be launched. -This is not a security measure, just a UX feature. +Magic Cookie key and value are used as a very basic verification that a plugin is intended to be launched. +This is not a security measure, just a UX feature. Magic Cookie key and value are injected as an environment variable while executing the plugin process. @@ -83,11 +83,11 @@ Magic Cookie key and value are injected as an environment variable while executi QUORUM_PLUGIN_MAGIC_COOKIE="CB9F51969613126D93468868990F77A8470EB9177503C5A38D437FEFF7786E0941152E05C06A9A3313391059132A7F9CED86C0783FE63A8B38F01623C8257664" ``` -The plugin and the GoQuorum client's magic cookies are compared. If they are equal then the plugin is loaded. If they are not equal, the plugin should show human-friendly output. +The plugin and the GoQuorum client's magic cookies are compared. If they are equal then the plugin is loaded. If they are not equal, the plugin should show human-friendly output. ### Mutual TLS Authentication -The GoQuorum client requires the plugin to authenticate and secure the connection via mutual TLS. +The GoQuorum client requires the plugin to authenticate and secure the connection via mutual TLS. `PLUGIN_CLIENT_CERT` environment variable is populated with GoQuorum Client certificate (in PEM format). A plugin would need to include this certificate to its trusted certificate pool, then generate a self-signed certificate and append the base64-encoded value of the certificate (in DER format) diff --git a/docs/HowTo/GetStarted/Cakeshop.md b/docs/HowTo/GetStarted/Cakeshop.md index 47266c6f..d918b26a 100644 --- a/docs/HowTo/GetStarted/Cakeshop.md +++ b/docs/HowTo/GetStarted/Cakeshop.md @@ -34,15 +34,15 @@ There are a few ways in which you can run Cakeshop (see the sections below for d 2\. **'Attach/Unmanaged' mode**: _Used when you want to attach Cakeshop to an already running Ethereum-like node._ - Running Cakeshop in 'Attach' a.k.a 'unmanaged' mode will initialize Cakeshop but not start it nor start any Ethereum node. Once Cakeshop initialization is complete you can configure it to use the RPC details of your running node . When you then start Cakeshop it will attach to your node. + Running Cakeshop in 'Attach' a.k.a 'unmanaged' mode will initialize Cakeshop but not start it nor start any Ethereum node. Once Cakeshop initialization is complete you can configure it to use the RPC details of your running node . When you then start Cakeshop it will attach to your node. - NOTE: if different parties on the network are using Cakeshop to deploy contracts to the network then they need to ensure they are using the same ContractRegistry address. See details below for setting up the ContractRegistry address in this case. + NOTE: if different parties on the network are using Cakeshop to deploy contracts to the network then they need to ensure they are using the same ContractRegistry address. See details below for setting up the ContractRegistry address in this case. 3\. **Multi-Instance Set Up**: _Used when you want to run Cakeshop on more than one node in your network._ Cakeshop is currently designed such that a given instance of Cakeshop works directly with a single Ethereum-like node, however you can set up multiple instances of Cakeshop on the same machine (each which could either have been started in 'Default' mode or 'Attach' mode) such that each can talk to a different node. -Note: you can use the Attach mode and/or Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. +Note: you can use the Attach mode and/or Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. #### The below commands assume you have renamed the WAR file to cakeshop.war @@ -95,7 +95,7 @@ Although Cakeshop currently has a one-to-one mapping with the underlying Ethereu > ** Cakeshop ContractRegistry contract** ->Cakeshop deploys a ContractRegistry contract upon start up that is used to track those contracts that have been deployed to the chain using Cakeshop or the Cakeshop APIs. When running a multi-instance setup, you'll want to ensure that each instance of Cakeshop references the same ContractRegistry contract in order that each provides a consistent view within the Contracts Explorer. +>Cakeshop deploys a ContractRegistry contract upon start up that is used to track those contracts that have been deployed to the chain using Cakeshop or the Cakeshop APIs. When running a multi-instance setup, you'll want to ensure that each instance of Cakeshop references the same ContractRegistry contract in order that each provides a consistent view within the Contracts Explorer. >There are two cmd flags that can be set to achieve this: @@ -158,6 +158,6 @@ In all cases, Cakeshop will be running once you see the below image, which shows ![image](https://raw.githubusercontent.com/jpmorganchase/cakeshop-docs/master/images/happylion.png) -### Cakeshop FAQ +### Cakeshop FAQ -See the [Cakeshop FAQ](../../Reference/CakeshopFAQ.md) for more information. +See the [Cakeshop FAQ](../../Reference/CakeshopFAQ.md) for more information. diff --git a/docs/HowTo/GetStarted/GettingStartedOverview.md b/docs/HowTo/GetStarted/GettingStartedOverview.md index 57bb1ab2..1a94a58f 100644 --- a/docs/HowTo/GetStarted/GettingStartedOverview.md +++ b/docs/HowTo/GetStarted/GettingStartedOverview.md @@ -12,16 +12,16 @@ local network, to configuring and creating a full network from scratch. The easiest way to get a network up and running is by using the [GoQuorum Wizard](Wizard/GettingStarted.md). This command-line tool creates a local GoQuorum network that can be started and be ready for use in minutes. The wizard provides options for configuring the network and generates all the resources to run either -in containers using `docker-compose`, or locally through the use of bash scripts. +in containers using `docker-compose`, or locally through the use of bash scripts. -The wizard requires [NodeJS](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) and runs on Linux/Mac only. +The wizard requires [NodeJS](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) and runs on Linux/Mac only. ``` npm install -g quorum-wizard quorum-wizard ``` -To explore the features of GoQuorum and deploy a private contract, follow the instructions on [Interacting with the Network](Wizard/GettingStarted.md). +To explore the features of GoQuorum and deploy a private contract, follow the instructions on [Interacting with the Network](Wizard/GettingStarted.md). ## GoQuorum Examples sample network @@ -31,22 +31,22 @@ or locally through the use of bash scripts to automate creation of the network. ## ![k8s-logo](../../images/qubernetes/k8s-logo.png){: style="height:20px;width:20px"} GoQuorum on Kubernetes -Use [qubernetes](https://github.com/ConsenSys/qubernetes) to run configurable N node GoQuorum networks on Kubernetes. - -You can use [kind](https://github.com/ConsenSys/qubernetes#quickest-start) or [Minikube](https://github.com/ConsenSys/qubernetes/blob/master/docs/minikube-docs.md) -for local development. For long running networks, use a cloud service (e.g. Google Kubernetes Engine, Azure KS, AWS EKS) or a self-hosted kubernetes cluster. +Use [qubernetes](https://github.com/ConsenSys/qubernetes) to run configurable N node GoQuorum networks on Kubernetes. + +You can use [kind](https://github.com/ConsenSys/qubernetes#quickest-start) or [Minikube](https://github.com/ConsenSys/qubernetes/blob/master/docs/minikube-docs.md) +for local development. For long running networks, use a cloud service (e.g. Google Kubernetes Engine, Azure KS, AWS EKS) or a self-hosted kubernetes cluster. Qubernetes supports Raft and Istanbul consensus algorithms, multiple versions, and networks with an arbitrary number of nodes. -Also includes [examples](https://github.com/ConsenSys/qubernetes/blob/master/docs/7nodes-on-k8s.md) ready to run on Kubernetes. +Also includes [examples](https://github.com/ConsenSys/qubernetes/blob/master/docs/7nodes-on-k8s.md) ready to run on Kubernetes. ## Creating a network from scratch [Creating a Network From Scratch](../../Tutorials/Creating-A-Network-From-Scratch.md) provides a step-by-step walkthrough -of how to create and configure a GoQuorum network suitable for either Raft or Istanbul consensus. It +of how to create and configure a GoQuorum network suitable for either Raft or Istanbul consensus. It also shows how to enable privacy and add/remove nodes as required. ## Creating a network deployed in the cloud [Quorum Cloud](https://github.com/ConsenSys/quorum-cloud) provides an example of how a GoQuorum network -can be run on a cloud platform. It uses Terraform to create a 7 node GoQuorum network deployed on AWS +can be run on a cloud platform. It uses Terraform to create a 7 node GoQuorum network deployed on AWS using AWS ECS Fargate, S3 and an EC2. diff --git a/docs/HowTo/GetStarted/Install.md b/docs/HowTo/GetStarted/Install.md index e8f91cc8..747b0d48 100644 --- a/docs/HowTo/GetStarted/Install.md +++ b/docs/HowTo/GetStarted/Install.md @@ -9,7 +9,7 @@ Docker containers exist for GoQuorum and Tessera and can be found at the [`quoru ``` docker pull quorumengineering/quorum docker pull quorumengineering/tessera -``` +``` ## From source ### GoQuorum diff --git a/docs/HowTo/GetStarted/Wizard/GettingStarted.md b/docs/HowTo/GetStarted/Wizard/GettingStarted.md index 591a579c..38c6c541 100644 --- a/docs/HowTo/GetStarted/Wizard/GettingStarted.md +++ b/docs/HowTo/GetStarted/Wizard/GettingStarted.md @@ -36,7 +36,7 @@ GoQuorum network using Raft consensus), or customizing the options to fit your n You can also provide these flags when running quorum-wizard: -* `-q`, `--quickstart` create 3 node raft network with Tessera and cakeshop (no user-input required) +* `-q`, `--quickstart` create 3 node raft network with Tessera and cakeshop (no user-input required) * `-v`, `--verbose` Turn on additional logs for debugging * `--version` Show version number * `-h`, `--help` Show help diff --git a/docs/HowTo/GetStarted/Wizard/Interacting.md b/docs/HowTo/GetStarted/Wizard/Interacting.md index daf1123d..df098726 100644 --- a/docs/HowTo/GetStarted/Wizard/Interacting.md +++ b/docs/HowTo/GetStarted/Wizard/Interacting.md @@ -3,7 +3,7 @@ After following the instructions in [Getting Started](GettingStarted.md), you sh ## Start the Network -If you haven't done so already, go into the network directory and run start.sh (`network/3-nodes-raft-tessera-bash` is the quickstart default, if you changed any settings the folder name will be different). +If you haven't done so already, go into the network directory and run start.sh (`network/3-nodes-raft-tessera-bash` is the quickstart default, if you changed any settings the folder name will be different). ```sh cd network/3-nodes-raft-tessera-bash ./start.sh @@ -12,11 +12,11 @@ cd network/3-nodes-raft-tessera-bash Note: Run `./stop.sh` if you want to stop all GoQuorum, Tessera, and Cakeshop instances running on your machine ## Demonstrating Privacy -The network comes with some simple contracts to demonstrate the privacy features of GoQuorum. In this demo we: +The network comes with some simple contracts to demonstrate the privacy features of GoQuorum. In this demo we: - Send a private transaction between nodes 1 and 2 - Show that only nodes 1 and 2 are able to view the initial state of the contract -- Have Node 1 update the state of the contract and, once the block containing the updated transaction is validated by the network, again verify that only nodes 1 and 2 are able to see the updated state of the contract +- Have Node 1 update the state of the contract and, once the block containing the updated transaction is validated by the network, again verify that only nodes 1 and 2 are able to see the updated state of the contract ## Using Geth from the Command Line @@ -30,9 +30,9 @@ Make note of the `TransactionHash` printed to the terminal. ### Inspecting the GoQuorum nodes -We can inspect any of the GoQuorum nodes by using `./attach.sh` to open the Geth JavaScript console. For this demo, we will be inspecting Node 1, Node 2, and Node 3. +We can inspect any of the GoQuorum nodes by using `./attach.sh` to open the Geth JavaScript console. For this demo, we will be inspecting Node 1, Node 2, and Node 3. -It is recommended to use separate terminal windows for each node we are inspecting. In each terminal, ensure you are in your network's directory, then: +It is recommended to use separate terminal windows for each node we are inspecting. In each terminal, ensure you are in your network's directory, then: - In terminal 1 run `./attach.sh 1` to attach to node 1 - In terminal 2 run `./attach.sh 2` to attach to node 2 @@ -42,7 +42,7 @@ To look at the private transaction that was just sent, run the following command ```sh eth.getTransaction("0xe28912c5694a1b8c4944b2252d5af21724e9f9095daab47bac37b1db0340e0bf") ``` -where you should replace this hash with the TransactionHash that was previously printed to the terminal. This will print something of the form: +where you should replace this hash with the TransactionHash that was previously printed to the terminal. This will print something of the form: ```sh { blockHash: "0x4d6eb0d0f971b5e0394a49e36ba660c69e62a588323a873bb38610f7b9690b34", @@ -62,19 +62,19 @@ where you should replace this hash with the TransactionHash that was previously } ``` -Note the `v` field value of `"0x25"` or `"0x26"` (37 or 38 in decimal) which indicates this transaction has a private payload (input). +Note the `v` field value of `"0x25"` or `"0x26"` (37 or 38 in decimal) which indicates this transaction has a private payload (input). #### Checking the state of the contract -For each of the 3 nodes we'll use the Geth JavaScript console to create a variable called `address` which we will assign to the address of the contract created by Node 1. The contract address can be found in two ways: +For each of the 3 nodes we'll use the Geth JavaScript console to create a variable called `address` which we will assign to the address of the contract created by Node 1. The contract address can be found in two ways: - In Node 1's log file: `qdata/logs/1.log` - By reading the `contractAddress` param after calling `eth.getTransactionReceipt(txHash)` ([Ethereum API documentation](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgettransactionreceipt)) where `txHash` is the hash printed to the terminal after sending the transaction. Once you've identified the contract address, run the following command in each terminal: ``` -> var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"; //replace with your contract address -``` +> var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"; //replace with your contract address +``` Next we'll use ```eth.contract``` to define a contract class with the simpleStorage ABI definition in each terminal: ``` @@ -99,7 +99,7 @@ The function calls are now available on the contract instance and you can call t 0 ``` -So we can see nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. If you look in `private-contract.js` you will see that this was the value set when the contract was created. Node 3 is unable to read the state. +So we can see nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. If you look in `private-contract.js` you will see that this was the value set when the contract was created. Node 3 is unable to read the state. ### Updating the state of the contract diff --git a/docs/HowTo/GetStarted/migration.md b/docs/HowTo/GetStarted/migration.md index 94d67240..fd2aaf35 100644 --- a/docs/HowTo/GetStarted/migration.md +++ b/docs/HowTo/GetStarted/migration.md @@ -1,15 +1,15 @@ # Upgrade to GoQuorum 2.6.0 -GoQuorum 2.6.0 upgrades the base `geth` version from 1.8.18 to 1.9.7 -See [ethereum 1.9.0](https://blog.ethereum.org/2019/07/10/geth-v1-9-0/) for the complete list if new features added as a part of `geth` 1.9.7. +GoQuorum 2.6.0 upgrades the base `geth` version from 1.8.18 to 1.9.7 +See [ethereum 1.9.0](https://blog.ethereum.org/2019/07/10/geth-v1-9-0/) for the complete list if new features added as a part of `geth` 1.9.7. -**Note** `geth` 1.9.7 has several enhancements at the database layer which are part of GoQuorum 2.6.0. Hence, once migrates to 2.6.0, it cannot rollback to older version of Quourm. The recommendation is to keep the back of the data directory before upgrading to 2.6.0 which can be used to revert back to older version if necessary. +**Note** `geth` 1.9.7 has several enhancements at the database layer which are part of GoQuorum 2.6.0. Hence, once migrates to 2.6.0, it cannot rollback to older version of Quourm. The recommendation is to keep the back of the data directory before upgrading to 2.6.0 which can be used to revert back to older version if necessary. A node running on GoQuorum 2.6.0 can coexist on a network where other nodes are running on lower version of GoQuorum and thus supports node by node upgrade to GoQuorum 2.6.0. The suggested upgrade process is as described below: * Bring down the node which needs to be upgraded to GoQuorum 2.6.0. Modify the `genesis.json` file to include `istanbulBlock` and `petersburgBlock`. The values for this should be set to an appropriate value in future by when the entire network would have upgraded to GoQuorum 2.6.0. This is important as the gas calculation logic has changed in `geth` 1.9.7. Not setting this value properly can result in `Bad block error` -* GoQuorum 2.6.0 has deprecated genesis attributes `maxCodeSize` and `maxCodeSizeChangeBlock`. To allow tracking of multiple `maxCodeSize` value changes, a new attribute `maxCodeSizeConfig` is added to genesis. If the `maxCodeSize` was changed multiple times, it could possibly result in `Bad block` error for any new node joining the network. The changes in GoQuorum 2.6.0 address this and enable tracking of historical changes of `maxCodeSize` in genesis and thus allow it to be changed multiple times in network life. With this change when `init` is executed in GoQuorum 2.6.0, `geth` will force usage of `maxCodeSizeConfig`. A sample example is shown below. +* GoQuorum 2.6.0 has deprecated genesis attributes `maxCodeSize` and `maxCodeSizeChangeBlock`. To allow tracking of multiple `maxCodeSize` value changes, a new attribute `maxCodeSizeConfig` is added to genesis. If the `maxCodeSize` was changed multiple times, it could possibly result in `Bad block` error for any new node joining the network. The changes in GoQuorum 2.6.0 address this and enable tracking of historical changes of `maxCodeSize` in genesis and thus allow it to be changed multiple times in network life. With this change when `init` is executed in GoQuorum 2.6.0, `geth` will force usage of `maxCodeSizeConfig`. A sample example is shown below. ```javascript "config": { diff --git a/docs/HowTo/ManageKeys/AccountPlugins.md b/docs/HowTo/ManageKeys/AccountPlugins.md index 588bb5ed..66e490cb 100644 --- a/docs/HowTo/ManageKeys/AccountPlugins.md +++ b/docs/HowTo/ManageKeys/AccountPlugins.md @@ -8,7 +8,7 @@ We recommended reading the [Plugins overview](../../Concepts/Plugins/Plugins.md) | Name | Version | | Description | | --- | --- | --- | --- | -| `hashicorp-vault` | `0.0.1` | [Docs & Source](https://www.github.com/ConsenSys/quorum-account-plugin-hashicorp-vault) | Enables storage of Quorum account keys in a Hashicorp Vault kv v2 engine. Written in Go. +| `hashicorp-vault` | `0.0.1` | [Docs & Source](https://www.github.com/ConsenSys/quorum-account-plugin-hashicorp-vault) | Enables storage of Quorum account keys in a Hashicorp Vault kv v2 engine. Written in Go. ## Using with GoQuorum & clef @@ -51,7 +51,7 @@ Create a plugin-managed account with a new key: | Parameter | Description | | --- | --- | -| `config` | Plugin-specific json configuration for creating an account. See the plugin's documentation for more info on the json config required +| `config` | Plugin-specific json configuration for creating an account. See the plugin's documentation for more info on the json config required !!! example @@ -94,12 +94,12 @@ Create a plugin-managed account with a new key: Create a plugin-managed account from an existing private key: !!! note - Although this API can be used to move plugin-managed accounts between nodes, the plugin may provide a more preferable alternative. See the plugin's documentation for more info. + Although this API can be used to move plugin-managed accounts between nodes, the plugin may provide a more preferable alternative. See the plugin's documentation for more info. | Parameter | Description | | --- | --- | | `rawkey` | Hex-encoded account private key (without 0x prefix) -| `config` | Plugin-specific json configuration for creating a new account. See the plugin's documentation for more info on the json config required +| `config` | Plugin-specific json configuration for creating a new account. See the plugin's documentation for more info on the json config required !!! example @@ -147,7 +147,7 @@ Create a plugin-managed account from an existing key: | Parameter | Description | | --- | --- | -| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required. +| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required. === "json file" @@ -171,7 +171,7 @@ Create a plugin-managed account from an existing private key: | Parameter | Description | | --- | --- | -| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required +| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required | `rawkey` | Path to file containing hex-encoded account private key (without 0x prefix) (e.g. `/path/to/raw.key`) === "json file" diff --git a/docs/HowTo/ManageKeys/clef.md b/docs/HowTo/ManageKeys/clef.md index 39c7b076..5437589a 100644 --- a/docs/HowTo/ManageKeys/clef.md +++ b/docs/HowTo/ManageKeys/clef.md @@ -11,7 +11,7 @@ features, including: * Ability to extend functionality with [`account` plugins](AccountPlugins.md) `clef` runs as a separate process to `geth` and provides an alternative method of managing accounts -and signing transactions/data. Instead of `geth` loading and using accounts directly, `geth` delegates +and signing transactions/data. Instead of `geth` loading and using accounts directly, `geth` delegates account management responsibilities to `clef`. Account management will be deprecated within `geth` in the future and replaced with `clef`. @@ -50,16 +50,16 @@ for an overview and step-by-step guide on initialising and starting `clef`, as w 1. As a `geth` signer !!! warning - In the long term, the preferred way of using `clef` will be as an external signer. However, whilst + In the long term, the preferred way of using `clef` will be as an external signer. However, whilst waiting for tooling to support the `clef` API, the `go-ethereum` project have included the option - to use `clef` as a `geth` signer. This ensures existing tooling and user flows can remain unchanged. + to use `clef` as a `geth` signer. This ensures existing tooling and user flows can remain unchanged. The option to use `clef` as a `geth` signer **will be deprecated** in a future release of `go-ethereum` once the migration of account management from `geth` to `clef` is complete. ### As an external signer -Using `clef` as an external signer requires interacting with `clef` through its RPC API. By default -this is exposed over IPC socket. The API can also be exposed over HTTP by using the `--rpcaddr` CLI flag. +Using `clef` as an external signer requires interacting with `clef` through its RPC API. By default +this is exposed over IPC socket. The API can also be exposed over HTTP by using the `--rpcaddr` CLI flag. An example workflow would be: @@ -82,7 +82,7 @@ echo '{"id": 1, "jsonrpc": "2.0", "method": "account_signData", "params": ["data ### As a geth signer -Using `clef` as a `geth` signer does not require direct interaction through the `clef` API. Instead +Using `clef` as a `geth` signer does not require direct interaction through the `clef` API. Instead `geth` can be used as normal and will automatically delegate to `clef`. To use `clef` as a `geth` signer: @@ -98,8 +98,8 @@ An example workflow would be: ### Extending with account plugins -By default, `clef` manages file-stored `keystore` accounts. Alternative account management options -can be enabled through the use of [`account` plugins](AccountPlugins.md). See the +By default, `clef` manages file-stored `keystore` accounts. Alternative account management options +can be enabled through the use of [`account` plugins](AccountPlugins.md). See the [Pluggable Architecture Overview](../../Concepts/Plugins/Plugins.md) for more info on using plugins with `clef`. ```shell diff --git a/docs/HowTo/Use/AddingIBFTValidators.md b/docs/HowTo/Use/AddingIBFTValidators.md index 298496ab..4cb5d5f1 100644 --- a/docs/HowTo/Use/AddingIBFTValidators.md +++ b/docs/HowTo/Use/AddingIBFTValidators.md @@ -1,71 +1,71 @@ # Adding and removing IBFT validators -Over the lifetime of an IBFT network, validators will need to be added and removed as authorities change. +Over the lifetime of an IBFT network, validators will need to be added and removed as authorities change. Here we will showcase adding a new validator to an IBFT network, as well as removing an existing one. ## Adding a node to the validator set Adding a node to the IBFT validator set is relatively easy once a node is part of the network. -It does not matter whether the node is already online or not, as the process to add the new node as a validator only +It does not matter whether the node is already online or not, as the process to add the new node as a validator only needs the *existing* validators. !!! warning If you are adding multiple validators before they are brought online, make sure you don't go over the BFT limit and cause the chain to stop progressing. -Adding a new validator requires that a majority of existing validators propose the new node to be added. This is +Adding a new validator requires that a majority of existing validators propose the new node to be added. This is achieved by calling the `propose` RPC method with the value `true` and replacing the address to your required one: ```bash $ geth attach /qdata/dd/geth.ipc - + > istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true); null ``` - -This indicates that the current node wishes to add address `0xb131288f355bc27090e542ae0be213c20350b767` as a new + +This indicates that the current node wishes to add address `0xb131288f355bc27090e542ae0be213c20350b767` as a new validator. ### Example -You can find the resources required to run the examples in the -[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/ibft_validator_set_changes) -repository. +You can find the resources required to run the examples in the +[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/ibft_validator_set_changes) +repository. -1. The examples use `docker-compose` for the container definitions. If you are following along by copying the commands - described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for - your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) +1. The examples use `docker-compose` for the container definitions. If you are following along by copying the commands + described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for + your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) for more details. - + To set the project name, run the following: ```bash $ export COMPOSE_PROJECT_NAME=addnode ``` - + 2. Bring up the network, which contains 7 nodes, of which 6 are validators. ```bash $ docker-compose -f ibft-6-validators.yml up ``` - - We will be adding the 7th node as a validator. You may notice in the logs of node 7 messages along the lines of - `node7_1 | WARN [01-20|10:37:16.034] Block sealing failed err=unauthorized`. This is because - the node was started up with minting enabled, but doesn't have the authority to create blocks, and so throws this + + We will be adding the 7th node as a validator. You may notice in the logs of node 7 messages along the lines of + `node7_1 | WARN [01-20|10:37:16.034] Block sealing failed err=unauthorized`. This is because + the node was started up with minting enabled, but doesn't have the authority to create blocks, and so throws this error. - + 3. Now we need to propose node 7 as a new proposer from the existing nodes. !!! note Remember, you could do this stage before starting node 7 in your network - + We need a majority of existing validators to propose the new node before the changes will take effect. - + Lets start with node 1 and see what happens: - + ```bash # Propose node 7 from node 1 $ docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null - + # Wait about 5 seconds, and then run: $ docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { @@ -88,21 +88,21 @@ repository. }] } ``` - + Let's break this down. - Firstly, we proposed the address `0xb131288f355bc27090e542ae0be213c20350b767` to be added; that is what the `true` + Firstly, we proposed the address `0xb131288f355bc27090e542ae0be213c20350b767` to be added; that is what the `true` parameter is for. If we had set it to `false`, that means we want to remove an existing validator with that address. - + Secondly, we fetched the current snapshot, which gives us an insight into the current running state of the voting. - We can see that the new address has 1 vote under the `tally` section, and that one vote is described under the + We can see that the new address has 1 vote under the `tally` section, and that one vote is described under the `votes` section. So we know our vote was registered! - + 4. Let's run this from node 2 and see similar results: ```bash $ docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null - + # Again, you may have to wait 5 - 10 seconds for the snapshot to show the vote $ docker exec -it addnode_node2_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { @@ -130,7 +130,7 @@ repository. }] } ``` - + True to form, we have the second vote registered! 5. Ok, let's finally vote on nodes 3 and 4. @@ -138,7 +138,7 @@ repository. ```bash $ docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null - + $ docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null ``` @@ -157,69 +157,69 @@ repository. votes: [] } ``` - + We can see that the votes have now been wiped clean, ready for a new round. Additionally, the address we were adding, `0xb131288f355bc27090e542ae0be213c20350b767` now exists within the `validators` list! - Lastly, the `unauthorized` messages that node 7 was giving before has stopped, as it now has the authority to mint + Lastly, the `unauthorized` messages that node 7 was giving before has stopped, as it now has the authority to mint blocks. ## Removing a node from the validator set -Removing a validator is very similar to adding a node, but this time we want to propose nodes with the value `false`, -to indicate we are deauthorising them. It does not matter whether the node is still online or not, as it doesn't +Removing a validator is very similar to adding a node, but this time we want to propose nodes with the value `false`, +to indicate we are deauthorising them. It does not matter whether the node is still online or not, as it doesn't require any input from the node being removed. !!! warning Be aware when removing nodes that cross the BFT boundary, e.g. going from 10 validators to 9, as this may impact the chains ability to progress if other nodes are offline -Removing a new validator requires that a majority of existing validators propose the new node to be removed. This is +Removing a new validator requires that a majority of existing validators propose the new node to be removed. This is achieved by calling the `propose` RPC method with the value `false` and replacing the address to your required one: ```bash $ geth attach /qdata/dd/geth.ipc - + > istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", false); null ``` ### Example -You can find the resources required to run the examples in the -[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/ibft_validator_set_changes) -repository. +You can find the resources required to run the examples in the +[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/ibft_validator_set_changes) +repository. -1. The examples use `docker-compose` for the container definitions. If you are following along by copying the commands - described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for - your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) +1. The examples use `docker-compose` for the container definitions. If you are following along by copying the commands + described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for + your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) for more details. - + To set the project name, run the following: ```bash $ export COMPOSE_PROJECT_NAME=addnode ``` - + 2. Bring up the network, which contains 7 nodes, of which 6 are validators. ```bash # Set the environment variable for docker-compose $ export COMPOSE_PROJECT_NAME=addnode - + # Start the 7 node network, of which 6 are validators $ docker-compose -f ibft-6-validators.yml up ``` - + 3. Now we need to propose node 6 as the node to remove. - + !!! note We need a majority of existing validators to propose the new node before the changes will take effect. - + Lets start with node 1 and see what happens: - + ```bash # Propose node 7 from node 1 $ docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null - + # Wait about 5 seconds, and then run: $ docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { @@ -242,29 +242,29 @@ repository. }] } ``` - + Let's break this down. - Firstly, we proposed the address `0x8157d4437104e3b8df4451a85f7b2438ef6699ff` to be removed; that is what the + Firstly, we proposed the address `0x8157d4437104e3b8df4451a85f7b2438ef6699ff` to be removed; that is what the `false` parameter is for. - + Secondly, we fetched the current snapshot, which gives us an insight into the current running state of the voting. - We can see that the proposed address has 1 vote under the `tally` section, and that one vote is described under the - `votes` section. Here, the `authorize` section is set to `false`, which is inline with our proposal to *remove* the + We can see that the proposed address has 1 vote under the `tally` section, and that one vote is described under the + `votes` section. Here, the `authorize` section is set to `false`, which is inline with our proposal to *remove* the validator. - + 4. We need to get a majority, so let's run the proposal on 3 more nodes: ```bash $ docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null - + $ docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null - + $ docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null ``` - + 5. Let's check the snapshot now all the required votes are in: ```bash @@ -279,10 +279,10 @@ repository. votes: [] } ``` - - The validator has been removed from the `validators` list, and we are left with the other 5 still present. You will - also see in the logs of node 6 a message like - `node6_1 | WARN [01-20|11:35:52.044] Block sealing failed err=unauthorized`. This is because it is still minting + + The validator has been removed from the `validators` list, and we are left with the other 5 still present. You will + also see in the logs of node 6 a message like + `node6_1 | WARN [01-20|11:35:52.044] Block sealing failed err=unauthorized`. This is because it is still minting blocks, but realises it does not have the authority to push them to any of the other nodes on the network (you will also see this message for node 7, which was never authorised but still set up to mine). diff --git a/docs/HowTo/Use/DevelopingSmartContracts.md b/docs/HowTo/Use/DevelopingSmartContracts.md index 2d70bbf3..c953792e 100644 --- a/docs/HowTo/Use/DevelopingSmartContracts.md +++ b/docs/HowTo/Use/DevelopingSmartContracts.md @@ -1,14 +1,14 @@ # Developing Smart Contracts GoQuorum uses standard [Solidity](https://solidity.readthedocs.io/en/develop/) for writing Smart Contracts, -and generally, these can be designed as you would design Smart Contracts for Ethereum. Smart Contracts can +and generally, these can be designed as you would design Smart Contracts for Ethereum. Smart Contracts can either be public (i.e. visible and executable by all participants on a given GoQuorum network) or private to -one or more network participants. Note that GoQuorum does not introduce new contract types. +one or more network participants. Note that GoQuorum does not introduce new contract types. ## Creating public transactions/contracts Sending a standard Ethereum-style transaction to a given network will make it viewable and executable by -all participants on the network. As with Ethereum, leave the `to` field empty for a contract-creation transaction. +all participants on the network. As with Ethereum, leave the `to` field empty for a contract-creation transaction. Example JSON RPC API call to send a public transaction: @@ -70,5 +70,5 @@ See the [GoQuorum API](../../Reference/APIs/PrivacyAPI.md) page for details on t ## GoQuorum contract design considerations -1. *Private contracts cannot update public contracts.* This is because not all participants will be able to execute a private contract, and so if that contract can update a public contract, then each participant will end up with a different state for the public contract. -2. *Once a contract has been made public, it can't later be made private.* If you do need to make a public contract private, it would need to be deleted from the blockchain and a new private contract created. +1. *Private contracts cannot update public contracts.* This is because not all participants will be able to execute a private contract, and so if that contract can update a public contract, then each participant will end up with a different state for the public contract. +2. *Once a contract has been made public, it can't later be made private.* If you do need to make a public contract private, it would need to be deleted from the blockchain and a new private contract created. diff --git a/docs/HowTo/Use/EnhancedPermissions.md b/docs/HowTo/Use/EnhancedPermissions.md index b53c8f72..ed47fe5f 100644 --- a/docs/HowTo/Use/EnhancedPermissions.md +++ b/docs/HowTo/Use/EnhancedPermissions.md @@ -1,4 +1,4 @@ -# Using enhanced permissioning +# Using enhanced permissioning Managing the [enhanced permissioning model](../../Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md) can be broadly categorized into the following activities: @@ -7,25 +7,25 @@ can be broadly categorized into the following activities: Please refer to [set up](../Configure/EnhancedPermissions.md). For an existing network running with an older version of GoQuorum: -* Upgrade GoQuorum to the latest version -* Deploy the contracts +* Upgrade GoQuorum to the latest version +* Deploy the contracts * Execute the `init` method of `PermissionsUpgradable.sol` from the guardian account -* Copy the `permission-config.json` to the data directory of each node +* Copy the `permission-config.json` to the data directory of each node * Bring `geth` up in `--permissioned` mode. For a new network using the latest version of GoQuorum: -* Bring up the initial set of nodes -* Deploy the contracts +* Bring up the initial set of nodes +* Deploy the contracts * Execute the `init` method of `PermissionsUpgradable.sol` from the guardian account -* Upgrade GoQuorum to the latest version -* Copy the `permission-config.json` to the data directory of each node +* Upgrade GoQuorum to the latest version +* Copy the `permission-config.json` to the data directory of each node * Bring `geth` up in `--permissioned` mode. As part of network initialization: -* A network admin organization is created with the `nwAdminOrg` name specified in `permission-config.json`. All nodes which are part of `static-nodes.json` are assigned to this organization. -* A network admin role is created with the `nwAdminRole` name specified in the config file. +* A network admin organization is created with the `nwAdminOrg` name specified in `permission-config.json`. All nodes which are part of `static-nodes.json` are assigned to this organization. +* A network admin role is created with the `nwAdminRole` name specified in the config file. * All accounts given in the `accounts` array of the config file are assigned the network admin role. These accounts will have the ability to propose and approve new organizations into the network. Assuming that the network was started with the `permission-config.json` given in the [set up](../Configure/EnhancedPermissions.md), and assuming the network was brought up with the `static-nodes.json` file given below: @@ -171,11 +171,11 @@ As can be seen from the above, as a part of approval: The new node belonging to the organization can now join the network. In case the network is running in `Raft` consensus mode, before the node joins the network, please ensure that: -* The node has been added as a peer using `raft.addPeer(<>)` -* Bring up `geth` for the new node using `--raftjoinexisting` with the peer id as obtained in the above step - +* The node has been added as a peer using `raft.addPeer(<>)` +* Bring up `geth` for the new node using `--raftjoinexisting` with the peer id as obtained in the above step + ### Organization admin managing the organization level permissions -Once the organization is approved and the node of the organization has joined the network, the organization admin can then create sub organizations, roles, add additional nodes at organization level, add accounts to the organization and change roles of existing organization level accounts. +Once the organization is approved and the node of the organization has joined the network, the organization admin can then create sub organizations, roles, add additional nodes at organization level, add accounts to the organization and change roles of existing organization level accounts. To add a sub org at `ORG1` level refer to [addSubOrg API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addsuborg). ```javascript @@ -232,7 +232,7 @@ The role `SUBADMIN` can now be assigned to an account at sub org `SUB1` for maki } ``` -The account `0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0` is now the admin for sub org `SUB1` and will be able to add roles, accounts and nodes to the sub org. It should be noted that the org admin account at master org level has the admin rights on all the sub organizations below. However the admin account at sub org level has control only in the sub org to which it is linked. +The account `0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0` is now the admin for sub org `SUB1` and will be able to add roles, accounts and nodes to the sub org. It should be noted that the org admin account at master org level has the admin rights on all the sub organizations below. However the admin account at sub org level has control only in the sub org to which it is linked. ```javascript > quorumPermission.addNewRole("ORG1.SUB1", "TRANSACT", 1, false, true,{from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) "Action completed successfully" @@ -441,7 +441,7 @@ When the org is suspended no transaction from any of the account linked to the o ### Revoking suspension of an organization -To revoke the suspension of an org [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) can be called with action as 2. This will require majority approval (API [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus) with action 2). +To revoke the suspension of an org [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) can be called with action as 2. This will require majority approval (API [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus) with action 2). ```javascript > quorumPermission.updateOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) "Action completed successfully" @@ -459,7 +459,7 @@ To revoke the suspension of an org [updateOrgStatus](../../Reference/APIs/Permis } ``` -Once the revoke is approved, all accounts in the organization and sub organization will be able to transact as per role level access. +Once the revoke is approved, all accounts in the organization and sub organization will be able to transact as per role level access. ### Assigning admin privileges at organization and network level There may be a scenario where one of the accounts at the organization level needs to have network admin level permissions and be able to perform network admin activities. Similarly there can be a need to change the admin account at organization level. Both these activities can be performed by existing network admin accounts only, and will require majority approval from the network admin accounts. The API usage details are as below. diff --git a/docs/HowTo/Use/JSON-RPC-API-Security.md b/docs/HowTo/Use/JSON-RPC-API-Security.md index c4ec02fe..9f38c3dd 100644 --- a/docs/HowTo/Use/JSON-RPC-API-Security.md +++ b/docs/HowTo/Use/JSON-RPC-API-Security.md @@ -7,21 +7,21 @@ The official implementation is [Quorum Security Plugin](https://github.com/Conse enables the GoQuorum Client to protect JSON RPC APIs with the following features: ### Native Transport Layer Security - + The native Transport Layer Security (TLS) introduces an encryption layer to the JSON-RPC request/response communication channel for both HTTP, and Web Socket listeners. By using a simple configuration flag this feature allows the automatic generation of self signed certificate for testing environment, or a smooth integration with certificate authorities for enterprise deployment. - + ### Enterprise Authorization Protocol Integration - + Enterprise authorization protocol integration introduces an access control layer that authorizes each JSON RPC invocation to an atomic -module function level (E.g `personal_OpenWallet`) using industry -standard [OAuth 2.0](https://tools.ietf.org/html/rfc6749) -protocol and/or [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) method. +module function level (E.g `personal_OpenWallet`) using industry +standard [OAuth 2.0](https://tools.ietf.org/html/rfc6749) +protocol and/or [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) method. This feature allows managing distributed application (dApps), and Quorum Clients access control in an efficient approach. @@ -29,7 +29,7 @@ and Quorum Clients access control in an efficient approach. Please refer to [plugin implementation](../../Reference/Plugins/security/For-Users.md) for more details. -There are also [examples](https://github.com/ConsenSys/quorum-security-plugin-enterprise/tree/master/examples) on +There are also [examples](https://github.com/ConsenSys/quorum-security-plugin-enterprise/tree/master/examples) on how to configure the plugin to work with different OAuth2 Authorization servers. ## Client Usage @@ -39,18 +39,18 @@ authorization server. An access token could be opaque or a JWT. It's the client' this preauthenticated token valid during its life time. When invoking a JSON RPC API, the client must send the preauthenticated token in the `Authorization` request header field -with `Bearer` authentication scheme. All major HTTP client libraries have extensions to allow such customization. +with `Bearer` authentication scheme. All major HTTP client libraries have extensions to allow such customization. ## Examples -Here are some examples on how to interact with protected JSON RPC APIs: +Here are some examples on how to interact with protected JSON RPC APIs: ### `web3` ```js let Web3 = require('web3'); let HttpHeaderProvider = require('httpheaderprovider'); -// obtain the preauthenticated bearer token +// obtain the preauthenticated bearer token // by authenticating with the authorization server let token = ...; let headers = { "Authorization": `Bearer ${token}` }; @@ -61,7 +61,7 @@ web3.setProvider(provider); ### `curl` ```bash -# obtain the preauthenticated bearer token +# obtain the preauthenticated bearer token # by authenticating with the authorization server export TOKEN="Bearer ..." curl -X POST -H "Content-type: application/json" -H "Authorization: $TOKEN" \ @@ -83,8 +83,8 @@ There are additional flags allowing to connect to secured Quorum node E.g.: Connect to the node with `--rpcclitls.insecureskipverify` to ignore the Server's certificate validation. ```shell -geth attach https://localhost:22000 --rpcclitls.insecureskipverify -geth attach wss://localhost:23000 --rpcclitls.insecureskipverify +geth attach https://localhost:22000 --rpcclitls.insecureskipverify +geth attach wss://localhost:23000 --rpcclitls.insecureskipverify ``` ### `ethclient` @@ -99,7 +99,7 @@ The token value is obtained from `rpc.HttpCredentialsProviderFunc` implementatio `rpc.Client` is instantiated. ```go -// obtain the preauthenticated bearer token +// obtain the preauthenticated bearer token // by authenticating with the authorization server token := ... // instantiate rpc.Client @@ -123,19 +123,19 @@ if err != nil { To customize TLS client configuration: ```go // instantiate a http.Client with custom TLS client config -myHttpClient := ... +myHttpClient := ... // instantiate rpc.Client c, err := rpc.DialHTTPWithClient("https://...", myHttpClient) ``` **WS/WSS** -For WS endpoint, the preauthenticated token is populated in `Authorization` HTTP request header only once -during the handshake. The token value is obtained from `rpc.HttpCredentialsProviderFunc` implementation via +For WS endpoint, the preauthenticated token is populated in `Authorization` HTTP request header only once +during the handshake. The token value is obtained from `rpc.HttpCredentialsProviderFunc` implementation via `context.Context` when dialing. ```go -// obtain the preauthenticated bearer token +// obtain the preauthenticated bearer token // by authenticating with the authorization server token := ... diff --git a/docs/HowTo/Use/add_node_examples.md b/docs/HowTo/Use/add_node_examples.md index 9b827365..404619f0 100644 --- a/docs/HowTo/Use/add_node_examples.md +++ b/docs/HowTo/Use/add_node_examples.md @@ -1,15 +1,15 @@ # Adding node examples -Below are some scenarios for adding a new node into a network, with a mix of different options such as +Below are some scenarios for adding a new node into a network, with a mix of different options such as consensus algorithm, permissioning, and discovery. -You can find the resources required to run the examples in the -[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/adding_nodes) repository. +You can find the resources required to run the examples in the +[quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/adding_nodes) repository. Checkout the repository through `git` or otherwise download all the resources your local machine to follow along. -The examples use `docker-compose` for the container definitions. If you are following along by copying the commands -described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for -your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) +The examples use `docker-compose` for the container definitions. If you are following along by copying the commands +described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for +your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) for more details. To set the project name, run the following: @@ -20,7 +20,7 @@ $ export COMPOSE_PROJECT_NAME=addnode ## Non-permimssioned IBFT with discovery An example using IBFT, no permissioning and discover enabled via a bootnode. -There are no static peers in this network; instead, every node is set to talk to node 1 via the CLI flag +There are no static peers in this network; instead, every node is set to talk to node 1 via the CLI flag `--bootnodes enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@172.16.239.11:21000`. Node 1 will forward the details of all the nodes it knows about (in this case, everyone) and they will then initiate their own connections. @@ -30,41 +30,41 @@ own connections. ```bash # Ensure any old network is removed $ docker-compose -f ibft-non-perm-bootnode.yml down - + # Bring up 6 nodes $ docker-compose -f ibft-non-perm-bootnode.yml up node1 node2 node3 node4 node5 node6 ``` - + 2. Send in a public transaction and check it is minted. !!! note * The block creation period is set to 2 seconds, so you may have to wait upto that amount of time for the transaction to be minted. * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - + ```bash # Send in the transaction $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... true - + # Retrieve the value of the contract $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - + We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. Bring up the last node. This node also has its bootnodes set to be node 1, so at startup will try to establish a -connection to node 1 only. After this, node 1 will share which nodes it knows about, and node 7 can then initiate +3. Bring up the last node. This node also has its bootnodes set to be node 1, so at startup will try to establish a +connection to node 1 only. After this, node 1 will share which nodes it knows about, and node 7 can then initiate connections with those peers. - + ```bash # Bring up node 7 $ docker-compose -f ibft-non-perm-bootnode.yml up node7 ``` - -4. Let's check to see if the nodes are in sync. If they are, they will have similar block numbers, which is enough for + +4. Let's check to see if the nodes are in sync. If they are, they will have similar block numbers, which is enough for this example; there are other ways to tell if nodes are on the same chain, e.g. matching block hashes. !!! note @@ -74,12 +74,12 @@ this example; there are other ways to tell if nodes are on the same chain, e.g. # Fetch the latest block number for node 1 $ docker exec -it addnode_node1_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc 45 - + # Fetch the latest block number for node 7 $ docker exec -it addnode_node7_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc 45 ``` - + 5. We can check that the transaction and contract we sent earlier now exist on node 7. ```bash @@ -88,32 +88,32 @@ this example; there are other ways to tell if nodes are on the same chain, e.g. ``` 6. To be sure we have two way communication, let's send a transaction from node 7 to the network. - + ```bash $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... true ``` - + 7. Finally, we can check if the transaction was minted and the contract executed on each node. ```bash # Check on node 1 $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 - + # Check on node 7 $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to + +And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to read existing public data, as well as deploy its own transactions and contracts for others to see! ## Non-permissioned RAFT with discovery disabled -This example walks through adding a new node to a RAFT network. This network does not have permissioning for the -Ethereum peer-to-peer layer, and makes it connections solely based on who is listed in the nodes `static-nodes.json` +This example walks through adding a new node to a RAFT network. This network does not have permissioning for the +Ethereum peer-to-peer layer, and makes it connections solely based on who is listed in the nodes `static-nodes.json` file. 1. Bring up an initial network of 6 nodes. @@ -121,31 +121,31 @@ file. ```bash # Ensure any old network is removed $ docker-compose -f raft-non-perm-nodiscover.yml down - + # Bring up 6 nodes $ docker-compose -f raft-non-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 ``` - + 2. Send in a public transaction and check it is minted. !!! note * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - + ```bash # Send in the transaction $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... true - + # Retrieve the value of the contract $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - + We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from +3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from the RAFT communication layer; we also need to know what ID the new node should join with. ```bash @@ -153,21 +153,21 @@ the RAFT communication layer; we also need to know what ID the new node should j $ docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc 7 ``` - - The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need - this ID number handy. If it was lost, you can always view the full network, including IDs, by running the + + The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need + this ID number handy. If it was lost, you can always view the full network, including IDs, by running the `raft.cluster` command on an existing node. -4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets -the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing +4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets +the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing node there are fetch any bootstrap information. - + ```bash # Bring up node 7 $ QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 ``` - -5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on + +5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on node 7. ```bash @@ -177,32 +177,32 @@ node 7. ``` 6. To be sure we have two way communication, let's send a transaction from node 7 to the network. - + ```bash $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... true ``` - + 7. Finally, we can check if the transaction was minted and the contract executed on each node. ```bash # Check on node 1 $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 - + # Check on node 7 $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to + +And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to read existing public data, as well as deploy its own transactions and contracts for others to see! ## Permissioned RAFT with discovery disabled -This example walks through adding a new node to a RAFT network. This network does have permissioning enabled for the -Ethereum peer-to-peer layer; this means that for any Ethereum tasks, such as syncing the initial blockchain or +This example walks through adding a new node to a RAFT network. This network does have permissioning enabled for the +Ethereum peer-to-peer layer; this means that for any Ethereum tasks, such as syncing the initial blockchain or propagating transactions, the node must appear is others nodes' `permissioned-nodes.json` file. 1. Bring up an initial network of 6 nodes. @@ -210,31 +210,31 @@ propagating transactions, the node must appear is others nodes' `permissioned-no ```bash # Ensure any old network is removed $ docker-compose -f raft-perm-nodiscover.yml down - + # Bring up 6 nodes $ docker-compose -f raft-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 ``` - + 2. Send in a public transaction and check it is minted. !!! note * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - + ```bash # Send in the transaction $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... true - + # Retrieve the value of the contract $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - + We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from +3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from the RAFT communication layer; we also need to know what ID the new node should join with. ```bash @@ -242,21 +242,21 @@ the RAFT communication layer; we also need to know what ID the new node should j $ docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc 7 ``` - - The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need - this ID number handy. If it was lost, you can always view the full network, including IDs, by running the + + The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need + this ID number handy. If it was lost, you can always view the full network, including IDs, by running the `raft.cluster` command on an existing node. -4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets -the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing +4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets +the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing node there are fetch any bootstrap information. - + ```bash # Bring up node 7 $ QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 ``` - -5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on + +5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on node 7. ```bash @@ -264,13 +264,13 @@ node 7. $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc 0 ``` - - The value here is `0`, not the expected `42`! Node 7 is unable to sync the blockchain because the other peers in the + + The value here is `0`, not the expected `42`! Node 7 is unable to sync the blockchain because the other peers in the network are refusing to allow connections from node 7, due to it being missing in the `permissioned-nodes.json` file. - - This does not affect the RAFT layer, so if node 7 was already is sync, it could still receive new blocks; this is + + This does not affect the RAFT layer, so if node 7 was already is sync, it could still receive new blocks; this is okay though, since it would be permissioned on the RAFT side by virtue of being part of the RAFT cluster. - + 6. Let's update the permissioned nodes list on node 1, which will allow node 7 to connect to it. ```bash @@ -289,33 +289,33 @@ node 7. ``` 8. To be sure we have two way communication, let's send a transaction from node 7 to the network. - + ```bash $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... true ``` - + 9. Finally, we can check if the transaction was minted and the contract executed on each node. ```bash # Check on node 1 $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 - + # Check on node 7 $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc 42 ``` - -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to + +And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to read existing public data, as well as deploy its own transactions and contracts for others to see! - + ## Adding a Private Transaction Manager -This is a simple example of adding a new Tessera instance to an existing network. For simplicity, +This is a simple example of adding a new Tessera instance to an existing network. For simplicity, the steps to add the GoQuorum node are omitted, but are those followed in the IBFT example. -Here, a Tessera node is added without any of the discovery options specified, meaning that the +Here, a Tessera node is added without any of the discovery options specified, meaning that the IP Whitelist isn't used, nor is key discovery disabled. 1. Start up the initial 6 node network. @@ -323,11 +323,11 @@ IP Whitelist isn't used, nor is key discovery disabled. ```bash # Ensure any old network is removed $ docker-compose -f tessera-add.yml down - + # Bring up 6 nodes $ docker-compose -f tessera-add.yml up node1 node2 node3 node4 node5 node6 ``` - + 2. We can verify that private transactions can be sent by sending one from node 1 to node 6. We can also see that since node 7 doesn't exist yet, we can't send private transactions to it. @@ -336,27 +336,27 @@ We can also see that since node 7 doesn't exist yet, we can't send private trans $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-6.js")' attach /qdata/dd/geth.ipc Contract transaction send: TransactionHash: 0xc8a5de4bb79d4a8c3c1156917968ca9b2965f2514732fc1cff357ec999b9aba4 waiting to be mined... true - # Success! - + # Success! + $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-7.js")' attach /qdata/dd/geth.ipc err creating contract Error: Non-200 status code: &{Status:404 Not Found StatusCode:404 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Server:[Jetty(9.4.z-SNAPSHOT)] Date:[Thu, 16 Jan 2020 12:44:19 GMT] Content-Type:[text/plain] Content-Length:[73]] Body:0xc028e87d40 ContentLength:73 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000287200 TLS:} true # An expected failure. The script content didn't succeed, but the script itself was run okay, so true was still returned ``` - + 3. Let's first bring up node 7, then we can inspect what is happening and the configuration used. - + ```bash # Bring up node 7 - $ docker-compose -f tessera-add.yml up node7 - + $ docker-compose -f tessera-add.yml up node7 + $ docker exec -it addnode_node7_1 cat /qdata/tm/tessera-config.json # ...some output... ``` - + The last command will output Tessera 7's configuration. The pieces we are interested in here are the following: - + ```json { "useWhiteList": false, @@ -368,13 +368,13 @@ We can also see that since node 7 doesn't exist yet, we can't send private trans ... } ``` - + We can see that the whitelist is not enabled, discovery is not specified so defaults to enabled, and we have a single peer to start off with, which is node 1. - This is all that is needed to connect to an existing network. Shortly after starting up, Tessera - will ask node 1 about all it's peers, and then will keep a record of them for it's own use. From + This is all that is needed to connect to an existing network. Shortly after starting up, Tessera + will ask node 1 about all it's peers, and then will keep a record of them for it's own use. From then on, all the nodes will know about node 7 and can send private transactions to it. - + 4. Let's try it! Let's send a private transaction from node 1 to the newly added node 7. ```bash @@ -383,6 +383,6 @@ We can also see that since node 7 doesn't exist yet, we can't send private trans Contract transaction send: TransactionHash: 0x3e3b50768ffdb51979677ddb58f48abdabb82a3fd4f0bac5b3d1ad8014e954e9 waiting to be mined... true ``` - - We got a success this time! Tessera 7 has been accepted into the network and can interact with the + + We got a success this time! Tessera 7 has been accepted into the network and can interact with the other existing nodes. diff --git a/docs/HowTo/Use/adding_nodes.md b/docs/HowTo/Use/adding_nodes.md index e6c02ade..beba52e3 100644 --- a/docs/HowTo/Use/adding_nodes.md +++ b/docs/HowTo/Use/adding_nodes.md @@ -2,11 +2,11 @@ Adding new nodes to an existing network can range from a common occurence to never happening. In public blockchains, such as the Ethereum Mainnet, new nodes continuously join and talk to the existing network. -In permissioned blockchains, this may not happen as often, but it still an important task to achieve as your network +In permissioned blockchains, this may not happen as often, but it still an important task to achieve as your network evolves. When adding new nodes to the network, it is important understand that the GoQuorum network and Tessera - network are distinct and do not overlap in any way. Therefore, options applicable to one are not applicable to + network are distinct and do not overlap in any way. Therefore, options applicable to one are not applicable to the other. In some cases, they may have their own options to achieve similar tasks, but must be specified separately. ## Prerequisites @@ -24,7 +24,7 @@ the other. In some cases, they may have their own options to achieve similar tas > raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407") 7 ``` - + So in this example, our new node has a Raft ID of `7`. 2. If you are using permissioning, or discovery for Ethereum p2p, please refer [here](#extra-options). @@ -39,24 +39,24 @@ the other. In some cases, they may have their own options to achieve similar tas $ geth --datadir qdata/dd7 init genesis.json ``` -4. Now we can start up the new node and let it sync with the network. The main difference now is the use of the -`--raftjoinexisting` flag, which lets the node know that it is joining an existing network, which is handled +4. Now we can start up the new node and let it sync with the network. The main difference now is the use of the +`--raftjoinexisting` flag, which lets the node know that it is joining an existing network, which is handled differently internally. The Raft ID obtained in step 1 is passed as a parameter to this flag. ```bash $ PRIVATE_CONFIG=ignore geth --datadir qdata/dd7 ... OTHER ARGS ... --raft --raftport 50407 --rpcport 22006 --port 21006 --raftjoinexisting 7 ``` - - The new node is now up and running, and will start syncing the blockchain from existing peers. Once this has + + The new node is now up and running, and will start syncing the blockchain from existing peers. Once this has completed, it can send new transactions just as any other peer. ### IBFT/Clique -Adding nodes to an IBFT/Clique network is a bit simpler, as it only needs to configure itself rather then be +Adding nodes to an IBFT/Clique network is a bit simpler, as it only needs to configure itself rather then be pre-allocated on the network (permissioning aside). 1. Initialise the new node with the network's genesis configuration. - + !!! note Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. @@ -67,7 +67,7 @@ pre-allocated on the network (permissioning aside). 2. If you are using permissioning or discovery for Ethereum peer-to-peer, please refer [here](#extra-options). -3. Start the new node, pointing either to a `bootnode` or listing an existing peer in the `static-nodes.json` file. +3. Start the new node, pointing either to a `bootnode` or listing an existing peer in the `static-nodes.json` file. Once a connection is established, the node will start syncing the blockchain, after which transactions can be sent. ### Extra options @@ -76,15 +76,15 @@ Some options take effect regardless of the consensus mechanism used. #### Permissioned nodes -If using the `permissioned-nodes.json` file for permissioning, then you must make sure this file is updated on all -nodes before the new node is able to communicate with existing nodes. You do not need to restart any nodes in +If using the `permissioned-nodes.json` file for permissioning, then you must make sure this file is updated on all +nodes before the new node is able to communicate with existing nodes. You do not need to restart any nodes in order for the changes to take effect. #### Static node connections -If not using peer-to-peer node discovery (i.e. you have specified `--nodiscover`), then the only connections a node -made will be to peers defined in the `static-nodes.json` file. When adding a new node, you should make sure you have -peers defined in its `static-nodes.json` file. The more peers you have defined here, the better network connectivity +If not using peer-to-peer node discovery (i.e. you have specified `--nodiscover`), then the only connections a node +made will be to peers defined in the `static-nodes.json` file. When adding a new node, you should make sure you have +peers defined in its `static-nodes.json` file. The more peers you have defined here, the better network connectivity and fault tolerance you have. !!! note @@ -95,11 +95,11 @@ and fault tolerance you have. If you are using discovery, then more options *in addition* to static nodes become available. -- Any nodes that are connected to your peers, which at the start will be ones defined in the static node list, will +- Any nodes that are connected to your peers, which at the start will be ones defined in the static node list, will then be visible by you, allowing you to connect to them; this is done automatically. -- You may specify any number of bootnodes, defined by the `--bootnodes` parameter. This takes a commas separated list -of enode URIs, similar to the `static-nodes.json` file. These act in the same way as static nodes, letting you connect +- You may specify any number of bootnodes, defined by the `--bootnodes` parameter. This takes a commas separated list +of enode URIs, similar to the `static-nodes.json` file. These act in the same way as static nodes, letting you connect to them and then find out about other peers, whom you then connect to. !!! note @@ -110,12 +110,12 @@ to them and then find out about other peers, whom you then connect to. In this tutorial, there will be no focus on the advanced features of adding a new Private Transaction Manager (PTM). This tutorial uses [Tessera](https://github.com/ConsenSys/tessera) for any examples. -Adding a new node to the PTM is relatively straight forward, but there are a lot of extra options that can be used, +Adding a new node to the PTM is relatively straight forward, but there are a lot of extra options that can be used, which is what will be explained here. ### Adding a new PTM node -In a basic setting, adding a new PTM node is as simple as making sure you have one of the existing nodes listed in your +In a basic setting, adding a new PTM node is as simple as making sure you have one of the existing nodes listed in your peer list. In Tessera, this would equate to the following in the configuration file: @@ -129,15 +129,15 @@ In Tessera, this would equate to the following in the configuration file: } ``` -From there, Tessera will connect to that peer and discover all the other PTM nodes in the network, connecting to each +From there, Tessera will connect to that peer and discover all the other PTM nodes in the network, connecting to each of them in turn. !!! note You may want to include multiple peers in the peer list in case any of them are offline/unreachable. - + ### IP whitelisting -The IP Whitelist that Tessera provides allows you restrict connections much like the `permissioned-nodes.json` file +The IP Whitelist that Tessera provides allows you restrict connections much like the `permissioned-nodes.json` file does for GoQuorum. Only IP addresses/hostnames listed in your peers list will be allowed to connect to you. See the [Tessera configuration page](https://docs.tessera.consensys.net) for details on setting it up. @@ -149,7 +149,7 @@ In order to make sure the new node is accepted into the network: ```bash $ java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 ``` - + 2. The new peer can be started, setting the `peers` configuration to mirror the existing network. e.g. if there are 3 existing nodes in the network, then the new nodes configuration will look like this: ```json @@ -168,33 +168,33 @@ In order to make sure the new node is accepted into the network: } ``` - The new node will allow incoming connections from the existing peers, and then existing peers will allow incoming + The new node will allow incoming connections from the existing peers, and then existing peers will allow incoming connections from the new peer! - + ### Discovery -Tessera discovery is very similar to the IP whitelist. The difference being that the IP whitelist blocks +Tessera discovery is very similar to the IP whitelist. The difference being that the IP whitelist blocks communications between nodes, whereas disabling discovery only affects which public keys we keep track of. -See the [Tessera configuration page](https://docs.tessera.consensys.net) for +See the [Tessera configuration page](https://docs.tessera.consensys.net) for details on setting it up. - -When discovery is disabled, Tessera will only allow keys that are owned by a node in its peer list to be available to -the users. This means that if any keys are found that are owned by a node NOT in our peer list, they are discarded and + +When discovery is disabled, Tessera will only allow keys that are owned by a node in its peer list to be available to +the users. This means that if any keys are found that are owned by a node NOT in our peer list, they are discarded and private transactions cannot be sent to that public key. !!! note This does not affect incoming transactions. Someone not in your peer list can still send transactions to your node, unless you also enable the IP Whitelist option. - + In order to make sure the new node is accepted into the network: -1. You will need to add the new peer to each of the existing nodes before they will accept public keys that are linked +1. You will need to add the new peer to each of the existing nodes before they will accept public keys that are linked to the new peer. Tessera provides a way to do this without needing to restart an already running node: ```bash $ java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 ``` - + 2. The new peer can be started, setting the `peers` configuration to mirror the existing network. e.g. if there are 3 existing nodes in the network, then the new nodes configuration will look like this: ```json @@ -212,11 +212,11 @@ to the new peer. ] } ``` - - The new node will now record public keys belonging to the existing peers, and then existing peers will record + + The new node will now record public keys belonging to the existing peers, and then existing peers will record public keys belonging to the new peer; this allows private transactions to be sent both directions! - - + + ## Examples -For a walkthrough of some examples that put into action the above, check out [this guide](add_node_examples.md). +For a walkthrough of some examples that put into action the above, check out [this guide](add_node_examples.md). diff --git a/docs/HowTo/Use/graphql.md b/docs/HowTo/Use/graphql.md index d55808fa..9acc4af7 100644 --- a/docs/HowTo/Use/graphql.md +++ b/docs/HowTo/Use/graphql.md @@ -3,8 +3,8 @@ ## Overview -Ethereum has defined a GraphQL schema as part of -[EIP 1767](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1767.md). To support GoQuorum private transaction data, +Ethereum has defined a GraphQL schema as part of +[EIP 1767](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1767.md). To support GoQuorum private transaction data, a supplement schema and implementation has been added on top of the default. #### New Supplement Schema for GoQuorum diff --git a/docs/HowTo/Use/import-export.md b/docs/HowTo/Use/import-export.md index fde428c1..8198a869 100644 --- a/docs/HowTo/Use/import-export.md +++ b/docs/HowTo/Use/import-export.md @@ -1,7 +1,7 @@ # Backup and Restore of GoQuorum Nodes -GoQuorum supports export and import of chain data with built in tooling. This is an effective node backup mechanism -adapted for the specific needs of GoQuorum such as private transactions, permissioning, and supported consensus +GoQuorum supports export and import of chain data with built in tooling. This is an effective node backup mechanism +adapted for the specific needs of GoQuorum such as private transactions, permissioning, and supported consensus algorithms. @@ -23,11 +23,11 @@ Backup functionality mimics original `geth export` command. GoQuorum export acce ### Node Restore (Import) Restore functionality mimics original `geth import` command but requires transaction manager environment variable. -GoQuorum import must run on a new node with an initialized `--datadir` after `geth init` has been executed. Restore +GoQuorum import must run on a new node with an initialized `--datadir` after `geth init` has been executed. Restore supports arbitrary number of import files (at least 1). !!! warning - If private transactions are used in the chain data, Private Transaction Manager process for the original exported + If private transactions are used in the chain data, Private Transaction Manager process for the original exported node must be running on the PTM ipc endpoint during import chain. Otherwise, nil pointer exceptions will be raised. ##### Sample command @@ -38,11 +38,11 @@ supports arbitrary number of import files (at least 1). ##### IBFT -IBFT block data contains sealer information in the header, to restore a copy of exported chain data, the new node must -be initialized use an IBFT genesis file with exact same validator set encoded in extra data field as original exported +IBFT block data contains sealer information in the header, to restore a copy of exported chain data, the new node must +be initialized use an IBFT genesis file with exact same validator set encoded in extra data field as original exported node's genesis. ##### Raft -Raft backup do not account for current Raft state. An exported chain data from a Raft cluster can only be used by +Raft backup do not account for current Raft state. An exported chain data from a Raft cluster can only be used by new nodes being added to that same cluster only. diff --git a/docs/Reference/APIs/PermissioningAPIs.md b/docs/Reference/APIs/PermissioningAPIs.md index 1b51b621..d04270e3 100644 --- a/docs/Reference/APIs/PermissioningAPIs.md +++ b/docs/Reference/APIs/PermissioningAPIs.md @@ -474,7 +474,7 @@ This api can only be executed by a network admin account and is used for tempora ### `quorumPermission_approveOrgStatus` -This api can only be executed by a network admin account and is used for approving the org status change proposal. Once majority approval is received from network admins, the org status is updated. +This api can only be executed by a network admin account and is used for approving the org status change proposal. Once majority approval is received from network admins, the org status is updated. #### Parameters diff --git a/docs/Reference/APIs/PrivacyAPI.md b/docs/Reference/APIs/PrivacyAPI.md index 7c525c32..eb3e3977 100644 --- a/docs/Reference/APIs/PrivacyAPI.md +++ b/docs/Reference/APIs/PrivacyAPI.md @@ -74,8 +74,8 @@ __Important:__ Before calling this API, a `storeraw` api need to be called first ##### Returns `String` - The 32 Bytes transaction hash as HEX string. If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - - + + ##### Example ```js @@ -83,10 +83,10 @@ __Important:__ Before calling this API, a `storeraw` api need to be called first var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') var rawTx = { nonce: '0x00', - gasPrice: '0x09184e72a000', + gasPrice: '0x09184e72a000', gasLimit: '0x2710', - to: '0x0000000000000000000000000000000000000000', - value: '0x00', + to: '0x0000000000000000000000000000000000000000', + value: '0x00', // This data should be the hex value of the hash returned by Tessera after invoking storeraw api data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057' } @@ -105,8 +105,8 @@ To support offline signing of transaction. This api fills and defaults `RLP` plu ##### Parameters 1. `Object` - The transaction object to send: - - `from`: `String` - The address for the sending account. - - `to`: `String` - (optional) The destination address of the message, + - `from`: `String` - The address for the sending account. + - `to`: `String` - (optional) The destination address of the message, - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. @@ -164,7 +164,7 @@ Call `eth.sendRawPrivateTransaction` to send the transaction to intended recipie > eth.sendRawPrivateTransaction(b.raw, {privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}) "0xcd8ab3f6dbdb8535a44d47df9c7d8a3862fe9fb4257a2d377bdd8bface016928" ``` - + ## JSON RPC Privacy API Reference @@ -178,11 +178,11 @@ Returns the storage root of given address (Contract/Account etc) ##### Parameters 1. `address`: `String` - The address to fetch the storage root for in hex -2. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. +2. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. ##### Returns -`String` - 32 Bytes storageroot hash as HEX string at latest block height. When blocknumber is given, it provides the storageroot hash at that block height. +`String` - 32 Bytes storageroot hash as HEX string at latest block height. When blocknumber is given, it provides the storageroot hash at that block height. ##### Example @@ -266,15 +266,15 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ *** #### eth_sendTransactionAsync - - Sends a transaction to the network asynchronously. This will return - immediately, potentially before the transaction has been submitted to the - transaction pool. A callback can be provided to receive the result of + + Sends a transaction to the network asynchronously. This will return + immediately, potentially before the transaction has been submitted to the + transaction pool. A callback can be provided to receive the result of submitting the transaction; a server must be set up to receive POST requests at the given URL. - + ##### Parameters - + 1. `Object` - The transaction object to send: - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. @@ -287,20 +287,20 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction - + ##### Returns - + 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` - + The callback URL receives the following object: - + 2. `Object` - The result object: - `id`: `String` - the identifier in the original RPC call, used to match this result to the request - `txHash`: `String` - the transaction hash that was generated, if successful - `error`: `String` - the error that occurred whilst submitting the transaction. - + If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - + ##### Example For the RPC call and the immediate response: @@ -320,7 +320,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send // Request curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' -//If a syntactic error occured with the RPC call. +//If a syntactic error occured with the RPC call. //In this example the wallet address is the wrong length //so the error is it cannot convert the parameter to the correct type //it is NOT an error relating the the address not being managed by this node. @@ -338,7 +338,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send If the callback URL is provided, the following response will be received after the transaction has been submitted; this example assumes a webserver that can -be accessed by calling http://localhost:8080 has been set up to accept POST +be accessed by calling http://localhost:8080 has been set up to accept POST requests: ``` @@ -360,7 +360,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send // Request curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' -//If a semantic error occured with the RPC call. +//If a semantic error occured with the RPC call. //In this example the wallet address is not managed by the node //So the RPC call will succeed (giving the empty hash), but the callback will show a failure diff --git a/docs/Reference/CakeshopFAQ.md b/docs/Reference/CakeshopFAQ.md index 407f50d4..375cab4c 100644 --- a/docs/Reference/CakeshopFAQ.md +++ b/docs/Reference/CakeshopFAQ.md @@ -1,23 +1,23 @@ ??? question "How do I call contracts or send Transactions to existing contracts?" - The "Sandbox" tab provides the ability to load up a contract that has been deployed using Cakeshop or the Cakeshop APIs and to make Read calls or submit Transactions to those contracts. - + The "Sandbox" tab provides the ability to load up a contract that has been deployed using Cakeshop or the Cakeshop APIs and to make Read calls or submit Transactions to those contracts. -??? question "How do I find existing contracts?" + +??? question "How do I find existing contracts?" The "Contracts" explorer tab lists all contracts that have been deployed using Cakeshop sandbox. ??? question "How do I deploy contracts to my network using Cakeshop?" - The "Sandbox" tab provides the ability to write and deploy contracts onto your chain. + The "Sandbox" tab provides the ability to write and deploy contracts onto your chain. ??? question "How do I run Cakeshop on any Ethereum build or on my private Ethereum network?" - See the [Attach Mode](../Getting Started#attach-mode) instructions for using Cakeshop with your Ethereum-like node. This provides you the ability to start Cakeshop without auto-starting a geth node, and then attach it to your already-running node. + See the [Attach Mode](../Getting Started#attach-mode) instructions for using Cakeshop with your Ethereum-like node. This provides you the ability to start Cakeshop without auto-starting a geth node, and then attach it to your already-running node. ??? question "How do I run Cakeshop on many nodes?" - See the [Multi-Instance](../Getting Started#multi-instance-setup) instructions for managing multiple nodes that you control on an Ethereum-based network. + See the [Multi-Instance](../Getting Started#multi-instance-setup) instructions for managing multiple nodes that you control on an Ethereum-based network. ??? question "How do I save the solidity files that I have written in the Sandbox?" diff --git a/docs/Reference/Consensus/IBFTParameters.md b/docs/Reference/Consensus/IBFTParameters.md index 0f246055..10d55942 100644 --- a/docs/Reference/Consensus/IBFTParameters.md +++ b/docs/Reference/Consensus/IBFTParameters.md @@ -1,4 +1,4 @@ -# IBFT Parameters +# IBFT Parameters ## Command line options @@ -8,7 +8,7 @@ Setting the block period is used for how long blocks should be minted by the validators. It is also used for validation of block times by all nodes, so should not be changed after deciding a value for the network. -The setting is a positive integer, and measures the minimum numbers of seconds before the next block is considered +The setting is a positive integer, and measures the minimum numbers of seconds before the next block is considered valid. The default value is `1`. @@ -18,17 +18,17 @@ The default value is `1`. `--istanbul.requesttimeout 10000` The request timeout is the timeout at which IBFT will seek to trigger a new round if the previous one did not complete. -This period increases are the timeout is hit more often. This parameter sets the minimum timeout in the case of normal +This period increases are the timeout is hit more often. This parameter sets the minimum timeout in the case of normal operation and is measured in milliseconds. The default value is `10000`. ## Genesis file options -Within the `genesis.json` file, there is an area for IBFT specific configuration, much like a Clique network -configuration. +Within the `genesis.json` file, there is an area for IBFT specific configuration, much like a Clique network +configuration. -The options are as follows: +The options are as follows: ``` { "config": { @@ -46,14 +46,14 @@ The options are as follows: ### Epoch The epoch specifies the number of blocks that should pass before pending validator votes are reset. When the -`blocknumber%EPOCH == 0`, the votes are reset in order to prevent a single vote from becoming stale. If the existing +`blocknumber%EPOCH == 0`, the votes are reset in order to prevent a single vote from becoming stale. If the existing vote was still due to take place, then it must be resubmitted, along with all its votes. ### Policy The policy refers to the proposer selection policy, which is either `ROUND_ROBIN` or `STICKY`. -A value of `0` denotes a `ROUND_ROBIN` policy, where the next expected proposer is the next in queue. Once a proposer +A value of `0` denotes a `ROUND_ROBIN` policy, where the next expected proposer is the next in queue. Once a proposer has submitted a valid block, they join the back of the queue and must wait their turn again. A value of `1` denotes a `STICKY` proposer policy, where a single proposer is selected to mint blocks and does so until @@ -61,9 +61,9 @@ such a time as they go offline or are otherwise unreachable. ### ceil2Nby3Block -The `ceil2Nby3Block` sets the block number from which to use an updated formula for calculating the number of faulty +The `ceil2Nby3Block` sets the block number from which to use an updated formula for calculating the number of faulty nodes. This was introduced to enable existing network the ability to upgrade at a point in the future of the network, as -it is incompatible with the existing formula. For new networks, it is recommended to set this value to `0` to use the +it is incompatible with the existing formula. For new networks, it is recommended to set this value to `0` to use the updated formula immediately. To update this value, the same process can be followed as other hard-forks. diff --git a/docs/Reference/Consensus/Raft-RPC-API.md b/docs/Reference/Consensus/Raft-RPC-API.md index f715363d..cc83ee15 100644 --- a/docs/Reference/Consensus/Raft-RPC-API.md +++ b/docs/Reference/Consensus/Raft-RPC-API.md @@ -184,7 +184,7 @@ API to remove a node from raft cluster #### Parameters -* `raftId` : raft id of the node to be removed from the cluster +* `raftId` : raft id of the node to be removed from the cluster #### Returns diff --git a/docs/Reference/FAQ.md b/docs/Reference/FAQ.md index 412995b1..6f76220e 100644 --- a/docs/Reference/FAQ.md +++ b/docs/Reference/FAQ.md @@ -2,23 +2,23 @@ ??? question "I've run into an issue with GoQuorum, where do I get support?" The [GoQuorum Slack channels](https://93ecjxb0d3.execute-api.us-east-1.amazonaws.com/Express/) are the best place to query the community and get immediate help. - - The GoQuorum engineering team monitors Slack as well as any issues raised on the GoQuorum GitHub repositories (e.g. [Quorum](https://github.com/ConsenSys/quorum/), [Tessera](https://github.com/ConsenSys/tessera), [Quorum-Examples](https://github.com/ConsenSys/quorum-examples), etc.). - + + The GoQuorum engineering team monitors Slack as well as any issues raised on the GoQuorum GitHub repositories (e.g. [Quorum](https://github.com/ConsenSys/quorum/), [Tessera](https://github.com/ConsenSys/tessera), [Quorum-Examples](https://github.com/ConsenSys/quorum-examples), etc.). + ??? question "How does GoQuorum achieve Transaction Privacy?" GoQuorum achieves Transaction Privacy by: - + 1. Enabling transaction Senders to create a private transaction by marking who is privy to that transaction via the `privateFor` parameter 2. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction - 3. Storing encrypted private data off-chain in a separate component called the Privacy Manager (provided by [Tessera](https://github.com/ConsenSys/tessera)). The Privacy Manager distributes the encrypted data to other parties that are privy to the transaction and returns the decrypted payload to those parties - + 3. Storing encrypted private data off-chain in a separate component called the Privacy Manager (provided by [Tessera](https://github.com/ConsenSys/tessera)). The Privacy Manager distributes the encrypted data to other parties that are privy to the transaction and returns the decrypted payload to those parties + Please see the [Transaction and Contract Privacy](../Privacy/Overview) section for more info. - + ??? question "How does GoQuorum achieve consensus on Private Transactions?" - In standard Ethereum, all nodes process all transactions and so each node has the same state root. In GoQuorum, nodes process all 'public' transactions (which might include reference data or market data contracts for example) but only process the private transactions that they are party to. - - GoQuorum nodes maintain two Patricia Merkle Tries: one for private state and one for public state. As a result, block validation includes a **state** check on the new-to-GoQuorum `public state root`. Block validation also includes a check of the `global Transaction hash`, which is a hash of **all** Transactions in a block - private and public. This means that each node is able to validate that it has the same set of Transactions as other nodes. Since the EVM is provably deterministic through the synchronized public state root, and that the Private Transaction inputs are known to be in sync across nodes (global Transaction Hash), private state synchronization across nodes can be implied. In addition, GoQuorum provides an API call, `eth_storageRoot`, that returns the private state hash for a given transaction at a given block height, that can optionally be called at the application layer to specifically perform an off-chain state validation with a counterparty. - + In standard Ethereum, all nodes process all transactions and so each node has the same state root. In GoQuorum, nodes process all 'public' transactions (which might include reference data or market data contracts for example) but only process the private transactions that they are party to. + + GoQuorum nodes maintain two Patricia Merkle Tries: one for private state and one for public state. As a result, block validation includes a **state** check on the new-to-GoQuorum `public state root`. Block validation also includes a check of the `global Transaction hash`, which is a hash of **all** Transactions in a block - private and public. This means that each node is able to validate that it has the same set of Transactions as other nodes. Since the EVM is provably deterministic through the synchronized public state root, and that the Private Transaction inputs are known to be in sync across nodes (global Transaction Hash), private state synchronization across nodes can be implied. In addition, GoQuorum provides an API call, `eth_storageRoot`, that returns the private state hash for a given transaction at a given block height, that can optionally be called at the application layer to specifically perform an off-chain state validation with a counterparty. + Please see the [GoQuorum Consensus](../Consensus/Consensus) and [Transaction and Contract Privacy Overview](../Privacy/Overview) pages for more info. ??? question "Are there any restrictions on the transaction size for private transactions (since they are encrypted)?" @@ -26,17 +26,17 @@ ??? question "Should I include originating node in private transaction?" No. In GoQuorum, including originating node's `privateFor` results in an error. To create a private - contract that is visible to the originating node only, use this format: `privateFor: []`. + contract that is visible to the originating node only, use this format: `privateFor: []`. ??? question "Is it possible to run a GoQuorum node without a Transaction Manager?" Starting a GoQuorum node with `PRIVATE_CONFIG=ignore` (instead of `PRIVATE_CONFIG=path/to/tm.ipc`) will start the node without a Transaction Manager. The node will not broadcast matching private keys (please ensure that there is no transaction manager running for it) and will be unable to participate in any private transactions. - + ??? question "Are there official docker images for GoQuorum and Tessera?" Yes! The [official docker containers](https://hub.docker.com/u/quorumengineering/): - + `quorumengineering/quorum:latest` `quorumengineering/tessera:latest` - + ??? question "Can I create a network of GoQuorum nodes using different consensus mechanisms?" Unfortunately, that is not possible. GoQuorum nodes configured with raft will only be able to work correctly with other nodes running raft consensus. This applies to all other supported consensus algorithms. @@ -60,7 +60,7 @@ It means the node will only communicate with the nodes defined in the configuration file. Upto version 0.10.2, the nodes still accepts transactions from undiscovered nodes. From version 0.10.3 the node blocks all communication with undiscovered nodes. ??? info "Upgrading to Tessera version 0.10.+ from verion 0.9.+ and below" - Due to 'database file unable to open' issue with H2 DB upgrade from version 1.4.196 direct to version 1.4.200 as explained [here](https://github.com/h2database/h2database/issues/2263), our recommended mitigation strategy is to upgrade to version 1.4.199 first before upgrading to version 1.4.200 i.e., first upgrade to Tessera 0.10.0 before upgrading to higher versions. + Due to 'database file unable to open' issue with H2 DB upgrade from version 1.4.196 direct to version 1.4.200 as explained [here](https://github.com/h2database/h2database/issues/2263), our recommended mitigation strategy is to upgrade to version 1.4.199 first before upgrading to version 1.4.200 i.e., first upgrade to Tessera 0.10.0 before upgrading to higher versions. ### Raft FAQ @@ -69,7 +69,7 @@ ??? question "What happens if you don't assume minter and leader are the same node?" There's no hard reason they couldn't be different. We just co-locate the minter and leader as an optimization. - + * It saves one network call communicating the block to the leader. * It provides a simple way to choose a minter. If we didn't use the Raft leader we'd have to build in "minter election" at a higher level. @@ -96,4 +96,4 @@ `--existwhensycned` is not applicable for Raft consensus ??? question "Can I remove the statedb using `geth removedb` command and recover the statedb by syncing with other nodess in the network when running the node in Raft consensus" - `geth removedb` cannot be used with Raft consensus. + `geth removedb` cannot be used with Raft consensus. diff --git a/docs/Reference/GoQuorum-Projects.md b/docs/Reference/GoQuorum-Projects.md index c0c95680..e065dfde 100644 --- a/docs/Reference/GoQuorum-Projects.md +++ b/docs/Reference/GoQuorum-Projects.md @@ -14,7 +14,7 @@ Current examples include: !!! Info Most of the links link out to externally maintained repos. We thank all of the authors. Please contact us for any modifications or questions about the content. -## Zero Knowledge Work +## Zero Knowledge Work ### ZSL Proof of Concept @@ -22,7 +22,7 @@ The proof of concept (POC) implementation of ZSL for GoQuorum enables the issuan using ZSL-enabled public smart contracts (z-contracts). We refer to such digital assets as “z-tokens”. Z-tokens can be shielded from public view and transacted privately. Proof that a shielded transaction has been executed can be presented to a private contract, thereby allowing the private contract to update -its state in response to shielded transactions that are executed using public z-contracts. +its state in response to shielded transactions that are executed using public z-contracts. This combination of Tessera private contracts with ZSL z-contracts, allows obligations that arise from a private contract, to be settled using shielded transfers of z-tokens, while maintaining full privacy and confidentiality. diff --git a/docs/Reference/Plugins/security/For-Developers.md b/docs/Reference/Plugins/security/For-Developers.md index 8bb5bb8d..5338c6c4 100644 --- a/docs/Reference/Plugins/security/For-Developers.md +++ b/docs/Reference/Plugins/security/For-Developers.md @@ -2,13 +2,13 @@ New `security` plugins can be developed to customize protection of JSON API server -`security` plugins must satisfy the [documented gRPC API](interface.md). +`security` plugins must satisfy the [documented gRPC API](interface.md). -!!! note +!!! note This documentation is auto-generated from the [Quorum Plugin Definitions](https://www.github.com/ConsenSys/quorum-plugin-definitions) `security.proto` file -To simplify the development of new `security` plugins the following `security` plugin SDKs are available: +To simplify the development of new `security` plugins the following `security` plugin SDKs are available: | Name | Language | -| --- | --- | +| --- | --- | | [quorum-security-plugin-sdk-go](https://www.github.com/ConsenSys/quorum-security-plugin-sdk-go) | [Go](https://golang.org) diff --git a/docs/Reference/Plugins/security/For-Users.md b/docs/Reference/Plugins/security/For-Users.md index f8908db7..cb1afbd3 100644 --- a/docs/Reference/Plugins/security/For-Users.md +++ b/docs/Reference/Plugins/security/For-Users.md @@ -8,7 +8,7 @@ providing the following enterprise features to `geth` JSON RPC server: ## Configuration -One of the below blocks must be configured: +One of the below blocks must be configured:
 {
@@ -170,7 +170,7 @@ Below is the default configuration if not specified
 
 ### `EnvironmentAwaredValue`
 
-A regular string which allows value being read from an environment variable 
+A regular string which allows value being read from an environment variable
 by specifying an URI with `env` scheme. For example: `env://MY_VAR` will return
 value from `MY_VAR` environment variable.
 
@@ -206,8 +206,8 @@ Examples on how to integrate Quorum Security Plugin with an OAuth2 Authorization
 ## OAuth2 Scopes
 
 Scope is a mechanism to limit a client's access to protected resources
-in Quorum Client RPC server. A client can request one ore more scopes 
-from a token endpoint of an OAuth2 Provider. The access token issued to 
+in Quorum Client RPC server. A client can request one ore more scopes
+from a token endpoint of an OAuth2 Provider. The access token issued to
 the client will be limited to the scopes granted.
 
 The scope syntax is as follow:
@@ -215,11 +215,11 @@ The scope syntax is as follow:
     scope := "rpc://"rpc-string
 
     rpc-string := service-name delimiter method-name
-   
+
     service-name := string
-   
+
     delimiter := "." or "_"
-   
+
     method-name := string
 ```
 
diff --git a/docs/Reference/quorum.js/Overview.md b/docs/Reference/quorum.js/Overview.md
index caac0a52..50b59143 100644
--- a/docs/Reference/quorum.js/Overview.md
+++ b/docs/Reference/quorum.js/Overview.md
@@ -1,7 +1,7 @@
 # quorum.js
 
 ## Overview, Installation, Quickstart & Examples
-See the [project page README](https://github.com/ConsenSys/quorum.js). 
+See the [project page README](https://github.com/ConsenSys/quorum.js).
 
 ## API
 This documentation provides additional usage and API information not included in the README.
diff --git a/docs/Reference/quorum.js/RawTransactionManager.md b/docs/Reference/quorum.js/RawTransactionManager.md
index 10022da8..bffbf894 100644
--- a/docs/Reference/quorum.js/RawTransactionManager.md
+++ b/docs/Reference/quorum.js/RawTransactionManager.md
@@ -21,7 +21,7 @@ const enclaveOptions = {
 const txnMngr = quorumjs.RawTransactionManager(web3, enclaveOptions);
 
 txnMngr.sendRawTransaction(args);
-``` 
+```
 
 ## Parameters
 | param | type | required | description |
@@ -49,25 +49,25 @@ txnMngr.sendRawTransaction(args);
 ### sendRawTransaction
 
 !!! info "If using Constellation"
-    Constellation privacy managers do not support this method.  Use [`sendRawTransactionViaSendAPI`](#sendrawtransactionviasendapi) instead.
-    
+    Constellation privacy managers do not support this method. Use [`sendRawTransactionViaSendAPI`](#sendrawtransactionviasendapi) instead.
+
 ```js
 txnMngr.sendRawTransaction(txnParams);
 ```
 Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnParams` with the response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, RLP encodes the transaction in hex format, and submits the signed transaction to the blockchain with `eth_sendRawPrivateTransaction`.
 
 #### Parameters
-1. `txnParams` - The transaction to sign and send 
+1. `txnParams` - The transaction to sign and send
     - `gasPrice`: `Number` - Must always be 0 in Quorum networks
     - `gasLimit`: `Number` - The amount of gas to use for the transaction
-    - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction 
+    - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction
     - `value`: `Number` - (optional) The value transferred for the transaction
     - `data`: `String` - (optional) Either a byte string containing the associated data of the message, or the initialisation code (bytecode) in the case of a contract-creation transaction
-    - `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt) 
+    - `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt)
     - `nonce`: `Number`  - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
     - `privateFrom`: `String`  - When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, the default key as configured in the `TransactionManager` is used
     - `privateFor`: `List`  - When sending a private transaction, an array of the recipients' base64-encoded public keys
-    - `isPrivate`: `boolean` - Is the transaction private 
+    - `isPrivate`: `boolean` - Is the transaction private
 1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous.
 
 #### Returns
@@ -76,7 +76,7 @@ A promise that resolves to the transaction receipt if the transaction was sent s
 ### sendRawTransactionViaSendAPI
 
 !!! info "If using Tessera"
-    Tessera privacy managers support [`sendRawTransaction`](#sendrawtransaction) which should be used instead.  `sendRawTransactionViaSendAPI` requires exposing the `Q2T` server to the `js` app.  Ideally only the `ThirdParty` server should be exposed to such applications.
+    Tessera privacy managers support [`sendRawTransaction`](#sendrawtransaction) which should be used instead.  `sendRawTransactionViaSendAPI` requires exposing the `Q2T` server to the `js` app. Ideally only the `ThirdParty` server should be exposed to such applications.
 
 ```js
 txnMngr.sendRawTransactionViaSendAPI(txnParams);
@@ -85,17 +85,17 @@ txnMngr.sendRawTransactionViaSendAPI(txnParams);
 Calls Privacy Manager's `/send` API to encrypt txn data and send to all participant Privacy Manager nodes, replaces `data` field in `txnParams` with response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, and submits the signed transaction to the blockchain with `eth_sendRawTransaction`.
 
 #### Parameters
-1. `txnParams` - The transaction to sign and send 
+1. `txnParams` - The transaction to sign and send
     - `gasPrice`: `Number` - Must always be 0 in Quorum networks
     - `gasLimit`: `Number` - The amount of gas to use for the transaction
-    - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction 
+    - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction
     - `value`: `Number` - (optional) The value transferred for the transaction
     - `data`: `String` - (optional) Either a byte string containing the associated data of the message, or the initialisation code (bytecode) in the case of a contract-creation transaction
-    - `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt) 
+    - `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt)
     - `nonce`: `Number`  - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
     - `privateFrom`: `String`  - When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, the default key as configured in the `TransactionManager` is used
     - `privateFor`: `List`  - When sending a private transaction, an array of the recipients' base64-encoded public keys
-    - `isPrivate`: `boolean` - Is the transaction private 
+    - `isPrivate`: `boolean` - Is the transaction private
 1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous.
 
 #### Returns
@@ -108,7 +108,7 @@ txnMngr.setPrivate(rawTransaction);
 Marks a signed transaction as private by changing the value of `v` to `37` or `38`.
 #### Parameters
 1. `rawTransaction`: `String` - RLP-encoded hex-format signed transaction
-#### Returns 
+#### Returns
 Updated RLP-encoded hex-format signed transaction
 
 ### storeRawRequest
@@ -122,7 +122,7 @@ Calls Tessera's `ThirdParty` `/storeraw` API to encrypt the provided `data` and
 1. `privateFrom`: `String` - Sending party's base64-encoded public key
 
 #### Returns
-A promise that resolves to the hex-encoded hash of the encrypted `data` (`key` field) that should be used to replace the `data` field of a transaction if externally signing.  
+A promise that resolves to the hex-encoded hash of the encrypted `data` (`key` field) that should be used to replace the `data` field of a transaction if externally signing.
 
 ### sendRawRequest
 ```js
@@ -159,6 +159,6 @@ A promise that resolves to the transaction receipt if the transaction was sent s
     ```js
      txnManager.sendRawRequest(serializedTransaction, privateFor)
     ```
- 
+
 ### Other examples
-The [7nodes-test](https://github.com/ConsenSys/quorum.js/tree/master/7nodes-test) directory in the quorum.js project repo contains examples of quorum.js usage.  These scripts can be tested with a running [7nodes test network](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes).
+The [7nodes-test](https://github.com/ConsenSys/quorum.js/tree/master/7nodes-test) directory in the quorum.js project repo contains examples of quorum.js usage. These scripts can be tested with a running [7nodes test network](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes).
diff --git a/docs/Reference/quorum.js/extend.md b/docs/Reference/quorum.js/extend.md
index b419bed6..6db75529 100644
--- a/docs/Reference/quorum.js/extend.md
+++ b/docs/Reference/quorum.js/extend.md
@@ -15,7 +15,7 @@ web3.quorum.eth.sendRawPrivateTransaction(signedTx, args);
 | param | type | required | description |
 | :---: | :---: | :---: | --- |
 | `web3` | `Object` | yes | web3 instance |
-| `apis` | `String` | no | comma-separated list of APIs to extend `web3` with.  Default is to add all APIs, i.e. `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` | 
+| `apis` | `String` | no | comma-separated list of APIs to extend `web3` with. Default is to add all APIs, i.e. `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` |
 
 ## Methods
 See the [Raft](../Consensus/Raft-RPC-API.md), [Istanbul](../Consensus/IBFT-RPC-API.md), [Privacy](../APIs/PrivacyAPI.md), and [Permissioning](../APIs/PermissioningAPIs.md) API documentation for API details.
diff --git a/docs/Tutorials/CreatePermissionedNetwork.md b/docs/Tutorials/CreatePermissionedNetwork.md
index 804e4f05..c4f7e883 100644
--- a/docs/Tutorials/CreatePermissionedNetwork.md
+++ b/docs/Tutorials/CreatePermissionedNetwork.md
@@ -1,4 +1,4 @@
-# Create a permissioned network 
+# Create a permissioned network
 
 ## 1. Initialize chain
 
@@ -67,7 +67,7 @@ node a spectator. If you have setup a bootnode then be sure to add the `--bootno
 ## Adding New Nodes
 
 Any additions to the `permissioned-nodes.json` file are dynamically picked up by the server when
-subsequent incoming/outgoing requests are made. The node does not need to be restarted in order for the changes to take effect. 
+subsequent incoming/outgoing requests are made. The node does not need to be restarted in order for the changes to take effect.
 
 ## Removing existing nodes
 
diff --git a/docs/Tutorials/Creating-A-Network-From-Scratch.md b/docs/Tutorials/Creating-A-Network-From-Scratch.md
index b12b6ecd..bbb764c0 100644
--- a/docs/Tutorials/Creating-A-Network-From-Scratch.md
+++ b/docs/Tutorials/Creating-A-Network-From-Scratch.md
@@ -1,5 +1,5 @@
 ---
-description: Creating a network from scratch tutorial 
+description: Creating a network from scratch tutorial
 ---
 
 # Creating a network from scratch
@@ -27,22 +27,22 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
 3. Generate one or more accounts for this node and take down the account address. A funded account may be required depending what you are trying to accomplish
     ```
     $ geth --datadir new-node-1 account new
-    
+
      INFO [06-07|14:52:18.742] Maximum peer count                       ETH=25 LES=0 total=25
      Your new account is locked with a password. Please give a password. Do not forget this password.
-     Passphrase: 
-     Repeat passphrase: 
+     Passphrase:
+     Repeat passphrase:
      Address: {679fed8f4f3ea421689136b25073c6da7973418f}
-     
+
      Please note the keystore file generated inside new-node-1 includes the address in the last part of its filename.
-     
+
      $ ls new-node-1/keystore
      UTC--2019-06-17T09-29-06.665107000Z--679fed8f4f3ea421689136b25073c6da7973418f
     ```
 
-    !!! note 
+    !!! note
         You could generate multiple accounts for a single node, or any number of accounts for additional nodes and pre-allocate them with funds in the genesis.json file (see below)
-       
+
 4. Create a `genesis.json` file see example [here](../Reference/genesis.md). The `alloc` field should be pre-populated with the account you generated at previous step
     ```
     $ vim genesis.json
@@ -77,7 +77,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
      "nonce": "0x0",
      "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "timestamp": "0x00"
-    }   
+    }
     ```
 5. Generate node key and copy it into datadir
     ```
@@ -87,7 +87,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
 6. Execute below command to display enode id of the new node
     ```
     $ bootnode --nodekey=new-node-1/nodekey --writeaddress > new-node-1/enode
-    $ cat new-node-1/enode  
+    $ cat new-node-1/enode
     '70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8'
     ```
 7. Create a file called `static-nodes.json` and edit it to match this [example](permissioned-nodes.md). Your file should contain a single line for your node with your enode's id and the ports you are going to use for devp2p and raft. Ensure that this file is in your nodes data directory
@@ -96,21 +96,21 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     .... paste below lines with enode generated in previous step, port 21000;IP 127.0.0.1 and raft port set as 50000
     [
       "enode://70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8@127.0.0.1:21000?discport=0&raftport=50000"
-    ] 
+    ]
     $ cp static-nodes.json new-node-1
     ```
 8. Initialize new node with below command.
     ```
     $ geth --datadir new-node-1 init genesis.json
-    
+
     INFO [06-07|15:45:17.508] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-07|15:45:17.516] Allocated cache and file handles         database=/Users/krish/new-node-1/geth/chaindata cache=16 handles=16
-    INFO [06-07|15:45:17.524] Writing custom genesis block 
+    INFO [06-07|15:45:17.524] Writing custom genesis block
     INFO [06-07|15:45:17.524] Persisted trie from memory database      nodes=1 size=152.00B time=75.344µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-07|15:45:17.525] Successfully wrote genesis state         database=chaindata                              hash=ec0542…9665bf
     INFO [06-07|15:45:17.525] Allocated cache and file handles         database=/Users/krish/new-node-1/geth/lightchaindata cache=16 handles=16
-    INFO [06-07|15:45:17.527] Writing custom genesis block 
-    INFO [06-07|15:45:17.527] Persisted trie from memory database      nodes=1 size=152.00B time=60.76µs  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
+    INFO [06-07|15:45:17.527] Writing custom genesis block
+    INFO [06-07|15:45:17.527] Persisted trie from memory database      nodes=1 size=152.00B time=60.76µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-07|15:45:17.527] Successfully wrote genesis state         database=lightchaindata                              hash=ec0542…9665bf
     ```
 9. Start your node by first creating a script as below and then starting it:
@@ -120,24 +120,24 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     #!/bin/bash
     PRIVATE_CONFIG=ignore nohup geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000 >> node.log 2>&1 &
 
-    $ chmod +x startnode1.sh 
+    $ chmod +x startnode1.sh
     $ ./startnode1.sh
-    ``` 
-    
+    ```
+
     !!! note
         This configuration starts GoQuorum without privacy support as could be evidenced in prefix `PRIVATE_CONFIG=ignore`, please see below sections on [how to enable privacy with privacy transaction managers](#adding-privacy-transaction-manager).
 
-    Your node is now operational and you may attach to it with below commands. 
+    Your node is now operational and you may attach to it with below commands.
     ```
     $ geth attach new-node-1/geth.ipc
     Welcome to the Geth JavaScript console!
-    
+
     instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2
     coinbase: 0xedf53f5bf40c99f48df184441137659aed899c48
     at block: 0 (Thu, 01 Jan 1970 01:00:00 BST)
      datadir: /Users/krish/fromscratch/new-node-1
      modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0
-    
+
     > raft.cluster
     [{
         ip: "127.0.0.1",
@@ -150,7 +150,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     "a5596803caebdc9c5326e1a0775563ad8e4aa14aa3530f0ae16d3fd8d7e48bc0b81342064e22094ab5d10303ab5721650af561f2bcdc54d705f8b6a8c07c94c3"
     > raft.role
     "minter"
-    > 
+    >
     > exit
     ```
 
@@ -166,47 +166,47 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     ```
 2. Retrieve current chains `genesis.json` and `static-nodes.json`. `static-nodes.json` should be placed into new nodes data dir
     ```
-    $ cp static-nodes.json new-node-2    
+    $ cp static-nodes.json new-node-2
     ```
 
 3. Edit `static-nodes.json` and add new entry for the new node you are configuring (should be last)
    ```
-   $ vim new-node-2/static-nodes.json 
+   $ vim new-node-2/static-nodes.json
    .... append new-node-2's enode generated in step 1, port 21001;IP 127.0.0.1 and raft port set as 50001
 
    [
      "enode://70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8@127.0.0.1:21000?discport=0&raftport=50000",
      "enode://56e81550db3ccbfb5eb69c0cfe3f4a7135c931a1bae79ea69a1a1c6092cdcbea4c76a556c3af977756f95d8bf9d7b38ab50ae070da390d3abb3d7e773099c1a9@127.0.0.1:21001?discport=0&raftport=50001"
    ]
-   ```  
-    
-4. Initialize new node as given below: 
+   ```
+
+4. Initialize new node as given below:
 
     ```
     $ geth --datadir new-node-2 init genesis.json
-    
+
     INFO [06-07|16:34:39.805] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-07|16:34:39.814] Allocated cache and file handles         database=/Users/krish/fromscratch/new-node-2/geth/chaindata cache=16 handles=16
-    INFO [06-07|16:34:39.816] Writing custom genesis block 
+    INFO [06-07|16:34:39.816] Writing custom genesis block
     INFO [06-07|16:34:39.817] Persisted trie from memory database      nodes=1 size=152.00B time=59.548µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-07|16:34:39.817] Successfully wrote genesis state         database=chaindata                                          hash=f02d0b…ed214a
     INFO [06-07|16:34:39.817] Allocated cache and file handles         database=/Users/krish/fromscratch/new-node-2/geth/lightchaindata cache=16 handles=16
-    INFO [06-07|16:34:39.819] Writing custom genesis block 
+    INFO [06-07|16:34:39.819] Writing custom genesis block
     INFO [06-07|16:34:39.819] Persisted trie from memory database      nodes=1 size=152.00B time=43.733µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-07|16:34:39.819] Successfully wrote genesis state         database=lightchaindata                                          hash=f02d0b…ed214a
     ```
-    
+
 5. Connect to an already running node of the chain and execute raft `addPeer` command.
     ```
     $ geth attach new-node-1/geth.ipc
     Welcome to the Geth JavaScript console!
-    
+
     instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2
     coinbase: 0xedf53f5bf40c99f48df184441137659aed899c48
     at block: 0 (Thu, 01 Jan 1970 01:00:00 BST)
      datadir: /Users/krish/fromscratch/new-node-1
      modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0
-    
+
     > raft.addPeer('enode://56e81550db3ccbfb5eb69c0cfe3f4a7135c931a1bae79ea69a1a1c6092cdcbea4c76a556c3af977756f95d8bf9d7b38ab50ae070da390d3abb3d7e773099c1a9@127.0.0.1:21001?discport=0&raftport=50001')
     2
     > raft.cluster
@@ -232,8 +232,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     ..... paste below details
     #!/bin/bash
     PRIVATE_CONFIG=ignore nohup geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21001 2>>node2.log &
-    
-    $ ./startnode2.sh 
+
+    $ ./startnode2.sh
     ```
 
 7. Optional: share new `static-nodes.json` with all other chain participants
@@ -245,18 +245,18 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
 
 ### Removing node
 1. Connect to an already running node of the chain and execute `raft.cluster` and get the `RAFT_ID` corresponding to the node that needs to be removed
-2. Run `raft.removePeer(RAFT_ID)` 
+2. Run `raft.removePeer(RAFT_ID)`
 3. Stop the `geth` process corresponding to the node that was removed.
     ```
     $ geth attach new-node-1/geth.ipc
     Welcome to the Geth JavaScript console!
-    
+
     instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2
     coinbase: 0xedf53f5bf40c99f48df184441137659aed899c48
     at block: 0 (Thu, 01 Jan 1970 01:00:00 BST)
      datadir: /Users/krish/fromscratch/new-node-1
      modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 raft:1.0 rpc:1.0 txpool:1.0 web3:1.0
-    
+
     > raft.cluster
     [{
         ip: "127.0.0.1",
@@ -271,7 +271,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
         raftId: 1,
         raftPort: 50000
     }]
-    > 
+    >
     > raft.removePeer(2)
     null
     > raft.cluster
@@ -319,7 +319,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     $ git clone https://github.com/ConsenSys/istanbul-tools.git
     $ cd istanbul-tools
     $ make
-    ```    
+    ```
 3. Create a working directory for each of the X number of initial validator nodes
     ```
     $ mkdir node0 node1 node2 node3 node4
@@ -354,8 +354,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     	"Nodekey": "768b87473ba96fcfa272f958fc95a3cefdf9aa82110cde6f2f34aa5855eb39db",
     	"NodeInfo": "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0"
     }
-    
-        
+
+
     static-nodes.json
     [
     	"enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0",
@@ -364,9 +364,9 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     	"enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@0.0.0.0:30303?discport=0",
     	"enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0"
     ]
-    
-    
-    
+
+
+
     genesis.json
     {
         "config": {
@@ -423,7 +423,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
      -rwxr-xr-x  1 krish  staff  1878 11 Jun 16:00 genesis.json
      -rwxr-xr-x  1 krish  staff   832 11 Jun 16:00 static-nodes.json
     ```
-    
+
 5. Update `static-nodes.json` to include the intended IP and port numbers of all initial validator nodes. In `static-nodes.json`, you will see a different row for each node. For the rest of the installation guide, row Y refers to node Y and row 1 is assumed to correspond to the lead node
     ```
     $ cat static-nodes.json
@@ -450,20 +450,20 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     $ geth --datadir node0/data account new
     INFO [06-11|16:05:53.672] Maximum peer count                       ETH=25 LES=0 total=25
     Your new account is locked with a password. Please give a password. Do not forget this password.
-    Passphrase: 
-    Repeat passphrase: 
+    Passphrase:
+    Repeat passphrase:
     Address: {8fc817d90f179b0b627c2ecbcc1d1b0fcd13ddbd}
     $ geth --datadir node1/data account new
     INFO [06-11|16:06:34.529] Maximum peer count                       ETH=25 LES=0 total=25
     Your new account is locked with a password. Please give a password. Do not forget this password.
-    Passphrase: 
-    Repeat passphrase: 
+    Passphrase:
+    Repeat passphrase:
     Address: {dce8adeef16a45d94be5e7804df6d35db834d94a}
     $ geth --datadir node2/data account new
     INFO [06-11|16:06:54.365] Maximum peer count                       ETH=25 LES=0 total=25
     Your new account is locked with a password. Please give a password. Do not forget this password.
-    Passphrase: 
-    Repeat passphrase: 
+    Passphrase:
+    Repeat passphrase:
     Address: {65a3ab6d4cf23395f544833831fc5d42a0b2b43a}
     ```
 8. To add accounts to the initial block, edit the `genesis.json` file in the lead node's working directory and update the `alloc` field with the account(s) that were generated at previous step
@@ -530,11 +530,11 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     $ geth --datadir data init genesis.json
     INFO [06-11|16:14:11.883] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-11|16:14:11.894] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node0/data/geth/chaindata cache=16 handles=16
-    INFO [06-11|16:14:11.896] Writing custom genesis block 
+    INFO [06-11|16:14:11.896] Writing custom genesis block
     INFO [06-11|16:14:11.897] Persisted trie from memory database      nodes=6 size=1.01kB time=76.665µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:11.897] Successfully wrote genesis state         database=chaindata                                                  hash=b992be…533db7
     INFO [06-11|16:14:11.897] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node0/data/geth/lightchaindata cache=16 handles=16
-    INFO [06-11|16:14:11.898] Writing custom genesis block 
+    INFO [06-11|16:14:11.898] Writing custom genesis block
     INFO [06-11|16:14:11.898] Persisted trie from memory database      nodes=6 size=1.01kB time=54.929µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:11.898] Successfully wrote genesis state         database=lightchaindata                                                  hash=b992be…533db7
     $
@@ -543,11 +543,11 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     $ geth --datadir data init genesis.json
     INFO [06-11|16:14:24.814] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-11|16:14:24.824] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node1/data/geth/chaindata cache=16 handles=16
-    INFO [06-11|16:14:24.831] Writing custom genesis block 
+    INFO [06-11|16:14:24.831] Writing custom genesis block
     INFO [06-11|16:14:24.831] Persisted trie from memory database      nodes=6 size=1.01kB time=82.799µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:24.832] Successfully wrote genesis state         database=chaindata                                                  hash=b992be…533db7
     INFO [06-11|16:14:24.832] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node1/data/geth/lightchaindata cache=16 handles=16
-    INFO [06-11|16:14:24.833] Writing custom genesis block 
+    INFO [06-11|16:14:24.833] Writing custom genesis block
     INFO [06-11|16:14:24.833] Persisted trie from memory database      nodes=6 size=1.01kB time=52.828µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:24.834] Successfully wrote genesis state         database=lightchaindata                                                  hash=b992be…533db7
     $
@@ -556,33 +556,33 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     $ geth --datadir data init genesis.json
     INFO [06-11|16:14:35.246] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-11|16:14:35.257] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node2/data/geth/chaindata cache=16 handles=16
-    INFO [06-11|16:14:35.264] Writing custom genesis block 
+    INFO [06-11|16:14:35.264] Writing custom genesis block
     INFO [06-11|16:14:35.265] Persisted trie from memory database      nodes=6 size=1.01kB time=124.91µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:35.265] Successfully wrote genesis state         database=chaindata                                                  hash=b992be…533db7
     INFO [06-11|16:14:35.265] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node2/data/geth/lightchaindata cache=16 handles=16
-    INFO [06-11|16:14:35.267] Writing custom genesis block 
+    INFO [06-11|16:14:35.267] Writing custom genesis block
     INFO [06-11|16:14:35.268] Persisted trie from memory database      nodes=6 size=1.01kB time=85.504µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:35.268] Successfully wrote genesis state         database=lightchaindata                                                  hash=b992be…533db7
     $ cd ../node3
     $ geth --datadir data init genesis.json
     INFO [06-11|16:14:42.168] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-11|16:14:42.178] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node3/data/geth/chaindata cache=16 handles=16
-    INFO [06-11|16:14:42.186] Writing custom genesis block 
+    INFO [06-11|16:14:42.186] Writing custom genesis block
     INFO [06-11|16:14:42.186] Persisted trie from memory database      nodes=6 size=1.01kB time=124.611µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:42.187] Successfully wrote genesis state         database=chaindata                                                  hash=b992be…533db7
     INFO [06-11|16:14:42.187] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node3/data/geth/lightchaindata cache=16 handles=16
-    INFO [06-11|16:14:42.189] Writing custom genesis block 
+    INFO [06-11|16:14:42.189] Writing custom genesis block
     INFO [06-11|16:14:42.189] Persisted trie from memory database      nodes=6 size=1.01kB time=80.973µs  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:42.189] Successfully wrote genesis state         database=lightchaindata                                                  hash=b992be…533db7
     $ cd ../node4
     $ geth --datadir data init genesis.json
     INFO [06-11|16:14:48.737] Maximum peer count                       ETH=25 LES=0 total=25
     INFO [06-11|16:14:48.747] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node4/data/geth/chaindata cache=16 handles=16
-    INFO [06-11|16:14:48.749] Writing custom genesis block 
+    INFO [06-11|16:14:48.749] Writing custom genesis block
     INFO [06-11|16:14:48.749] Persisted trie from memory database      nodes=6 size=1.01kB time=71.213µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:48.750] Successfully wrote genesis state         database=chaindata                                                  hash=b992be…533db7
     INFO [06-11|16:14:48.750] Allocated cache and file handles         database=/Users/krish/fromscratchistanbul/node4/data/geth/lightchaindata cache=16 handles=16
-    INFO [06-11|16:14:48.751] Writing custom genesis block 
+    INFO [06-11|16:14:48.751] Writing custom genesis block
     INFO [06-11|16:14:48.751] Persisted trie from memory database      nodes=6 size=1.01kB time=53.773µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
     INFO [06-11|16:14:48.751] Successfully wrote genesis state         database=lightchaindata                                                  hash=b992be…533db7
     $ cd..
@@ -595,17 +595,17 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     #!/bin/bash
     cd node0
     PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30300 2>>node.log &
-    
-    
+
+
     cd ../node1
     PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30301 2>>node.log &
-    
+
     cd ../node2
     PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22002 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30302 2>>node.log &
-     
+
     cd ../node3
     PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22003 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30303 2>>node.log &
-    
+
     cd ../node4
     PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22004 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30304 2>>node.log &
     $
@@ -626,15 +626,15 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     36434 ttys002    0:00.19 geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22002 --rpcapi admin,
     36435 ttys002    0:00.19 geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22003 --rpcapi admin,
     36436 ttys002    0:00.19 geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22004 --rpcapi admin,
-    $ 
+    $
     ```
-    
+
     !!! note
         This configuration starts GoQuorum without privacy support as could be evidenced in prefix `PRIVATE_CONFIG=ignore`, please see below sections on [how to enable privacy with privacy transaction managers](#adding-privacy-transaction-manager).
         Please note that istanbul-tools may be used to generate X number of nodes, more information is available in the [docs](https://github.com/ConsenSys/istanbul-tools).
 
-    Your node is now operational and you may attach to it with `geth attach node0/data/geth.ipc`. 
-    
+    Your node is now operational and you may attach to it with `geth attach node0/data/geth.ipc`.
+
 ### Adding additional validator
 1. Create a working directory for the new node that needs to be added
     ```
@@ -650,9 +650,9 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
     	"Nodekey": "25b47a49ef08f888c04f30417363e6c6bc33e739147b2f8b5377b3168f9f7435",
     	"NodeInfo": "enode://273eaf48591ce0e77c800b3e6465811d6d2f924c4dcaae016c2c7375256d17876c3e05f91839b741fe12350da0b5a741da4e30f39553fe8790f88503c64f6ef9@0.0.0.0:30303?discport=0"
     }
-    
-    
-    
+
+
+
     genesis.json
     {
         "config": {
@@ -685,20 +685,20 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co
         "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
     }
     ```
-    
+
 3. Copy the address of the validator and run `istanbul.propose(
, true)` from more than half the number of current validators. ``` $ cd .. $ geth attach node0/data/geth.ipc $ geth attach node0/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0x4c1ccd426833b9782729a212c857f2f03b7b4c0d at block: 137 (Tue, 11 Jun 2019 16:32:47 BST) datadir: /Users/krish/fromscratchistanbul/node0/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 - + > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",true) @@ -707,47 +707,47 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ $ geth attach node1/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0x189d23d201b03ae1cf9113672df29a5d672aefa3 at block: 176 (Tue, 11 Jun 2019 16:36:02 BST) datadir: /Users/krish/fromscratchistanbul/node1/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 - + > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",true) null $ $ $ geth attach node2/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6 at block: 179 (Tue, 11 Jun 2019 16:36:17 BST) datadir: /Users/krish/fromscratchistanbul/node2/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 - + > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",true) null $ $ $ geth attach node3/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0xc1056df7c02b6f1a353052eaf0533cc7cb743b52 at block: 181 (Tue, 11 Jun 2019 16:36:27 BST) datadir: /Users/krish/fromscratchistanbul/node3/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 - + > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",true) ``` - + 4. Verify that the new validator has been added to the list of validators by running `istanbul.getValidators()` ``` ... you can see below command now displays 6 node address as validators. > istanbul.getValidators() - ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] + ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` 5. Copy `static-nodes.json` and genesis.json from the existing chain. `static-nodes.json` should be placed into new nodes data dir ``` @@ -779,8 +779,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ geth --datadir data account new INFO [06-12|17:45:11.116] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. - Passphrase: - Repeat passphrase: + Passphrase: + Repeat passphrase: Address: {37922bce824bca2f3206ea53dd50d173b368b572} ``` 9. Initialize new node with below command @@ -788,15 +788,15 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ geth --datadir data init genesis.json INFO [06-11|16:42:27.120] Maximum peer count ETH=25 LES=0 total=25 INFO [06-11|16:42:27.130] Allocated cache and file handles database=/Users/krish/fromscratchistanbul/node5/data/geth/chaindata cache=16 handles=16 - INFO [06-11|16:42:27.138] Writing custom genesis block + INFO [06-11|16:42:27.138] Writing custom genesis block INFO [06-11|16:42:27.138] Persisted trie from memory database nodes=6 size=1.01kB time=163.024µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-11|16:42:27.139] Successfully wrote genesis state database=chaindata hash=b992be…533db7 INFO [06-11|16:42:27.139] Allocated cache and file handles database=/Users/krish/fromscratchistanbul/node5/data/geth/lightchaindata cache=16 handles=16 - INFO [06-11|16:42:27.141] Writing custom genesis block + INFO [06-11|16:42:27.141] Writing custom genesis block INFO [06-11|16:42:27.142] Persisted trie from memory database nodes=6 size=1.01kB time=94.57µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-11|16:42:27.142] Successfully wrote genesis state database=lightchaindata hash=b992be…533db7 $ - + ``` 10. Start the node by first creating below script and executing it: ``` @@ -808,7 +808,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co cd node5 PRIVATE_CONFIG=ignore nohup geth --datadir data --nodiscover --istanbul.blockperiod 5 --syncmode full --mine --minerthreads 1 --verbosity 5 --networkid 10 --rpc --rpcaddr 0.0.0.0 --rpcport 22005 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul --emitcheckpoints --port 30305 2>>node.log & $ - $ ./start6.sh + $ ./start6.sh $ $ ps PID TTY TIME CMD @@ -830,7 +830,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` $ geth attach node0/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0xc1056df7c02b6f1a353052eaf0533cc7cb743b52 at block: 181 (Tue, 11 Jun 2019 16:36:27 BST) @@ -846,7 +846,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ $ geth attach node1/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0xc1056df7c02b6f1a353052eaf0533cc7cb743b52 at block: 181 (Tue, 11 Jun 2019 16:36:27 BST) @@ -857,25 +857,25 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ $ geth attach node2/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0xc1056df7c02b6f1a353052eaf0533cc7cb743b52 at block: 181 (Tue, 11 Jun 2019 16:36:27 BST) datadir: /Users/krish/fromscratchistanbul/node2/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) - null + null $ $ geth attach node3/data/geth.ipc Welcome to the Geth JavaScript console! - + instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 coinbase: 0xc1056df7c02b6f1a353052eaf0533cc7cb743b52 at block: 181 (Tue, 11 Jun 2019 16:36:27 BST) datadir: /Users/krish/fromscratchistanbul/node3/data modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) - null + null ``` 3. Verify that the validator has been removed by running `istanbul.getValidators()` ``` @@ -922,7 +922,7 @@ Just execute **step 4** instruction from removing a validator node. $ cd .. .... copy tessera jar to your desired destination and rename it as tessera $ mv tessera-app-0.9.2-app.jar tessera.jar - + ``` 2. Generate new keys using `java -jar /path-to-tessera/tessera.jar -keygen -filename new-node-1` ``` @@ -930,9 +930,9 @@ Just execute **step 4** instruction from removing a validator node. $ cd new-node-1t $ java -jar ../tessera.jar -keygen -filename new-node-1 Enter a password if you want to lock the private key or leave blank - + Please re-enter the password (or lack of) to confirm - + 10:32:51.256 [main] INFO com.quorum.tessera.nacl.jnacl.Jnacl - Generating new keypair... 10:32:51.279 [main] INFO com.quorum.tessera.nacl.jnacl.Jnacl - Generated public key PublicKey[pnesVeDgs805ZPbnulzC5wokDzpdN7CeYKVUBXup/W4=] and private key REDACTED 10:32:51.624 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved public key to /Users/krish/fromscratch/new-node-1t/new-node-1.pub @@ -992,7 +992,7 @@ Just execute **step 4** instruction from removing a validator node. "alwaysSendTo": [] } ``` - + 4. If you want to start another Tessera node, please repeat step 2 & step 3 ``` $ cd .. @@ -1000,9 +1000,9 @@ Just execute **step 4** instruction from removing a validator node. $ cd new-node-2t $ java -jar ../tessera.jar -keygen -filename new-node-2 Enter a password if you want to lock the private key or leave blank - + Please re-enter the password (or lack of) to confirm - + 10:45:02.567 [main] INFO com.quorum.tessera.nacl.jnacl.Jnacl - Generating new keypair... 10:45:02.585 [main] INFO com.quorum.tessera.nacl.jnacl.Jnacl - Generated public key PublicKey[AeggpVlVsi+rxD6h9tcq/8qL/MsjyipUnkj1nvNPgTU=] and private key REDACTED 10:45:02.926 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved public key to /Users/krish/fromscratch/new-node-2t/new-node-2.pub @@ -1061,7 +1061,7 @@ Just execute **step 4** instruction from removing a validator node. }, "alwaysSendTo": [] } - + ``` 5. Start your Tessera nodes and send then into background ``` @@ -1103,25 +1103,25 @@ Just execute **step 4** instruction from removing a validator node. 38076 ttys002 0:47.60 /usr/bin/java -jar ../tessera.jar -configfile config.json 38183 ttys002 0:08.15 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpoo 38204 ttys002 0:00.19 geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debu - 36455 ttys003 0:00.15 -bash + 36455 ttys003 0:00.15 -bash ``` !!! note Tessera IPC bridge will be over a file name defined in your `config.json`, usually named `tm.ipc` as evidenced in prefix `PRIVATE_CONFIG=tm.ipc`. Your node is now able to send and receive private transactions, advertised public node key will be in the `new-node-1.pub` file. Tessera offers a lot of configuration flexibility, please refer [Configuration](../../Privacy/Tessera/Configuration/Configuration%20Overview) section under Tessera for complete and up to date configuration options. - - Your node is now operational and you may attach to it with `geth attach new-node-1/geth.ipc` to send private transactions. + + Your node is now operational and you may attach to it with `geth attach new-node-1/geth.ipc` to send private transactions. ``` $ vim private-contract.js ... create simple private contract to send transaction from new-node-1 private for new-node-2's tessera public key created in step 4 a = eth.accounts[0] web3.eth.defaultAccount = a; - + // abi and bytecode generated from simplestorage.sol: // > solcjs --bin --abi simplestorage.sol var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"payable":false,"type":"constructor"}]; - + var bytecode = "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029"; - + var simpleContract = web3.eth.contract(abi); var simple = simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["AeggpVlVsi+rxD6h9tcq/8qL/MsjyipUnkj1nvNPgTU="]}, function(e, contract) { if (e) { @@ -1138,10 +1138,10 @@ Just execute **step 4** instruction from removing a validator node. $ $ ``` - + !!! note Account opened in geth by default are locked, so please unlock account first before sending transaction - + ``` $ $ geth attach new-node-1/geth.ipc @@ -1149,7 +1149,7 @@ Just execute **step 4** instruction from removing a validator node. ["0x23214cd88f46865207fa1d2a69971a37cdbf526a"] > personal.unlockAccount("0x23214cd88f46865207fa1d2a69971a37cdbf526a"); Unlock account 0x23214cd88f46865207fa1d2a69971a37cdbf526a - Passphrase: + Passphrase: true > loadScript("private-contract.js") Contract transaction send: TransactionHash: 0x7d3bf7612ef10c71f752e881648b7c8c4eee3223acab151ee0652447790836a6 waiting to be mined... @@ -1158,13 +1158,13 @@ Just execute **step 4** instruction from removing a validator node. ``` You have **successfully** sent a private transaction from node 1 to node 2 !! - + !!! note if you do not have an valid public key in the array in private-contract.js, you will see the following error when the script in loaded. ``` > loadScript("private-contract.js") err creating contract Error: Non-200 status code: &{Status:400 Bad Request StatusCode:400 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Date:[Mon, 17 Jun 2019 15:23:53 GMT] Content-Type:[text/plain] Content-Length:[73] Server:[Jetty(9.4.z-SNAPSHOT)]] Body:0xc01997a580 ContentLength:73 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc019788200 TLS:} - ``` + ``` ## Enabling permissioned configuration diff --git a/docs/Tutorials/permissioned-nodes.md b/docs/Tutorials/permissioned-nodes.md index 7f607d1e..5f6fe87e 100644 --- a/docs/Tutorials/permissioned-nodes.md +++ b/docs/Tutorials/permissioned-nodes.md @@ -1,4 +1,4 @@ -``` +``` [ "enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@127.0.0.1:21000?discport=0&raftport=50401", "enode://0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416@127.0.0.1:21001?discport=0&raftport=50402", diff --git a/docs/index.md b/docs/index.md index 1cbd8a94..325d0134 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,16 +1,16 @@ --- -description: Overview of GoQuorum +description: Overview of GoQuorum --- # GoQuorum Enterprise Ethereum Client ## What is GoQuorum? -GoQuorum is an open-source Ethereum client developed under the LGPL license and written in Go. GoQuorum -is an Ethereum-based protocol that runs private, permissioned networks. GoQuorum implements Proof of -Authority (Raft, IBFT, and Clique) consensus mechanisms. +GoQuorum is an open-source Ethereum client developed under the LGPL license and written in Go. GoQuorum +is an Ethereum-based protocol that runs private, permissioned networks. GoQuorum implements Proof of +Authority (Raft, IBFT, and Clique) consensus mechanisms. -## Is GoQuorum part of ConsenSys Quorum? +## Is GoQuorum part of ConsenSys Quorum? Yes. [ConsenSys Quorum](https://consensys.net/quorum/developers) is the complete open source blockchain layer with enterprise support available from ConsenSys. @@ -18,9 +18,9 @@ layer with enterprise support available from ConsenSys. ## What can you do with GoQuorum? You can use GoQuorum to develop enterprise applications requiring secure, high-peformance transaction -processing in a private network. +processing in a private network. -## What does GoQuorum support? +## What does GoQuorum support? GoQuorum supports common smart contract and Dapp development, deployment, and operational use cases, using tools such as [Truffle](http://truffleframework.com/), From bec982dacb5de2fb729d1fbeb24f4b132c12fa5f Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Mon, 21 Sep 2020 18:45:01 +0200 Subject: [PATCH 3/9] fixing MD --- docs/Concepts/Architecture.md | 20 +- docs/Concepts/Consensus/IBFT.md | 31 +- docs/Concepts/Consensus/Raft.md | 54 +- .../Permissioning/BasicNetworkPermissions.md | 2 + .../Permissioning/Enhanced/ContractDesign.md | 39 +- .../Enhanced/EnhancedPermissionsOverview.md | 2 +- docs/Concepts/Plugins/Plugins.md | 64 +- docs/Concepts/Privacy/ContractExtension.md | 25 +- docs/Concepts/Privacy/Privacy.md | 5 +- docs/Concepts/Privacy/PrivateAndPublic.md | 13 +- .../Privacy/PrivateTransactionManager.md | 2 +- docs/Concepts/Profiling.md | 14 +- .../FrontendComponents.md | 2 +- .../SmartContractsSecurity.md | 154 ++- .../GoQuorumNetworkSecurity/Consortium.md | 45 +- .../Framework/GoQuorumNetworkSecurity/Node.md | 90 +- .../OpertionalConsiderations.md | 33 +- .../TransactionManager.md | 58 +- docs/Concepts/Security/Framework/Overview.md | 31 +- docs/HowTo/Configure/BasicPermissions.md | 8 +- docs/HowTo/Configure/EnhancedPermissions.md | 141 ++- docs/HowTo/Configure/GenesisOptions.md | 4 +- docs/HowTo/Configure/HighAvailability.md | 22 +- docs/HowTo/Configure/dns.md | 5 +- docs/HowTo/DevelopPlugins.md | 33 +- docs/HowTo/GetStarted/Cakeshop.md | 125 +- .../GetStarted/GettingStartedOverview.md | 5 +- docs/HowTo/GetStarted/Install.md | 8 +- .../HowTo/GetStarted/Wizard/GettingStarted.md | 33 +- docs/HowTo/GetStarted/Wizard/Interacting.md | 94 +- docs/HowTo/GetStarted/migration.md | 103 +- docs/HowTo/Logging and Errors.md | 2 +- docs/HowTo/ManageKeys/AccountPlugins.md | 22 +- docs/HowTo/ManageKeys/clef.md | 51 +- docs/HowTo/Use/AddingIBFTValidators.md | 58 +- docs/HowTo/Use/DevelopingSmartContracts.md | 2 +- docs/HowTo/Use/EnhancedPermissions.md | 978 ++++++++------- docs/HowTo/Use/JSON-RPC-API-Security.md | 11 +- docs/HowTo/Use/add_node_examples.md | 649 +++++++--- docs/HowTo/Use/adding_nodes.md | 119 +- docs/HowTo/Use/graphql.md | 23 +- docs/HowTo/Use/import-export.md | 47 +- docs/Reference/APIs/PermissioningAPIs.md | 1116 +++++++++-------- docs/Reference/APIs/PrivacyAPI.md | 488 +++---- docs/Reference/Consensus/IBFT-RPC-API.md | 2 +- docs/Reference/FAQ.md | 4 +- docs/Reference/RemixPlugin/GettingStarted.md | 16 +- docs/Tutorials/CreatePermissionedNetwork.md | 2 +- .../Creating-A-Network-From-Scratch.md | 246 ++-- 49 files changed, 2939 insertions(+), 2162 deletions(-) diff --git a/docs/Concepts/Architecture.md b/docs/Concepts/Architecture.md index 44486e5b..3e4739b1 100644 --- a/docs/Concepts/Architecture.md +++ b/docs/Concepts/Architecture.md @@ -4,7 +4,7 @@ description: Overview of GoQuorum Architecture # Architecture -![](../images/Quorum%20Design.png) +![GoQuorum Architecture diagram](../images/Quorum%20Design.png) ## Differences from geth @@ -13,12 +13,12 @@ GoQuorum is updated as geth releases occur. GoQuorum includes the following modifications to geth: - * Consensus is achieved with the Raft or Istanbul BFT consensus algorithms instead of Proof-of-Work. - * The P2P layer is modified to only allow connections between permissioned nodes. - * The block generation logic is modified to replace the `global state root` check with a `global public state root` check. - * The block validation logic is modified to replace the ‘global state root’ in the block header with the ‘global public state root’ - * The State Patricia trie has been split into two: a public state trie and a private state trie. - * Block validation logic is modified to handle private transactions. - * Transaction creation is modified to allow for transaction data to be replaced by encrypted hashes - to preserve private data where required. - * The pricing of gas is removed. Gas itself remains. +* Consensus is achieved with the Raft or Istanbul BFT consensus algorithms instead of Proof-of-Work. +* The P2P layer is modified to only allow connections between permissioned nodes. +* The block generation logic is modified to replace the `global state root` check with a `global public state root` check. +* The block validation logic is modified to replace the ‘global state root’ in the block header with the ‘global public state root’ +* The State Patricia trie has been split into two: a public state trie and a private state trie. +* Block validation logic is modified to handle private transactions. +* Transaction creation is modified to allow for transaction data to be replaced by encrypted hashes + to preserve private data where required. +* The pricing of gas is removed. Gas itself remains. diff --git a/docs/Concepts/Consensus/IBFT.md b/docs/Concepts/Consensus/IBFT.md index 545869bf..4b40ca0a 100644 --- a/docs/Concepts/Consensus/IBFT.md +++ b/docs/Concepts/Consensus/IBFT.md @@ -1,8 +1,14 @@ +--- +description: IBFT Consensus Overview +--- + # IBFT Consensus Overview ## Introduction -Istanbul Byzantine Fault Tolerant (IBFT) consensus is inspired by Castro-Liskov 99 [paper](http://pmg.csail.mit.edu/papers/osdi99.pdf). IBFT inherits from the original PBFT by using a 3-phase consensus, `PRE-PREPARE`, `PREPARE` and `COMMIT`. The system can tolerate at most `F` faulty nodes in a `N` validator network, where `N = 3F + 1`. +Istanbul Byzantine Fault Tolerant (IBFT) consensus is inspired by Castro-Liskov 99 [paper](http://pmg.csail.mit.edu/papers/osdi99.pdf). + +IBFT inherits from the original PBFT by using a 3-phase consensus, `PRE-PREPARE`, `PREPARE` and `COMMIT`. The system can tolerate at most `F` faulty nodes in a `N` validator network, where `N = 3F + 1`. ## Implementation @@ -19,11 +25,13 @@ Istanbul Byzantine Fault Tolerant (IBFT) consensus is inspired by Castro-Liskov - `Snapshot`: The validator voting state from last epoch. ### Consensus + Istanbul BFT Consensus protocol begins at Round `0` with the validators picking a proposer from themselves in a round robin fashion. The proposer will then propose a new block proposal and broadcast it along with the `PRE-PREPARE` message. Upon receiving the `PRE-PREPARE` message from the proposer, other validators validate the incoming proposal and enter the state of `PRE-PREPARED` and broadcast `PREPARE` message. This step is to make sure all validators are working on the same sequence and on the same round. When `ceil(2N/3)` of `PREPARE` messages is received by the validator from other validators, the validator switches to the state of `PREPARED` and broadcasts `COMMIT` message. This step is to inform other validators that it accepts the proposed block and is going to insert the block to the chain. Lastly, validators wait for `ceil(2N/3)` of `COMMIT` messages to enter `COMMITTED` state and then append the block to the chain. Blocks in Istanbul BFT protocol are final, which means that there are no forks and any valid block must be somewhere in the main chain. To prevent a faulty node from generating a totally different chain from the main chain, each validator appends `ceil(2N/3)` of received `COMMIT` signatures to `extraData` field in the header before inserting it into the chain. Thus all blocks are self-verifiable. However, the dynamic `extraData` would cause an issue on block hash calculation. Since the same block from different validators can have different set of `COMMIT` signatures, the same block can have different block hashes as well. To solve this, we calculate the block hash by excluding the `COMMIT` signatures part. Therefore, we can still keep the block/block hash consistency as well as put the consensus proof in the block header. #### Consensus States + Istanbul BFT is a state machine replication algorithm. Each validator maintains a state machine replica in order to reach block consensus. Various states in IBFT consensus are, - `NEW ROUND`: Proposer to send new block proposal. Validators wait for `PRE-PREPARE` message. @@ -33,7 +41,8 @@ Istanbul BFT is a state machine replication algorithm. Each validator maintains - `FINAL COMMITTED`: A new block is successfully inserted into the blockchain and the validator is ready for the next round. - `ROUND CHANGE`: A validator is waiting for `ceil(2N/3)` of `ROUND CHANGE` messages on the same proposed round number. -**State Transitions**: +##### State Transitions + ![State Transitions](../../images/IBFTStateTransition.png) - `NEW ROUND` -> `PRE-PREPARED`: @@ -99,6 +108,7 @@ For all transactions blocks: In an asynchronous network environment, one may receive future messages which cannot be processed in the current state. For example, a validator can receive `COMMIT` messages on `NEW ROUND`. We call this kind of message a "future message." When a validator receives a future message, it will put the message into its **backlog** and try to process later whenever possible. #### Constants + Istanbul BFT define the following constants - `EPOCH_LENGTH`: Default: 30000 blocks. Number of blocks after which to checkpoint and reset the pending votes. @@ -120,6 +130,7 @@ Istanbul BFT define the following constants - Must be `floor(N / 2) + 1` to enforce majority consensus on a chain. #### Block Header + Istanbul BFT does not add new block header fields. Instead, it follows Clique in repurposing the `ethash` header fields as follows: - `nonce`: Proposer proposal regarding the account defined by the beneficiary field. @@ -131,13 +142,15 @@ Istanbul BFT does not add new block header fields. Instead, it follows Clique in - `timestamp`: Must be at least the parent timestamp + `BLOCK_PERIOD` - `difficulty`: Must be filled with `0x0000000000000001`. - `extraData`: Combined field for signer vanity and RLP encoded Istanbul extra data, where Istanbul extra data contains validator list, proposer seal, and commit seals. Istanbul extra data is defined as follows: - ``` + + ```text type IstanbulExtra struct { - Validators []common.Address //Validator addresses - Seal []byte //Proposer seal 65 bytes + Validators []common.Address //Validator addresses + Seal []byte //Proposer seal 65 bytes CommittedSeal [][]byte //Committed seal, 65 * len(Validators) bytes } ``` + Thus the `extraData` would be in the form of `EXTRA_VANITY | ISTANBUL_EXTRA` where `|` represents a fixed index to separate vanity and Istanbul extra data (not an actual character for separator). - First `EXTRA_VANITY` bytes (fixed) may contain arbitrary proposer vanity data. @@ -147,14 +160,16 @@ Istanbul BFT does not add new block header fields. Instead, it follows Clique in - `CommittedSeal`: The list of commitment signature seals as consensus proof. #### Block hash, proposer seal and committed seals + The Istanbul block hash calculation is different from the `ethash` block hash calculation due to the following reasons: 1. The proposer needs to put proposer's seal in `extraData` to prove the block is signed by the chosen proposer. -2. The validators need to put `ceil(2N/3)` of committed seals as consensus proof in `extraData` to prove the block has gone through consensus. +1. The validators need to put `ceil(2N/3)` of committed seals as consensus proof in `extraData` to prove the block has gone through consensus. The calculation is still similar to the `ethash` block hash calculation, with the exception that we need to deal with `extraData`. We calculate the fields as follows: ##### Proposer seal calculation + By the time of proposer seal calculation, the committed seals are still unknown, so we calculate the seal with those unknowns empty. The calculation is as follows: - `Proposer seal`: `SignECDSA(Keccak256(RLP(Header)), PrivateKey)` @@ -163,12 +178,14 @@ By the time of proposer seal calculation, the committed seals are still unknown, - `extraData`: `vanity | RLP(IstanbulExtra)`, where in the `IstanbulExtra`, `CommittedSeal` and `Seal` are empty arrays. ##### Block hash calculation + While calculating block hash, we need to exclude committed seals since that data is dynamic between different validators. Therefore, we make `CommittedSeal` an empty array while calculating the hash. The calculation is: - `Header`: Same as `ethash` header only with a different `extraData`. - `extraData`: `vanity | RLP(IstanbulExtra)`, where in the `IstanbulExtra`, `CommittedSeal` is an empty array. ##### Consensus proof + Before inserting a block into the blockchain, each validator needs to collect `ceil(2N/3)` of committed seals from other validators to compose a consensus proof. Once it receives enough committed seals, it will fill the `CommittedSeal` in `IstanbulExtra`, recalculate the `extraData`, and then insert the block into the blockchain. **Note** that since committed seals can differ by different sources, we exclude that part while calculating the block hash as in the previous section. Committed seal calculation: @@ -179,6 +196,6 @@ Committed seal is calculated by each of the validators signing the hash along wi - `CONCAT(Hash, COMMIT_MSG_CODE)`: Concatenate block hash and `COMMIT_MSG_CODE` bytes. - `PrivateKey`: Signing validator's private key. - ## Provenance + Istanbul BFT implementation in GoQuorum is based on [EIP 650](https://github.com/ethereum/EIPs/issues/650). It has been updated since the EIP was opened to resolve safety issues by introducing locking. diff --git a/docs/Concepts/Consensus/Raft.md b/docs/Concepts/Consensus/Raft.md index ffc65519..7958fd6c 100644 --- a/docs/Concepts/Consensus/Raft.md +++ b/docs/Concepts/Consensus/Raft.md @@ -1,3 +1,7 @@ +--- +description: Raft Consensus Overview +--- + # Raft Consensus Overview ## Introduction @@ -16,12 +20,14 @@ Both Raft and Ethereum have their own notion of a "node": In Raft, a node in normal operation can be a "leader", "follower" or "learner." There is a single leader for the entire cluster, through which all log entries must flow through. There's also the concept of a "candidate", but only during leader election. We won't go into more detail about Raft here, because by design these details are opaque to applications built on it. A Raft network can be started with a set of verifiers and one of them would get elected as a leader when the network starts. If the leader node dies, re-election is triggered and new leader is elected by the network. Once the network is up additional verifier nodes(peers) or learner nodes can be added to this network. Brief summary of each type of nodes is given below: ### Leader + - mints blocks and sends the blocks to the verifier and learner nodes - takes part in voting during re-election and can become verifier if it does not win majority of votes - the network triggers re-election if the leader node dies. - can add/remove learner/verifier and promote learner to verifier ### Verifier + - follows the leader - applies the blocks minted by the leader - takes part in voting during re-election and can become leader if it wins majority of votes @@ -29,6 +35,7 @@ In Raft, a node in normal operation can be a "leader", "follower" or "learner." - can add/remove learner/verifier and promote learner to verifier ### Learner + - follows the leader - applies the blocks minted by the leader - cannot take part in voting during re-election @@ -60,34 +67,33 @@ When the minter creates a block, unlike in vanilla Ethereum where the block is w From the point of view of Ethereum, Raft is integrated via an implementation of the [`Service`](https://godoc.org/github.com/jpmorganchase/quorum/node#Service) interface in [`node/service.go`](https://github.com/jpmorganchase/quorum/blob/master/node/service.go): "an individual protocol that can be registered into a node". Another example of a service is [`Ethereum`](https://godoc.org/github.com/jpmorganchase/quorum/eth#Ethereum). - ## The lifecycle of a transaction Let's follow the lifecycle of a typical transaction: -#### on any node (whether minter, verifier or learner): +### on any node (whether minter, verifier or learner) 1. The transaction is submitted via an RPC call to geth. -2. Using the existing (p2p) transaction propagation mechanism in Ethereum, the transaction is announced to all peers and, because our cluster is currently configured to use "static nodes," every transaction is sent to all peers in the cluster. +1. Using the existing (p2p) transaction propagation mechanism in Ethereum, the transaction is announced to all peers and, because our cluster is currently configured to use "static nodes," every transaction is sent to all peers in the cluster. -#### on the minter: +### on the minter -3. It reaches the minter, where it's included in the next block (see `mintNewBlock`) via the transaction pool. -4. Block creation triggers a [`NewMinedBlockEvent`](https://godoc.org/github.com/jpmorganchase/quorum/core#NewMinedBlockEvent), which the Raft protocol manager receives via its subscription `minedBlockSub`. The `minedBroadcastLoop` (in `raft/handler.go`) puts this new block to the `ProtocolManager.blockProposalC` channel. -5. `serveLocalProposals` is waiting at the other end of the channel. Its job is to RLP-encode blocks and propose them to Raft. Once it flows through Raft, this block will likely become the new head of the blockchain (on all nodes.) +1. It reaches the minter, where it's included in the next block (see `mintNewBlock`) via the transaction pool. +1. Block creation triggers a [`NewMinedBlockEvent`](https://godoc.org/github.com/jpmorganchase/quorum/core#NewMinedBlockEvent), which the Raft protocol manager receives via its subscription `minedBlockSub`. The `minedBroadcastLoop` (in `raft/handler.go`) puts this new block to the `ProtocolManager.blockProposalC` channel. +1. `serveLocalProposals` is waiting at the other end of the channel. Its job is to RLP-encode blocks and propose them to Raft. Once it flows through Raft, this block will likely become the new head of the blockchain (on all nodes.) -#### on every node: +### on every node -6. _At this point, Raft comes to consensus and appends the log entry containing our block to the Raft log. (The way this happens at the Raft layer is that the leader sends an `AppendEntries` to all followers, and they acknowledge receipt of the message. Once the leader has received a quorum of such acknowledgements, it notifies each node that this new entry has been committed permanently to the log)._ +1. _At this point, Raft comes to consensus and appends the log entry containing our block to the Raft log. (The way this happens at the Raft layer is that the leader sends an `AppendEntries` to all followers, and they acknowledge receipt of the message. Once the leader has received a quorum of such acknowledgements, it notifies each node that this new entry has been committed permanently to the log)._ -7. Having crossed the network through Raft, the block reaches the `eventLoop` (which processes new Raft log entries.) It has arrived from the leader through `pm.transport`, an instance of `rafthttp.Transport`. +1. Having crossed the network through Raft, the block reaches the `eventLoop` (which processes new Raft log entries.) It has arrived from the leader through `pm.transport`, an instance of `rafthttp.Transport`. -8. The block is now handled by `applyNewChainHead`. This method checks whether the block extends the chain (i.e. it's parent is the current head of the chain; see below). If it does not extend the chain, it is simply ignored as a no-op. If it does extend chain, the block is validated and then written as the new head of the chain by [`InsertChain`](https://godoc.org/github.com/jpmorganchase/quorum/core#BlockChain.InsertChain). +1. The block is now handled by `applyNewChainHead`. This method checks whether the block extends the chain (i.e. it's parent is the current head of the chain; see below). If it does not extend the chain, it is simply ignored as a no-op. If it does extend chain, the block is validated and then written as the new head of the chain by [`InsertChain`](https://godoc.org/github.com/jpmorganchase/quorum/core#BlockChain.InsertChain). -9. A [`ChainHeadEvent`](https://godoc.org/github.com/jpmorganchase/quorum/core#ChainHeadEvent) is posted to notify listeners that a new block has been accepted. This is relevant to us because: - * It removes the relevant transaction from the transaction pool. - * It removes the relevant transaction from `speculativeChain`'s `proposedTxes` (see below). - * It triggers `requestMinting` in (`minter.go`), telling the node to schedule the minting of a new block if any more transactions are pending. +1. A [`ChainHeadEvent`](https://godoc.org/github.com/jpmorganchase/quorum/core#ChainHeadEvent) is posted to notify listeners that a new block has been accepted. This is relevant to us because: + - It removes the relevant transaction from the transaction pool. + - It removes the relevant transaction from `speculativeChain`'s `proposedTxes` (see below). + - It triggers `requestMinting` in (`minter.go`), telling the node to schedule the minting of a new block if any more transactions are pending. The transaction is now available on all nodes in the cluster with complete finality. Because Raft guarantees a single ordering of entries stored in its log, and because everything that is committed is guaranteed to remain so, there is no forking of the blockchain built upon Raft. @@ -105,7 +111,7 @@ Consider the following example where this might occur, where Raft entries attemp Where `0xbeda` is the ID of new block, and `0xacaa` is the ID of its parent. Here, the initial minter (node 1) is partitioned, and node 2 takes over as the minter. -``` +```text time block submissions node 1 node 2 | [ 0xbeda Parent: 0xacaa ] @@ -122,7 +128,7 @@ Where `0xbeda` is the ID of new block, and `0xacaa` is the ID of its parent. Her Once the partition heals, at the Raft layer node1 will resubmit `0x2c52`, and the resulting serialized log might look as follows: -``` +```text [ 0xbeda Parent: 0xacaa - Extends! ] (due to node 1) [ 0xf0ec Parent: 0xbeda - Extends! ] (due to node 2; let's call this the "winner") [ 0x839c Parent: 0xf0ec - Extends! ] (due to node 2) @@ -160,13 +166,13 @@ There is currently no limit to the length of these speculative chains, but we pl ### State in a speculative chain -* `head`: The last-created speculative block. This can be `nil` if the last-created block is already included in the blockchain. -* `proposedTxes`: The set of transactions which have been proposed to Raft in some block, but not yet included in the blockchain. -* `unappliedBlocks`: A queue of blocks which have been proposed to Raft but not yet committed to the blockchain. +- `head`: The last-created speculative block. This can be `nil` if the last-created block is already included in the blockchain. +- `proposedTxes`: The set of transactions which have been proposed to Raft in some block, but not yet included in the blockchain. +- `unappliedBlocks`: A queue of blocks which have been proposed to Raft but not yet committed to the blockchain. - When minting a new block, we enqueue it at the end of this queue - `accept` is called to remove the oldest speculative block when it's accepted into the blockchain. - When an [`InvalidRaftOrdering`](https://godoc.org/github.com/jpmorganchase/quorum/raft#InvalidRaftOrdering) occurs, we unwind the queue by popping the most recent blocks from the "new end" of the queue until we find the invalid block. We must repeatedly remove these "newer" speculative blocks because they are all dependent on a block that we know has not been included in the blockchain. -* `expectedInvalidBlockHashes`: The set of blocks which build on an invalid block, but haven't passsed through Raft yet. We remove these as we get them back. When these non-extending blocks come back through Raft we remove them from the speculative chain. We use this set as a "guard" against trying to trim the speculative chain when we shouldn't. +- `expectedInvalidBlockHashes`: The set of blocks which build on an invalid block, but haven't passsed through Raft yet. We remove these as we get them back. When these non-extending blocks come back through Raft we remove them from the speculative chain. We use this set as a "guard" against trying to trim the speculative chain when we shouldn't. ## The Raft transport layer @@ -182,9 +188,9 @@ Currently Raft-based consensus requires that all _initial_ nodes in the cluster To remove a node from the cluster, attach to a JS console and issue `raft.removePeer(raftId)`, where `raftId` is the number of the node you wish to remove. For initial nodes in the cluster, this number is the 1-indexed position of the node's enode ID in the static peers list. Once a node has been removed from the cluster, it is permanent; this raft ID can not ever re-connect to the cluster in the future, and the party must re-join the cluster with a new raft ID. -* To add a verifier node to the cluster, attach to a JS console and issue `raft.addPeer(enodeId)` -* To add a learner node to the cluster, attach to a JS console and issue `raft.addLearner(enodeId)` -* To promote a learner to become verifier in the cluster, attach to a JS console of leader/verifier node and issue `raft.promoteToPeer(raftId)`. +- To add a verifier node to the cluster, attach to a JS console and issue `raft.addPeer(enodeId)` +- To add a learner node to the cluster, attach to a JS console and issue `raft.addLearner(enodeId)` +- To promote a learner to become verifier in the cluster, attach to a JS console of leader/verifier node and issue `raft.promoteToPeer(raftId)`. Note that like the enode IDs listed in the static peers JSON file, this enode ID should include a `raftport` querystring parameter. This call will allocate and return a raft ID that was not already in use. After `addPeer`, start the new geth node with the flag `--raftjoinexisting RAFTID` in addition to `--raft`. diff --git a/docs/Concepts/Permissioning/BasicNetworkPermissions.md b/docs/Concepts/Permissioning/BasicNetworkPermissions.md index ef8f1f7e..dfaeb15f 100644 --- a/docs/Concepts/Permissioning/BasicNetworkPermissions.md +++ b/docs/Concepts/Permissioning/BasicNetworkPermissions.md @@ -12,6 +12,7 @@ file then this node can neither connect to any node nor accept any incoming conn The `permissioned-nodes.json` file follows the below pattern, which is similar to the `/static-nodes.json` file that is used to specify the list of static nodes a given node always connects to: + ``` json [ "enode://remoteky1@ip1:port1", @@ -21,6 +22,7 @@ file that is used to specify the list of static nodes a given node always connec ``` Sample file: (node id truncated for clarity) + ``` json [ "enode://6598638ac5b15ee386210156a43f565fa8c485924894e2f3a967207c047470@127.0.0.1:30300", diff --git a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md index 9da0b047..7e8938ae 100644 --- a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md +++ b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md @@ -7,32 +7,33 @@ The permissions smart contract design follows the Proxy-Implementation-Storage p the implementation logic to change without changing the storage or interface layer. A brief description of the smart contracts is below: * `PermissionsUpgradable.sol`: This contract stores the address of current implementation contract and -is owned by a guardian (an Ethereum account). Only the guardian is allowed to change the implementation contract address. + is owned by a guardian (an Ethereum account). Only the guardian is allowed to change the implementation contract address. * `PermissionsInterface.sol`: This is the interface contract and holds the interfaces for permissions -related actions. It has no business logic and forwards requests to the current implementation contract + related actions. It has no business logic and forwards requests to the current implementation contract * `PermissionsImplementation.sol`: This contract has the business logic for the permissions actions. It -can receive requests only from a valid interface as defined in `PermissionsUpgradable.sol` and interacts -with all the storage contracts for respective actions. + can receive requests only from a valid interface as defined in `PermissionsUpgradable.sol` and interacts + with all the storage contracts for respective actions. * `OrgManager.sol`: This contract stores data for organizations and sub organizations. It can receive -requests from a valid implementation contract as defined in `PermissionsUpgradable.sol` + requests from a valid implementation contract as defined in `PermissionsUpgradable.sol` * `AccountManager.sol`: This contract receives requests from a valid implementation contract as defined -in `PermissionsUpgradable.sol`. It stores the data of all accounts, their linkage to organization and various -roles. The contract also stores the status of an account. The account can be in any of the following -status - `PendingApproval`, `Active`, `Suspended`, `Blacklisted` or `Revoked` + in `PermissionsUpgradable.sol`. It stores the data of all accounts, their linkage to organization and various + roles. The contract also stores the status of an account. The account can be in any of the following + status - `PendingApproval`, `Active`, `Suspended`, `Blacklisted` or `Revoked` * `NodeManager.sol`: This contract receives requests from a valid implementation contract as defined -in `PermissionsUpgradable.sol`. It stores the data of a node, its linkage to an organization or sub organization, -and status of the node. The node can be in any one of the following status - `PendingApproval`, `Approved`, `Deactivated` or `Blacklisted` + in `PermissionsUpgradable.sol`. It stores the data of a node, its linkage to an organization or sub organization, + and status of the node. The node can be in any one of the following status - `PendingApproval`, `Approved`, `Deactivated` or `Blacklisted` * `RoleManager.sol`: This contract receives requests from a valid implementation contract as defined in `PermissionsUpgradable.sol`. -It stores data for various roles and the organization to which it is linked. The access at role level can be any one of the following: - - `Readonly` which allows only read operations - - `Transact` which allows value transfer but no contract deployment access - - `ContractDeploy` which allows both value transfer and contract deployment access - - `FullAccess` which allows additional network level accesses in addition to value transfer and contract deployment + It stores data for various roles and the organization to which it is linked. The access at role level can be any one of the following: + + * `Readonly` which allows only read operations + * `Transact` which allows value transfer but no contract deployment access + * `ContractDeploy` which allows both value transfer and contract deployment access + * `FullAccess` which allows additional network level accesses in addition to value transfer and contract deployment If a role is revoked all accounts which are linked to the role lose all access rights * `VoterManager.sol`: This contract receives requests from a valid implementation contract as defined in `PermissionsUpgradable.sol`. -It stores the data of valid voters at network level which can approve identified activities e.g. adding a new organization to the network. -Any account which is linked to a predefined network admin role will be marked as a voter. Whenever a network level activity which requires -voting is performed, a voting item is added to this contract and each voter account can vote for the activity. The activity is marked -as `Approved` upon majority voting. + It stores the data of valid voters at network level which can approve identified activities e.g. adding a new organization to the network. + Any account which is linked to a predefined network admin role will be marked as a voter. Whenever a network level activity which requires + voting is performed, a voting item is added to this contract and each voter account can vote for the activity. The activity is marked + as `Approved` upon majority voting. diff --git a/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md b/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md index ea37c34f..b0ae0746 100644 --- a/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md +++ b/docs/Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md @@ -6,7 +6,7 @@ This allows for significant flexibility to manage nodes, accounts, and account-l An overview of the model is as depicted below: ![permissions mode](../../../images/PermissionsModel.png) -### Key Definitions +## Key Definitions * Network - A set of interconnected nodes representing an enterprise blockchain which contains organizations * Organization - A set of roles, Ethereum accounts and nodes having a variety of permissions to interact with the network diff --git a/docs/Concepts/Plugins/Plugins.md b/docs/Concepts/Plugins/Plugins.md index 295a1cbc..92378282 100644 --- a/docs/Concepts/Plugins/Plugins.md +++ b/docs/Concepts/Plugins/Plugins.md @@ -1,8 +1,13 @@ +--- +description: GoQuorum pluggable architecture +--- + # GoQuorum Plugins -The GoQuorum client is a modified `geth` client. One of the unique enhancements -is the pluggable architecture which allows adding additional features as plugins to the core `geth`, -providing extensibility, flexibility, and isolation of GoQuorum features. +The GoQuorum client is a modified `geth` client. + +One of the unique enhancement is the pluggable architecture which allows adding additional features +as plugins to the core `geth`, providing extensibility, flexibility, and isolation of GoQuorum features. ## Benefits @@ -15,6 +20,7 @@ This enhancement provides a number of benefits, including: ## How it works? Each plugin exposes an implementation for a specific [plugin interface](https://github.com/ConsenSys/quorum-plugin-definitions) (or see `Pluggable Architecture -> Plugins` for more details) + Plugins are executed as a separate process and communicate with the main GoQuorum client `geth` process over a [gRPC](https://grpc.io/) interface. @@ -30,10 +36,10 @@ Currently plugins must be manually installed into a directory (defaults to `plug ## Using Plugins [Plugins settings file](../../HowTo/Configure/Plugins.md) contains a JSON that describes what plugins to be used. -Then start `geth` with `--plugins` as below: +Then start `geth` using the `--plugins` command line option: ```bash -geth ... \ +geth \ --plugins file://///plugins.json ``` @@ -58,30 +64,37 @@ that the plugin can take changes from its JSON configuration. ### Build plugin distribution file 1. Clone plugin repository + ```bash - › git clone --recursive https://github.com/ConsenSys/quorum-plugin-hello-world.git - › cd quorum-plugin-hello-world + git clone --recursive https://github.com/ConsenSys/quorum-plugin-hello-world.git + cd quorum-plugin-hello-world ``` + 1. Here we will use Go implementation of the plugin + ```bash - quorum-plugin-hello-world› cd go - quorum-plugin-hello-world/go› make + cd go + make ``` + `quorum-plugin-hello-world-1.0.0.zip` is now created in `build` directory. Noticed that there's a file `hello-world-plugin-config.json` which is the JSON configuration file for the plugin. ### Start GoQuorum with plugin support 1. Build Quorum + ```bash - › git clone https://github.com/ConsenSys/quorum.git - › cd quorum - quorum› make geth + git clone https://github.com/ConsenSys/quorum.git + cd quorum + make geth ``` + 1. Copy `HelloWorld` plugin distribution file and its JSON configuration `hello-world-plugin-config.json` to `build/bin` 1. Create `geth-plugin-settings.json` - ``` - quorum› cat > build/bin/geth-plugin-settings.json < build/bin/geth-plugin-settings.json < A -> B 2. S -> (A) -> (B) 3. S -> (A) -> [B -> C] @@ -56,12 +56,13 @@ The following transactions are allowed: and the following transaction are unsupported: -``` +```text 1. (S) -> A 2. (S) -> (A) ``` where: + - `S` = sender - `(X)` = private - `X` = public diff --git a/docs/Concepts/Privacy/PrivateAndPublic.md b/docs/Concepts/Privacy/PrivateAndPublic.md index 559567c9..85b23686 100644 --- a/docs/Concepts/Privacy/PrivateAndPublic.md +++ b/docs/Concepts/Privacy/PrivateAndPublic.md @@ -1,14 +1,19 @@ +--- +description: Transaction and Contract Privacy +--- + # Transaction and Contract Privacy GoQuorum achieves Transaction Privacy by: - 1. Enabling transaction Senders to create a private transaction by marking who is privy to that transaction via the `privateFor` parameter - 2. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction - 3. Storing encrypted private data off-chain in a separate component called the [Privacy Manager](PrivateTransactionManager.md). The Privacy Manager encrypts private data, distributes the encrypted data to other parties that are privy to the transaction, and returns the decrypted payload to those parties +1. Enabling transaction Senders to create a private transaction by marking who is privy to that transaction via the `privateFor` parameter +1. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction +1. Storing encrypted private data off-chain in a separate component called the [Privacy Manager](PrivateTransactionManager.md). The Privacy Manager encrypts private data, distributes the encrypted data to other parties that are privy to the transaction, and returns the decrypted payload to those parties GoQuorum introduces the notion of 'Public Transactions' and 'Private Transactions'. Note that this is a notional concept only and GoQuorum does not introduce new Transaction Types, but rather, the Ethereum Transaction Model has been extended to include an optional `privateFor` parameter (the population of which results in a Transaction being treated as private by GoQuorum) and the Transaction Type has a new `IsPrivate` method to identify such Transactions. ## Public Transactions + Public Transactions are those Transactions whose payload is visible to all participants of the same GoQuorum network. These are [created as standard Ethereum Transactions in the usual way](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethsendtransaction). Examples of Public Transactions may include Market Data updates from some service provider, or some reference data update such as a correction to a Bond Security definition. @@ -17,11 +22,13 @@ Examples of Public Transactions may include Market Data updates from some servic GoQuorum Public Transactions are not Transactions from the public Ethereum network. Perhaps a more appropriate term would be 'common' or 'global' Transactions, but 'Public' is used to contrast with 'Private' Transactions. ## Private Transactions + Private Transactions are those Transactions whose payload is only visible to the network participants whose public keys are specified in the `privateFor` parameter of the Transaction . `privateFor` can take multiple addresses in a comma separated list. (See Creating Private Transactions under the [Developing Smart Contracts](../../HowTo/Use/DevelopingSmartContracts.md#creating-private-transactions/contracts) section). When the GoQuorum Node encounters a Transaction with a non-null `privateFor` value, it sets the `V` value of the Transaction Signature to be either `37` or `38` (as opposed to `27` or `28` which are the values used to indicate a Transaction is 'public' as per standard Ethereum as specified in the Ethereum yellow paper). ## Public vs Private Transaction Handling + Public Transactions are executed in the standard Ethereum way, and so if a Public Transaction is sent to an Account that holds Contract code, each participant will execute the same code and their underlying StateDBs will be updated accordingly. Private Transactions, however, are not executed per standard Ethereum: prior to the sender's GoQuorum Node propagating the Transaction to the rest of the network, it replaces the original Transaction Payload with a hash of the encrypted Payload that it receives from Constellation/Tessera. Participants that are party to the Transaction will be able to replace the hash with the actual payload via their Constellation/Tessera instance, whilst those Participants that are not party will only see the hash. diff --git a/docs/Concepts/Privacy/PrivateTransactionManager.md b/docs/Concepts/Privacy/PrivateTransactionManager.md index 9dc8368b..fbd3e180 100644 --- a/docs/Concepts/Privacy/PrivateTransactionManager.md +++ b/docs/Concepts/Privacy/PrivateTransactionManager.md @@ -9,7 +9,7 @@ of encrypted private transaction data between recipients of a private transactio To enable private transactions, use the `PRIVATE_CONFIG` environment variable when starting a GoQuorum node to provide the node with the path to the Privacy Manager's `.ipc` socket, e.g.: -```shell +```bash export PRIVATE_CONFIG=path/to/tm.ipc ``` diff --git a/docs/Concepts/Profiling.md b/docs/Concepts/Profiling.md index 51e5d431..c9bb7150 100644 --- a/docs/Concepts/Profiling.md +++ b/docs/Concepts/Profiling.md @@ -22,17 +22,17 @@ Key Components: The tool executes the stress test profile selected and then collects the following metrics: - * CPU/Memory usage for both `Quorum` & `tessera` - * Transaction & Block count - * Transaction processing speed - * `Jmeter` test execution statistics +- CPU/Memory usage for both `Quorum` & `tessera` +- Transaction & Block count +- Transaction processing speed +- `Jmeter` test execution statistics - These metrics could be configured to be stored in an InfluxDB or Prometheus for further analysis. Both databases integrate well with the open source dashboard editor Grafana to allow for easy creation of dashboards to visualise the data being captured from the profiling tool. Sample dashboards below: +These metrics could be configured to be stored in an InfluxDB or Prometheus for further analysis. Both databases integrate well with the open source dashboard editor Grafana to allow for easy creation of dashboards to visualise the data being captured from the profiling tool. Sample dashboards below: -### Sample Network Dashboard +## Sample Network Dashboard ![Quorum Network Dashboard](../images/quorumDashboard.jpeg) -### Sample JMeter Dashboard +## Sample JMeter Dashboard ![JMeter Dashboard](../images/jmeterDashboard.jpeg) diff --git a/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md b/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md index eb62ff31..635ea4b0 100644 --- a/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md +++ b/docs/Concepts/Security/Framework/DecentralizedApplication/FrontendComponents.md @@ -1,4 +1,4 @@ -## Frontend +# Frontend As any traditional application, dApps Client/Server component has to follow application security best practices. Its recommended to use a Secure Software Development Lifecycle (SSDLC) to implement any application. diff --git a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md index a23e9cdf..e52c0f0e 100644 --- a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md +++ b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md @@ -1,4 +1,10 @@ -**Smart Contracts Security** must be considered as any other application security. It might contain logical vulnerabilities, insecure design, and it might run on vulnerable components (ledgers). However, Smart Contracts are the core element of Ethereum Blockchain. Unlike other software it is constrained by several Blockchain technology primitives: +--- +description: Smart Contracts Security tips and checklist +--- + +# Smart Contracts Security + +Smart Contracts security must be considered as any other application security. It might contain logical vulnerabilities, insecure design, and it might run on vulnerable components (ledgers). However, Smart Contracts are the core element of Ethereum Blockchain. Unlike other software it is constrained by several Blockchain technology primitives: - Smart Contracts runtime is sandboxed; this means obtaining a secure randomness source is hard. - Smart Contracts can hold, transfer or destroy funds, making them an economic risk component. @@ -6,123 +12,153 @@ - Smart Contracts are immutable and have an irrevocable self-destruction feature. - Smart Contracts can have one or multiple owners. -### Ownership +## Ownership + Unlike traditional software management process, Smart Contracts support the following technologically enforced ownership model: -**Single Ownership**: +### Single Ownership + The contract has one owner who is responsible for the contract administration process. -**Shared Custody Ownership**: -Suitable for agreement between two or more parties in a network of N parties; where any party can unilaterally perform administrative action over the contract. +### Shared Custody Ownership + +Suitable for agreement between two or more parties in a network of N parties; +where any party can unilaterally perform administrative action over the contract. + +### Consortium Based Ownership -**Consortium Based Ownership**: It is a form of expanded shared custody ownership that requires consensus over the administrative actions. +## Security Patterns + +### Checks-Effects-Interaction Pattern + +Interacting with other contracts should always be the last step in the contract function. + +It is crucial that the current contract has finished its functionality before handing control to another contract and does not depend on the execution of the other contract. -### Security Patterns: +### Circuit Breaker -**Checks-Effects-Interaction Pattern**: Interacting with other contracts should always be the last step in the contract function. It is crucial that the current contract has finished its functionality before handing control to another contract and does not depend on the execution of the other contract. +It is a logical emergency stop execution logic. Implementing emergency stops in the logic of smart contract is a good security practice. -**Circuit Breaker**: It is a logical emergency stop execution logic. Implementing emergency stops in the logic of smart contract is a good security practice. A Circuit breaker can be triggered manually by trusted parties included in the contract like the contract owner or by using programmatic consensus rules that automatically trigger the circuit breaker when the defined conditions meet. +A Circuit breaker can be triggered manually by trusted parties included in the contract like the contract owner or by using programmatic consensus rules that automatically trigger the circuit breaker when the defined conditions meet. -**Rate Limit**: Smart contract operation within an interval allows better control of abusable resources. +### Rate Limit -**Speed Bumps**: Speed bumps introduce a delay in the action execution allowing time to act if action is considered malicious. +Smart contract operation within an interval allows better control of abusable resources. +### Speed Bumps -### Common Contract Vulnerabilities +Speed bumps introduce a delay in the action execution allowing time to act if action is considered malicious. -**Reentrancy**: Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract, or the use of a low-level function with an external address. +## Common Contract Vulnerabilities -**Access Control**: While insecure visibility settings give attackers straightforward ways to access a contract's private values or logic, access control bypasses are sometimes more subtle. These vulnerabilities can occur when contracts use the deprecated "tx.origin" to validate callers, handle extensive authorization logic with lengthy "require" and make reckless use of "delegatecall" in proxy libraries or proxy contracts. +### Reentrancy -**Arithmetic**: Integer overflows and underflows are not a new class of vulnerability, but they are especially dangerous in smart contracts, where unsigned integers are prevalent, and most developers are used to simple int types (which are often just signed integers). If overflows occur, many seemingly benign code paths become vectors for theft or denial of service. +Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract, or the use of a low-level function with an external address. -**Unchecked Low Level Calls**: One of the more in-depth features of Solidity are the low-level functions such as call(), callcode(), delegatecall() and send(). Their error handling behaviour is quite different from other Solidity functions. The errors will not surface immediately and will not lead to the total reversal of the current execution. Instead, they will return a boolean value set to false, and the code will continue to run. This scenario could surprise developers. If the return value of such low-level calls is not checked, it could lead to "fail open" situations and other unwanted outcomes. +### Access Control -**Bad Randomness**: Randomness is hard to get right in Ethereum. While Solidity offers functions and variables that can access seemingly hard-to-predict values, they are generally either more public than they seem. Because randomness sources are predictable to an extent in Ethereum, malicious users can usually replicate them and attack the function relying on the unpredictability. This also applies to dApps built on top of Quorum. +While insecure visibility settings give attackers straightforward ways to access a contract's private values or logic, access control bypasses are sometimes more subtle. These vulnerabilities can occur when contracts use the deprecated "tx.origin" to validate callers, handle extensive authorization logic with lengthy "require" and make reckless use of "delegatecall" in proxy libraries or proxy contracts. -**Front Running**: In public Ethereum, miners always get rewarded via gas fees for running code on behalf of externally owned addresses (EOA). Users can specify higher fees to have their transactions mined quicker. Since the Ethereum blockchain is public, everyone can see the contents of other user's pending transactions. This situation means that if a given user is revealing the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. If smart contract developers are not careful, this situation can lead to practical and devastating front-running attacks. On the other hand, since Quorum does not use Proof Of Work (PoW) as consensus algorithm and the gas cost is zero, vulnerabilities related to PoW mining are not applicable when building on top of Quorum. However, front-running remains a risk and will depend on the consensus algorithm in use. +### Arithmetic -**Time Manipulation**: From locking a token sale to unlocking funds at a specific time, contracts sometimes need to rely on the current time. This is usually done via "block.timestamp "or it's alias "now" in Solidity. In public Ethereum, this value comes from the miners. However, in Quorum, it comes from the minter or validators. As a result, smart contracts should avoid relying strongly on the block time for critical decision making. Note that block.timestamp should not be used for the generation of random numbers. +Integer overflows and underflows are not a new class of vulnerability, but they are especially dangerous in smart contracts, where unsigned integers are prevalent, and most developers are used to simple int types (which are often just signed integers). If overflows occur, many seemingly benign code paths become vectors for theft or denial of service. -**Short Addresses**: Short address attacks are a side effect of the EVM accepting incorrectly padded arguments. Attackers can exploit this by using specially crafted addresses to make poorly coded clients encode arguments incorrectly before including them in transactions. +### Unchecked Low Level Calls +One of the more in-depth features of Solidity are the low-level functions such as call(), callcode(), delegatecall() and send(). Their error handling behaviour is quite different from other Solidity functions. The errors will not surface immediately and will not lead to the total reversal of the current execution. Instead, they will return a boolean value set to false, and the code will continue to run. This scenario could surprise developers. If the return value of such low-level calls is not checked, it could lead to "fail open" situations and other unwanted outcomes. -### Security Checklist +### Bad Randomness -#### Ownership +Randomness is hard to get right in Ethereum. While Solidity offers functions and variables that can access seemingly hard-to-predict values, they are generally either more public than they seem. Because randomness sources are predictable to an extent in Ethereum, malicious users can usually replicate them and attack the function relying on the unpredictability. This also applies to dApps built on top of Quorum. + +### Front Running + +In public Ethereum, miners always get rewarded via gas fees for running code on behalf of externally owned addresses (EOA). Users can specify higher fees to have their transactions mined quicker. Since the Ethereum blockchain is public, everyone can see the contents of other user's pending transactions. This situation means that if a given user is revealing the solution to a puzzle or other valuable secret, a malicious user can steal the solution and copy their transaction with higher fees to preempt the original solution. If smart contract developers are not careful, this situation can lead to practical and devastating front-running attacks. On the other hand, since Quorum does not use Proof Of Work (PoW) as consensus algorithm and the gas cost is zero, vulnerabilities related to PoW mining are not applicable when building on top of Quorum. However, front-running remains a risk and will depend on the consensus algorithm in use. + +### Time Manipulation + +From locking a token sale to unlocking funds at a specific time, contracts sometimes need to rely on the current time. This is usually done via "block.timestamp "or it's alias "now" in Solidity. In public Ethereum, this value comes from the miners. However, in Quorum, it comes from the minter or validators. As a result, smart contracts should avoid relying strongly on the block time for critical decision making. Note that block.timestamp should not be used for the generation of random numbers. + +### Short Addresses + +Short address attacks are a side effect of the EVM accepting incorrectly padded arguments. Attackers can exploit this by using specially crafted addresses to make poorly coded clients encode arguments incorrectly before including them in transactions. + +## Security Checklist + +### Ownership -!!! success "Smart contracts having no ownership must be prevented in Enterprise Blockchains." +- [X] Smart contracts having no ownership must be prevented in Enterprise Blockchains. -!!! success "Contracts must include initialization phase where all owners are identified clearly and set init(owners_list)." +- [X] Contracts must include initialization phase where all owners are identified clearly and set init(owners_list). -!!! success "Identify contract ownership model before starting the design of the smart contract logic." +- [X] Identify contract ownership model before starting the design of the smart contract logic. -!!! success "Define the consensus model for Consortium Based Ownership." +- [X] Define the consensus model for Consortium Based Ownership. -!!! success "Contract upgradability and ownership functionalities must verify new addresses are valid." +- [X] Contract upgradability and ownership functionalities must verify new addresses are valid. -!!! success "Ownership related events must be broadcasted to all the network participants." +- [X] Ownership related events must be broadcasted to all the network participants. -!!! success "In a Consortium based ownership structure, changing activities that are bound to approval from consortium members before they are committed (e.g. editing Consortium structure) must have approval pending expiration date." +- [X] In a Consortium based ownership structure, changing activities that are bound to approval from consortium members before they are committed (e.g. editing Consortium structure) must have approval pending expiration date. -!!! success "Consortium based voting must involve real-time notification through EVM event emission. " +- [X] Consortium based voting must involve real-time notification through EVM event emission. -#### Contract Implementation +### Contract Implementation -!!! success "Contract should use a locked compiler version." +- [X] Contract should use a locked compiler version. -!!! success "The compiler version should be consistent across all contracts." +- [X] The compiler version should be consistent across all contracts. -!!! success "Contract should not shadow or overwrite built-in functions." +- [X] Contract should not shadow or overwrite built-in functions. -!!! success "Contract should never use tx.origin as an authorization mechanism." +- [X] Contract should never use tx.origin as an authorization mechanism. -!!! success "Contract should never use the timestamp as a source of randomness." +- [X] Contract should never use the timestamp as a source of randomness. -!!! success "Contract should never use block number or hash as a source for randomness." +- [X] Contract should never use block number or hash as a source for randomness. -!!! success "Contract should never use block number or timestamp as critical decision-making conditions." +- [X] Contract should never use block number or timestamp as critical decision-making conditions. -!!! success "Contract should never misuse multiple inheritance." +- [X] Contract should never misuse multiple inheritance. -!!! success "Modifiers must preserve the contract state or performing an external call." +- [X] Modifiers must preserve the contract state or performing an external call. -!!! success "Contract should never contain cross-function race conditions." +- [X] Contract should never contain cross-function race conditions. -!!! success "Contract should never use plain arithmetic computation; instead, safe math should be used." +- [X] Contract should never use plain arithmetic computation; instead, safe math should be used. -!!! success "Contract fallback functions should be free of unknown states that might introduce security implications." +- [X] Contract fallback functions should be free of unknown states that might introduce security implications. -!!! success "Contract should avoid shadowed variables." +- [X] Contract should avoid shadowed variables. -!!! success "Contract public variables/functions should be reviewed to ensure visibility is appropriate." +- [X] Contract public variables/functions should be reviewed to ensure visibility is appropriate. -!!! success "Contract private variables should not contain sensitive data." +- [X] Contract private variables should not contain sensitive data. -!!! success "Contract functions should explicitly declare visibility." +- [X] Contract functions should explicitly declare visibility. -!!! success "Contract public functions should perform proper authorization checks." +- [X] Contract public functions should perform proper authorization checks. -!!! success "Contract should validate the input of all public and external functions." +- [X] Contract should validate the input of all public and external functions. -!!! success "Contract using old solidity version constructor name must match contract name." +- [X] Contract using old solidity version constructor name must match contract name. -!!! success "Contract should explicitly mark untrusted contracts as 'untrusted'." +- [X] Contract should explicitly mark untrusted contracts as 'untrusted'. -!!! success "Contract functions logic should perform state-changing actions before making external calls." +- [X] Contract functions logic should perform state-changing actions before making external calls. -!!! success "Contract logic should use send() and transfer() over call.value when possible." +- [X] Contract logic should use send() and transfer() over call.value when possible. -!!! success "Contract usage of delegatecall should be properly handled." +- [X] Contract usage of delegatecall should be properly handled. -!!! success "Contract logic must correctly handle return value of any external call." +- [X] Contract logic must correctly handle return value of any external call. -!!! success "Contract must never assume it has been created with a balance of 0." +- [X] Contract must never assume it has been created with a balance of 0. -!!! success "Contract logic should not contain loops that are vulnerable to denial of service attacks." +- [X] Contract logic should not contain loops that are vulnerable to denial of service attacks. -!!! success "Multiparty contract logic action should not be dependent on a single party." +- [X] Multiparty contract logic action should not be dependent on a single party. -!!! success "Prevent token transfers to 0x0 address." +- [X] Prevent token transfers to 0x0 address. diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md index 80b7e93e..3c7417fb 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md @@ -1,37 +1,50 @@ +--- +descriptions: +--- + +# Consortium + When creating a Consortium the following elements should be taken in consideration: -### Governance +## Governance + Chosen structure must not only be appropriate to permit efficient and effective operations of the Consortium, but also fulfill the concerns of those that form part of it equally. -### Ownership +## Ownership + The nature of blockchain technology also increases the risk of accidental data exposure. In order to manage this risk ownership of Intellectual Properties (IP), and assets should be documented, and agreed upon. -### Liability +## Liability + Most network operational activities are benign, but this is not true in all cases, and even in otherwise low-risk Consortium, where the membership constitutes “market power” under the antitrust -laws, a significant percentage of the competitors in a given product or service space might be members. The potential -for inadvertent mistakes, as well as the level of potential scrutiny by government regulators, is higher. +laws, a significant percentage of the competitors in a given product or service space might be members. + +The potential for inadvertent mistakes, as well as the level of potential scrutiny by government regulators, is higher. + In such a situation, individual members may wish to maintain tighter control over what can – and more importantly, what cannot – be done by the organization, and its members without proper prior consensus in order to reduce the risk and liability. -### Activities -Interconnecting multiple independent networks comes with risk factors. In order to -build a controls to minimize a risk, the activities that are expected to be performed in the network must be documented. +## Activities + +Interconnecting multiple independent networks comes with risk factors. + +In order to build a controls to minimize a risk, the activities that are expected to be performed in the network must be documented. -### Security Checklist +## Security Checklist -!!! success "Use Byzantine fault tolerant consensus protocol in case nodes are managed by un-trusted participants" +- [x] Use Byzantine fault tolerant consensus protocol in case nodes are managed by un-trusted participants -!!! success "Consortium member should provide a reasonable network Service-Level Agreement (SLA)." +- [x] Consortium member should provide a reasonable network Service-Level Agreement (SLA). -!!! success "Ensure Private/Public payloads data is stored in a appropiate Geographical legislation area. " +- [x] Ensure Private/Public payloads data is stored in a appropiate Geographical legislation area. -!!! success "Document the Consortium Governance Structure, Ownership, Liability, Memberships, Activities. " +- [x] Document the Consortium Governance Structure, Ownership, Liability, Memberships, Activities. -!!! success "Document the Organizational, and technological requirements to join the Consortium. " +- [x] Document the Organizational, and technological requirements to join the Consortium. -!!! success "Ensure Consortium members be known to every participant in the network." +- [x] Ensure Consortium members be known to every participant in the network. -!!! success "Ensure Private/Public paylaod data is compliant with privacy policies. " +- [x] Ensure Private/Public paylaod data is compliant with privacy policies. diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md index 5284349a..08739994 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md @@ -1,64 +1,86 @@ -**GoQuorum Node**, aka GoQuorum Client, is a thick-client whose Private Transaction feature operation depends on a Transaction Manager Client that encrypts and decrypts -private transactions payload. Both Quorum client and its dependencies i.e, Transaction Manager, Peers, and Enclave use traditional TCP/UDP transport layer to communicate. +--- +description: GoQuorum Node +--- + +# GoQuorum Node + +GoQuorum Node, also called GoQuorum Client, is a thick-client whose Private Transaction feature operation depends on a Transaction Manager Client that encrypts and decrypts +private transactions payload. +Both Quorum client and its dependencies i.e, Transaction Manager, Peers, and Enclave use traditional TCP/UDP transport layer to communicate. As any asset in a network its security depends on multiple elements (E.g the security of the Host, Data, and Accounts). In GoQuorum it will be the security of the Client and Transaction Manager host/host-runtime, encryption keys, Consensus runtime and Network Access Controls. -### Host Security -Any asset in a GoQuorum network (Client Host, Transaction Manager Host, Private Transaction Storage Host, ..etc ) must be hardened following industry best practices. A host IDS should be used to detect any malicious activities on the host. Direct access to the host should not be allowed, instead a jump server should be used and access limited to small number of administrators. +## Host Security + +Any asset in a GoQuorum network (Client Host, Transaction Manager Host, Private Transaction Storage Host, ..etc ) must be hardened following industry best practices. + +A host IDS should be used to detect any malicious activities on the host. Direct access to the host should not be allowed, instead a jump server should be used and access limited to small number of administrators. + Operating systems, software and services will have vulnerabilities. GoQuorum network hosts must implement a robust patch management program. -### Client Security -GoQuorum client instance exposes a JSON-Remote Procedure Call (RPC) interface through HTTP, Web Socket, or Inter-Process communication techniques. The JSON-RPC interfaces -allows the remote interaction with the ledger features, and Smart Contracts. The JSON-RPC interface must be secured in order to preserve the integrity of the ledger runtime. +## Client Security + +GoQuorum client instance exposes a JSON-Remote Procedure Call (RPC) interface through HTTP, Web Socket, or Inter-Process communication techniques. + +The JSON-RPC interfaces allows the remote interaction with the ledger features, and Smart Contracts. The JSON-RPC interface must be secured in order to preserve the integrity of the ledger runtime. + +Each client in the network must be uniquely identified. + +In GoQuorum this is done by using nodes identity. Node identity is represented through a public key/private key, where +the public key identifies the node in the network. + +GoQuorum Smart Contract Permissioning models depends on nodes identity to authorize TCP level communication between nodes, as such securing the private key of a node is a paramount activity required to prevent unauthorized node from joining the network. + +## Users Security + +Blockchain technology uses public key cryptography to protect the integrity of transactions and blocks. -Each client in the network must be uniquely identified. In GoQuorum this is done by using nodes identity. Node identity is represented through a public key/private key, where -the public key identifies the node in the network. GoQuorum Smart Contract Permissioning models depends on nodes identity to authorize TCP level communication between nodes, as such securing -the private key of a node is a paramount activity required to prevent unauthorized node from joining the network. +The security of a user’s Private keys is dependent on the security operation elements implemented to +preserve the Private key from compromise. +In Ethereum Accounts Private keys are encrypted with user specified seed (password). -### Users Security -Blockchain technology uses public key cryptography to protect the integrity of transactions and blocks. The security of a user’s Private keys is dependent on the security operation elements implemented to -preserve the Private key from compromise. In Ethereum Accounts Private keys are encrypted with user specified seed (password). Users password should never be saved across the ecosystem or stored in ledger host in any form. +Users password should never be saved across the ecosystem or stored in ledger host in any form. -### Security Checklist +## Security Checklist -#### Host +### Host -!!! success "Harden GoQuorum Host Operating System (e.g remove irrelevant services, root access...etc)." +- [x] Harden GoQuorum Host Operating System (e.g remove irrelevant services, root access...etc). -!!! success "Disable direct remote network access to GoQuorum host management interface in production." +- [x] Disable direct remote network access to GoQuorum host management interface in production. -!!! success "Use Host Based Intrusion Detection System (HIDS) to monitoring GoQuorum node host." +- [x] Use Host Based Intrusion Detection System (HIDS) to monitoring GoQuorum node host. -!!! success "Enable Host Based Firewall Rules that enforces network access to JSON-RPC interface to only a preidentified, trusted and required systems." +- [x] Enable Host Based Firewall Rules that enforces network access to JSON-RPC interface to only a preidentified, trusted and required systems. -!!! success "Implement a robust Patch Management Program, and always keep the host updated to latest stable version." +- [x] Implement a robust Patch Management Program, and always keep the host updated to latest stable version. -!!! success "Ensure host level Isolation of responsibility between GoQuorum client and its dependency (e.g do not run the transaction manager and its database in the same host) " +- [x] Ensure host level Isolation of responsibility between GoQuorum client and its dependency (e.g do not run the transaction manager and its database in the same host) -!!! success "Ensure GoQuorum network hosts run with appropiate service level agreement (SLA) that can ensure a defense against non-vulnerability based denial of service." +- [x] Ensure GoQuorum network hosts run with appropiate service level agreement (SLA) that can ensure a defense against non-vulnerability based denial of service. -#### Client +### Client -!!! success "Enable Secure Transport Security (TLS) to encrypt all communications from/to JSON-RPC interface to prevent data leakage and man in the middle attacks (MITM)." +- [x] Enable Secure Transport Security (TLS) to encrypt all communications from/to JSON-RPC interface to prevent data leakage and man in the middle attacks (MITM). -!!! success "Enable GoQuorum Enterprise JSON-RPC authorization model to enforce atomic access controls to ledger modules functionalities (e.g personal.OpenWallet)." +- [x] Enable GoQuorum Enterprise JSON-RPC authorization model to enforce atomic access controls to ledger modules functionalities (for example personal.OpenWallet). -!!! success "Implement a robust Patch Management Program, and always keep the client updated to latest stable version." +- [x] Implement a robust Patch Management Program, and always keep the client updated to latest stable version. -!!! success "Ensure GoQuorum client run configuration is not started with unlocked accounts options." +- [x] Ensure GoQuorum client run configuration is not started with unlocked accounts options. -!!! success "Ensure cross domain access of the JSON-RPC interface is configured appropriately. " +- [x] Ensure cross domain access of the JSON-RPC interface is configured appropriately. -!!! success "Ensure peer discovery is appropriately set based on the consortium requirements." +- [x] Ensure peer discovery is appropriately set based on the consortium requirements. -!!! success "In Raft Based Consensus there is no guarantee a leader would not be acting maliciously, hence raft should not be used in environment where network ledger is managed by third party authorities." +- [x] In Raft Based Consensus there is no guarantee a leader would not be acting maliciously, hence raft should not be used in environment where network ledger is managed by third party authorities. -!!! success "GoQuorum clients must run with metrics collection capability in order to preserve operational security." +- [x] GoQuorum clients must run with metrics collection capability in order to preserve operational security. -#### Users +### Users -!!! success "Accounts Private Key encryption password should never be stored in the ledger host in any form." +- [x] Accounts Private Key encryption password should never be stored in the ledger host in any form. -!!! success "In an architecture where accounts private keys are not offloaded to ledger node clients, the encrypted private keys should be backed-up to secure environment regularly. " +- [x] In an architecture where accounts private keys are not offloaded to ledger node clients, the encrypted private keys should be backed-up to secure environment regularly. diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md index 7c45ac07..02424851 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md @@ -1,20 +1,27 @@ -### Monitoring +--- +description: Network operational decisions +--- + +# Network operations + +## Monitoring + Monitoring a network for security events start from log collection activity. The GoQuorum network as any other network should produce logs, that must be analyzed for anomalies. The following parameters are of interest to be collected and analyzed: - - Hosts access and events - - Ethereum accounts on the network - - Active ledger, transaction manager nodes in the network - - Public and Private transaction rates per account in the network. - - Number of public Smart contracts in the network. - - Network connections to ledger nodes and metadata. - - Consensus protocol metadata (E.g Block creation rate, and source ...etc) +- Hosts access and events +- Ethereum accounts on the network +- Active ledger, transaction manager nodes in the network +- Public and Private transaction rates per account in the network. +- Number of public Smart contracts in the network. +- Network connections to ledger nodes and metadata. +- Consensus protocol metadata (E.g Block creation rate, and source ...etc) -### Security Checklist +## Security Checklist -!!! success "Ensure all activities of GoQuorum hosts are being logged to centralized log system" +- [x] Ensure all activities of GoQuorum hosts are being logged to centralized log system -!!! success "Centralized log system must be able to provide query capabilites over the following parameters:" +- [x] Centralized log system must be able to provide query capabilites over the following parameters - Ethereum accounts on the network - Active ledger, transaction manager nodes in the network - Public and Private transaction rates per account in the network. @@ -22,7 +29,7 @@ The following parameters are of interest to be collected and analyzed: - Network connections to ledger nodes and metadata. - Consensus protocol metadata (E.g Block creation rate, and source ...etc) -!!! success "Logs must be backed-up and integrity verified. " +- [x] Logs must be backed-up and integrity verified. -!!! success "An alerting system should be put in place in order to monitor consensus protocol anomalies " +- [x] An alerting system should be put in place in order to monitor consensus protocol anomalies diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md index 468db8a0..710bde50 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/TransactionManager.md @@ -1,35 +1,55 @@ -### Tessera -[Tessera](https://docs.tessera.consensys.net) is GoQuorum's Transaction Manager. GoQuorum privacy features depends on Tessera to Encrypt/Decrypt, and broadcast the orchestrations of a private transaction payload. +--- +description: Tessera transaction manager +--- + +# Transaction Manager + +## Tessera + +[Tessera](https://docs.tessera.consensys.net) is GoQuorum's Transaction Manager. + +GoQuorum privacy features depends on Tessera to Encrypt/Decrypt, and broadcast the orchestrations of a private transaction payload. + Tessera uses an enclave to perform the encryption/decryption of private transactions payload. The encryption keys should be stored in high secure environments such a hardware security module (HSM). -Tessera communication with its dependencies (Enclave, GoQuorum node, Payload Storage Database, Secret Storage Service) must be secured. To ensure the privacy and authentication of the communication between Tessera the network must be configured to Certificate Based Mutual Authentication (MTLS). -### Encryption Keys -Encryption keys is the most critical element of the privacy model, if the encryption key is compromised the network loses its privacy. Tessera support integration with Trusted Platform Modules (TPM) and Hardware Security Modules (HSM) to reduce surface attack and provide highly secure environment. +Tessera communication with its dependencies (Enclave, GoQuorum node, Payload Storage Database, Secret Storage Service) must be secured. + +To ensure the privacy and authentication of the communication between Tessera the network must be configured to Certificate Based Mutual Authentication (MTLS). + +## Encryption Keys + +Encryption keys is the most critical element of the privacy model, if the encryption key is compromised the network loses its privacy. + +Tessera support integration with Trusted Platform Modules (TPM) and Hardware Security Modules (HSM) to reduce surface attack and provide highly secure environment. + +## Security Checklist -### Security Checklist +- [x] Tessera should run in independent network segment in production -!!! success "Tessera should run in independent network segment in production" +- [x] Tessera must leverage certificate based mutual authentication with its dependencies -!!! success "Tessera must leverage certificate based mutual authentication with its dependencies" +- [x] Secret storage services must support key rotation. -!!! success "Secret storage services must support key rotation." +- [x] Depending on the deployment model Encryption Keys must be backed-up in offline secured locations. -!!! success "Depending on the deployment model Encryption Keys must be backed-up in offline secured locations." +- [x] Secret storage service must be in complete isolation of external network. -!!! success "Secret storage service must be in complete isolation of external network." +- [x] Tessera connection strings must not be stored in clear text in configuration files. -!!! success "Tessera connection strings must not be stored in clear text in configuration files. " +- [x] Secret storage in cloud deployment should run under a single tenancy model. -!!! success "Secret storage in cloud deployment should run under a single tenancy model." +- [x] Host firewall should be enabled, inbound and outbound traffic should be limited to only vault services and restricted to consumers of those services. This includes essential host services like DNS, and NTP. -!!! success "Host firewall should be enabled, inbound and outbound traffic should be limited to only vault services and restricted to consumers of those services. This includes essential host services like DNS, and NTP." +- [x] Restrict remote access to Secret Storage instance to whitelisted IP addresses and enable MFA. -!!! success "Restrict remote access to Secret Storage instance to whitelisted IP addresses and enable MFA." +- [x] Disable remote root access to Tessera/Secret storage hosts. -!!! success "Disable remote root access to Tessera/Secret storage hosts." +- [x] Enable remote centralized logging for tessera and its dependencies. -!!! success "Enable remote centralized logging for tessera and its dependencies." +- [x] Disable core dumps in tessera host. -!!! success "Disable core dumps in tessera host." +- [x] Tessera upgrades should be using immutable strategy and frequent. -!!! success "Tessera upgrades should be using immutable strategy and frequent." +*[TPM]: Trusted Platform Modules +*[HSM]: Hardware Security Module +*[MTLS]: Certificate Based Mutual Authentication diff --git a/docs/Concepts/Security/Framework/Overview.md b/docs/Concepts/Security/Framework/Overview.md index 13284415..57997514 100644 --- a/docs/Concepts/Security/Framework/Overview.md +++ b/docs/Concepts/Security/Framework/Overview.md @@ -1,21 +1,26 @@ -## Objectives -The **objective** of this framework is to provide an in-depth reference to Quorum and +--- +description: Security Framework overview +--- + +# Security Framework + +The Goal of this framework is to provide an in-depth reference to Quorum and Decentralized Applications (dApps) security best practices. -The following outlines the *scope* of the framework: +The following outlines the scope of the framework: - Quorum architecture security - Quorum network security guidelines - Decentralized application (dApps) security best practices - ## References -+ https://github.com/ethereum/go-ethereum/wiki -+ https://www.dasp.co/ -+ https://entethalliance.org/technical-documents/ -+ https://solidity.readthedocs.io/en/v0.5.7/# -+ https://nvlpubs.nist.gov/nistpubs/ir/2018/NIST.IR.8202.pdf -+ https://ws680.nist.gov/publication/get_pdf.cfm?pub_id=925957 -+ https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE1TH5G -+ https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf -+ https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt2r1.pdf + +- https://github.com/ethereum/go-ethereum/wiki +- https://www.dasp.co/ +- https://entethalliance.org/technical-documents/ +- https://solidity.readthedocs.io/en/v0.5.7/# +- https://nvlpubs.nist.gov/nistpubs/ir/2018/NIST.IR.8202.pdf +- https://ws680.nist.gov/publication/get_pdf.cfm?pub_id=925957 +- https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE1TH5G +- https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf +- https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt2r1.pdf diff --git a/docs/HowTo/Configure/BasicPermissions.md b/docs/HowTo/Configure/BasicPermissions.md index 867a6643..24af9d6f 100644 --- a/docs/HowTo/Configure/BasicPermissions.md +++ b/docs/HowTo/Configure/BasicPermissions.md @@ -1,9 +1,13 @@ -## Configure Basic Permissions +--- +description: Configure Basic Permissions +--- + +# Configure Basic Permissions Node Permissioning is used to define: 1. The nodes that a particular GoQuorum node is able to connect to -2. The nodes that a particular GoQuorum node is able to receive connections from +1. The nodes that a particular GoQuorum node is able to receive connections from In the [basic permissions model](../../Concepts/Permissioning/BasicNetworkPermissions.md), permissioning is managed at the individual node level by using the `--permissioned` command line flag when starting the node. diff --git a/docs/HowTo/Configure/EnhancedPermissions.md b/docs/HowTo/Configure/EnhancedPermissions.md index 815322c9..1924db68 100644 --- a/docs/HowTo/Configure/EnhancedPermissions.md +++ b/docs/HowTo/Configure/EnhancedPermissions.md @@ -5,75 +5,90 @@ are described below: ## New network -* Bring up the initial set of nodes which will be part of the network -* Deploy the `PermissionsUpgradable.sol` in the network. The deployment of this contract will require a guardian account to be given as a part of deployment. -* Deploy the rest of the contracts. All the other contracts will require the address of `PermissionsUpgradable.sol` contract as a part of deployment. -* Once all the contracts are deployed create a file `permission-config.json` which will have the following construct: -```json -{ - "upgradableAddress": "0x1932c48b2bf8102ba33b4a6b545c32236e342f34", - "interfaceAddress": "0x4d3bfd7821e237ffe84209d8e638f9f309865b87", - "implAddress": "0xfe0602d820f42800e3ef3f89e1c39cd15f78d283", - "nodeMgrAddress": "0x8a5e2a6343108babed07899510fb42297938d41f", - "accountMgrAddress": "0x9d13c6d3afe1721beef56b55d303b09e021e27ab", - "roleMgrAddress": "0x1349f3e1b8d71effb47b840594ff27da7e603d17", - "voterMgrAddress": "0xd9d64b7dc034fafdba5dc2902875a67b5d586420", - "orgMgrAddress" : "0x938781b9796aea6376e40ca158f67fa89d5d8a18", - "nwAdminOrg": "ADMINORG", - "nwAdminRole" : "ADMIN", - "orgAdminRole" : "ORGADMIN", - "accounts":["0xed9d02e382b34818e88b88a309c7fe71e65f419d", "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"], - "subOrgBreadth" : 3, - "subOrgDepth" : 4 -} -``` -> * `upgradableAddress` is the address of deployed contract `PermissionsUpgradable.sol` -> * `interfaceAddress` is the address of deployed contract `PermissionsInterface.sol` -> * `implAddress` is the address of deployed contract `PermissionsImplementation.sol` -> * `nodeMgrAddress` is the address of deployed contract `NodeManager.sol` -> * `accountMgrAddress` is the address of deployed contract `AccountManager.sol` -> * `roleMgrAddress` is the address of deployed contract `RoleManager.sol` -> * `voterMgrAddress` is the address of deployed contract `VoterManager.sol` -> * `orgMgrAddress` is the address of deployed contract `OrgManager.sol` -> * `nwAdminOrg` is the name of initial organization that will be created as a part of network boot up with new permissions model. This organization will own all the initial nodes which come at the time of network boot up and accounts which will be the network admin account -> * `nwAdminRole` is role id which will have full access and will be network admin. This role will be assigned to the network admin accounts -> * `orgAdminRole` is role id which will have full access and will manage organization level administration activities. This role will be assigned to the org admin account -> * `accounts` holds the initial list of accounts which will be linked to the network admin organization and will be assigned the network admin role. These accounts will have complete control on the network and can propose and approve new organizations into the network -> * `subOrgBreadth` indicates the number of sub organizations that any org can have -> * `subOrgDepth` indicates the maximum depth of sub org hierarchy allowed in the network - -* Once the contracts are deployed, `init` in `PermissionsUpgradable.sol` need to be executed by the guardian account. This will link the interface and implementation contracts. A sample script for loading the upgradable contract at `geth` prompt is as given below -```javascript -ac = eth.accounts[0]; -web3.eth.defaultAccount = ac; -var abi = [{"constant":true,"inputs":[],"name":"getPermImpl","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_proposedImpl","type":"address"}],"name":"confirmImplChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getGuardian","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPermInterface","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_permInterface","type":"address"},{"name":"_permImpl","type":"address"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_guardian","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]; -var upgr = web3.eth.contract(abi).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); // address of the upgradable contracts -var impl = "0xfe0602d820f42800e3ef3f89e1c39cd15f78d283" // address of the implementation contracts -var intr = "0x4d3bfd7821e237ffe84209d8e638f9f309865b87" // address of the interface contracts -``` -* At `geth` prompt load the above script after replacing the contract addresses appropriately and execute `upgr.init(intr, impl, {from: , gas: 4500000})` -* Bring down the all `geth` nodes in the network and copy `permission-config.json` into the data directory of each node +1. Bring up the initial set of nodes which will be part of the network +1. Deploy the `PermissionsUpgradable.sol` in the network. The deployment of this contract will require a guardian account to be given as a part of deployment. +1. Deploy the rest of the contracts. All the other contracts will require the address of `PermissionsUpgradable.sol` contract as a part of deployment. +1. Once all the contracts are deployed create a file `permission-config.json` which will have the following construct: + + !!! example + + ```json + { + "upgradableAddress": "0x1932c48b2bf8102ba33b4a6b545c32236e342f34", + "interfaceAddress": "0x4d3bfd7821e237ffe84209d8e638f9f309865b87", + "implAddress": "0xfe0602d820f42800e3ef3f89e1c39cd15f78d283", + "nodeMgrAddress": "0x8a5e2a6343108babed07899510fb42297938d41f", + "accountMgrAddress": "0x9d13c6d3afe1721beef56b55d303b09e021e27ab", + "roleMgrAddress": "0x1349f3e1b8d71effb47b840594ff27da7e603d17", + "voterMgrAddress": "0xd9d64b7dc034fafdba5dc2902875a67b5d586420", + "orgMgrAddress" : "0x938781b9796aea6376e40ca158f67fa89d5d8a18", + "nwAdminOrg": "ADMINORG", + "nwAdminRole" : "ADMIN", + "orgAdminRole" : "ORGADMIN", + "accounts":["0xed9d02e382b34818e88b88a309c7fe71e65f419d", "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"], + "subOrgBreadth" : 3, + "subOrgDepth" : 4 + } + ``` + + * `upgradableAddress` is the address of deployed contract `PermissionsUpgradable.sol` + * `interfaceAddress` is the address of deployed contract `PermissionsInterface.sol` + * `implAddress` is the address of deployed contract `PermissionsImplementation.sol` + * `nodeMgrAddress` is the address of deployed contract `NodeManager.sol` + * `accountMgrAddress` is the address of deployed contract `AccountManager.sol` + * `roleMgrAddress` is the address of deployed contract `RoleManager.sol` + * `voterMgrAddress` is the address of deployed contract `VoterManager.sol` + * `orgMgrAddress` is the address of deployed contract `OrgManager.sol` + * `nwAdminOrg` is the name of initial organization that will be created as a part of network boot up with new permissions model. This organization will own all the initial nodes which come at the time of network boot up and accounts which will be the network admin account + * `nwAdminRole` is role id which will have full access and will be network admin. This role will be assigned to the network admin accounts + * `orgAdminRole` is role id which will have full access and will manage organization level administration activities. This role will be assigned to the org admin account + * `accounts` holds the initial list of accounts which will be linked to the network admin organization and will be assigned the network admin role. These accounts will have complete control on the network and can propose and approve new organizations into the network + * `subOrgBreadth` indicates the number of sub organizations that any org can have + * `subOrgDepth` indicates the maximum depth of sub org hierarchy allowed in the network + +1. Once the contracts are deployed, `init` in `PermissionsUpgradable.sol` need to be executed by the guardian account. This will link the interface and implementation contracts. + The following is an example script for loading the upgradable contract at `geth` prompt: + + !!! example + + ```javascript + ac = eth.accounts[0]; + web3.eth.defaultAccount = ac; + var abi = [{"constant":true,"inputs":[],"name":"getPermImpl","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_proposedImpl","type":"address"}],"name":"confirmImplChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getGuardian","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPermInterface","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_permInterface","type":"address"},{"name":"_permImpl","type":"address"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_guardian","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]; + var upgr = web3.eth.contract(abi).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); // address of the upgradable contracts + var impl = "0xfe0602d820f42800e3ef3f89e1c39cd15f78d283" // address of the implementation contracts + var intr = "0x4d3bfd7821e237ffe84209d8e638f9f309865b87" // address of the interface contracts + ``` + +1. At `geth` prompt load the above script after replacing the contract addresses appropriately and execute `upgr.init(intr, impl, {from: , gas: 4500000})` +1. Bring down the all `geth` nodes in the network and copy `permission-config.json` into the data directory of each node ## Migrating from an earlier version + The following steps needs to be followed when migrating from a earlier version for enabling permissions feature * Bring down the running network in the earlier version. * The `maxCodeSize` attribute in `genesis.json` need to be set to 35. Update `genesis.json` to reflect the same -```javascript - "config": { - "homesteadBlock": 0, - "byzantiumBlock": 0, - "chainId": 10, - "eip150Block": 0, - "eip155Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip158Block": 0, - "maxCodeSize" : 35, - "isQuorum": -``` -* Execute `geth --datadir <> init genesis.json` + + ```javascript + "config": { + "homesteadBlock": 0, + "byzantiumBlock": 0, + "chainId": 10, + "eip150Block": 0, + "eip155Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip158Block": 0, + "maxCodeSize" : 35, + "isQuorum": + ``` + +* Execute `geth --datadir init genesis.json` * Bring up the network with latest geth and deploy the contracts as explained earlier in the set up. The rest of the steps will be similar to bringing up a new network -!!! Note - * It should be noted that the new permission model will be in force only when `permission-config.json` is present in data directory. If this file is not there and the node is brought up with `--permissioned` flag, node level permissions as per the earlier model will be effective. +!!! note + + * It should be noted that the new permission model will be in force only when `permission-config.json` is present in data directory. + If this file is not there and the node is brought up with `--permissioned` flag, node level permissions as per the earlier model will be effective. + * Please ensure that `maxCodeSize` in `genesis.json` is set to 35 diff --git a/docs/HowTo/Configure/GenesisOptions.md b/docs/HowTo/Configure/GenesisOptions.md index 45736135..e0cdf8f9 100644 --- a/docs/HowTo/Configure/GenesisOptions.md +++ b/docs/HowTo/Configure/GenesisOptions.md @@ -1,6 +1,6 @@ # GoQuorum Genesis Options -## Configurable transaction size: +## Configurable transaction size GoQuorum allows operators of blockchains to increase maximum transaction size of accepted transactions via the genesis block. The GoQuorum default is currently increased to `64kb` from Ethereum's default `32kb` @@ -15,7 +15,7 @@ transaction size. This is configurable up to `128kb` by adding `txnSizeLimit` to } ``` -## Contract code size: +## Contract code size GoQuorum allows operators of blockchains to increase maximum contract code size of accepted smart contracts via the genesis block. The GoQuorum default is currently increased to `32kb` from Ethereum's default `24kb` diff --git a/docs/HowTo/Configure/HighAvailability.md b/docs/HowTo/Configure/HighAvailability.md index 59d9468b..0e7feacf 100644 --- a/docs/HowTo/Configure/HighAvailability.md +++ b/docs/HowTo/Configure/HighAvailability.md @@ -3,19 +3,20 @@ GoQuorum architecture allows for end to end high availability on various i/o operations to fulfill security and compliance requirements. In this section we will go through an example configuration and setup: -**WARNING**: Below high availability setup is an example of how to achieve end to end high availability -using proxy server but it should be noted that this hasn't been tested in a production environment setup. +!!!warning + Below high availability setup is an example of how to achieve end to end high availability + using proxy server but it should be noted that this hasn't been tested in a production environment setup. -## GoQuorum Node Configuration Requirements: +## GoQuorum Node Configuration Requirements - Two or more GoQuorum Nodes serve as one client node. - The inbound RPC requests from clients will be load balanced to one of these Quorum nodes. - These nodes will need to share same key for transaction signing and should have shared access to key store directory or key vaults. - These nodes need to share the same private state. They could either connect to local Tessera node or -in 'full' HA setup using [proxy](#proxy-setup-on-both-quorum-nodes) running on each GoQuorum node -listening on local ipc file and directing request to Tessera Q2T http but in both cases the Tessera node(s) share the same database. + in 'full' HA setup using [proxy](#proxy-setup-on-both-quorum-nodes) running on each GoQuorum node + listening on local ipc file and directing request to Tessera Q2T http but in both cases the Tessera node(s) share the same database. -## Tessera Node Configuration Requirements: +## Tessera Node Configuration Requirements - Separate [Proxy](#standalone-proxy-server-setup) server to redirect/mirror requests to two or more Tessera nodes - Two or more Tessera Nodes serve as Privacy manager for Client GoQuorum node. @@ -23,12 +24,12 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot - In the server config, the bindingAddress should be the local addresses (their real addresses), but 'advertisedAddress' (serverAddress) needs to be configured to be the proxy - Add DB replication or mirroring for Tessera private data store and the JDBC connection string to include both Primary DB and DR DB connections to facilitate auto switchover on failure. - ??? info "Quorum HA Setup 1" **Quorum Tessera pair share same machine/container in this setup** ![Quorum Tessera HA Mode](../../images/QT_HA_1.png) ??? info "Quorum Full HA Setup " + - **The change here is each Quorum and Tessera node run in separate machine/container** - **Proxy running on each Quorum node to listen on local ipc file and load balance request to both Tessera nodes** ![Quorum Tessera Full HA Mode](../../images/QT_HA_2.png) @@ -37,10 +38,10 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot **If HA is required only for Tessera, below setup could be adopted** ![Tessera HA Mode](../../images/Tessera_HA.png) - ## Example Setup using nginx Proxy setup ### Proxy Setup on both Quorum nodes + ```c load_module /usr/lib/nginx/modules/ngx_stream_module.so; error_log /home/ubuntu/nginx-error.log; @@ -62,8 +63,8 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot } ``` - ### Standalone Proxy server setup + ```c load_module /usr/lib/nginx/modules/ngx_stream_module.so; @@ -128,6 +129,3 @@ listening on local ipc file and directing request to Tessera Q2T http but in bot proxy_pass http://p2p/upcheck; }}} ``` - - - diff --git a/docs/HowTo/Configure/dns.md b/docs/HowTo/Configure/dns.md index 2831d33c..7a9153f7 100644 --- a/docs/HowTo/Configure/dns.md +++ b/docs/HowTo/Configure/dns.md @@ -17,15 +17,18 @@ DNS is not supported for the discovery protocol. Use a bootnode instead, which c resolved. ## Compatibility + For Raft, the whole network must be on version 2.4.0 of Quorum for DNS to function properly. DNS must be explicitly enabled using the `--raftdnsenable` flag for each node once the node has migrated to version 2.4.0 of Quorum -The network runs fine when some nodes are in 2.4.0 version and some in older version as long as this feature is not enabled. For safe migration the recommended approach is as below: +The network runs fine when some nodes are in 2.4.0 version and some in older version as long as this feature is not enabled. For safe migration the following recommended approach: + * migrate the nodes to `geth` 2.4.0 version without using `--raftdnsenable` flag * once the network is fully migrated, restart the nodes with `--raftdnsenable` to enable the feature Please note that in a partially migrated network (where some nodes are on version 2.4.0 and others on lower version) **with DNS feature enabled** for migrated nodes, `raft.addPeer` should not be invoked with Hostname till entire network migrates to 2.4.0 version. If invoked, this call will crash all nodes running in older version and these nodes will have to restarted with `geth` of version 2.4.0 of Quorum. `raft.addPeer` can still be invoked with IP address and network will work fine. ### Note + In a network where all nodes are running on Quorum version 2.4.0, with few nodes enabled for DNS, we recommend the `--verbosity` to be 3 or below. We have observed that nodes which are not enabled for DNS fail to restart if `raft.addPeer` is invoked with host name if `--verbosity` is set above 3. diff --git a/docs/HowTo/DevelopPlugins.md b/docs/HowTo/DevelopPlugins.md index 6b3ab0db..b840d680 100644 --- a/docs/HowTo/DevelopPlugins.md +++ b/docs/HowTo/DevelopPlugins.md @@ -1,3 +1,7 @@ +--- +description: develop GoQuorum Plugins +--- + # Develop plugins We leverage HashiCorp's [`go-plugin`](https://github.com/hashicorp/go-plugin) to enable our plugin-based architecture using gRPC. @@ -8,8 +12,11 @@ Some advanced topics which are not available in the `go-plugin` documentation wi ## Life Cycle A plugin is started as a separate process and communicates with the GoQuorum client host process via gRPC service interfaces. + This is done over a mutually-authenticated TLS connection on the local machine. The implementation is done inside `go-plugin` -library. Usage is simplest when developing plugins in Golang. For plugins written in other languages, plugin authors need to have +library. + +Usage is simpler when developing plugins in Golang. For plugins written in other languages, plugin authors need to have an understanding of the following lifecycle (see [Advanced topics for non-Go plugins](#advanced-topics-for-non-go-plugins) for more info): 1. `geth` looks for the plugin distribution file after reading the plugin definition from settings @@ -22,8 +29,11 @@ an understanding of the following lifecycle (see [Advanced topics for non-Go plu 1. `geth` and the plugin communicate via RPC over TLS using mutual TLS Each plugin must implement the [`PluginInitializer`](#plugininitializer) gRPC service interface. + After the plugin process is successfully started and connection with the GoQuorum client is successfully established, + GoQuorum client invokes [`Init()`](#proto.PluginInitialization.Request) gRPC method in order to initialize the plugin with configuration data + read from the plugin definition's `config` field in [settings](Configure/Plugins.md) file. ## Distribution @@ -58,18 +68,20 @@ There are mandatory key value pairs which must be present. | `entrypoint` | (**Required**) Command to execute the plugin process | | `parameters` | (**Optional**) Command parameters to be passed to the plugin process | -E.g.: -```json -{ - "name": "quorum-plugin-helloWorld", - "version": "1.0.0", - "entrypoint": "helloWorldPlugin" -} -``` +!!!example + + ```json + { + "name": "quorum-plugin-helloWorld", + "version": "1.0.0", + "entrypoint": "helloWorldPlugin" + } + ``` ## Advanced topics for non-Go plugins Writing non-Go plugins is well-documented in [`go-plugin` Github](https://github.com/hashicorp/go-plugin/blob/master/docs/guide-plugin-write-non-go.md). + Some additional advanced topics are described here. ### Magic Cookie @@ -79,7 +91,7 @@ This is not a security measure, just a UX feature. Magic Cookie key and value are injected as an environment variable while executing the plugin process. -``` +```bash QUORUM_PLUGIN_MAGIC_COOKIE="CB9F51969613126D93468868990F77A8470EB9177503C5A38D437FEFF7786E0941152E05C06A9A3313391059132A7F9CED86C0783FE63A8B38F01623C8257664" ``` @@ -89,6 +101,7 @@ The plugin and the GoQuorum client's magic cookies are compared. If they are equ The GoQuorum client requires the plugin to authenticate and secure the connection via mutual TLS. `PLUGIN_CLIENT_CERT` environment variable is populated with GoQuorum Client certificate (in PEM format). + A plugin would need to include this certificate to its trusted certificate pool, then generate a self-signed certificate and append the base64-encoded value of the certificate (in DER format) in the [handshake](https://github.com/hashicorp/go-plugin/blob/master/docs/internals.md#handshake) message. diff --git a/docs/HowTo/GetStarted/Cakeshop.md b/docs/HowTo/GetStarted/Cakeshop.md index d918b26a..050ca2f5 100644 --- a/docs/HowTo/GetStarted/Cakeshop.md +++ b/docs/HowTo/GetStarted/Cakeshop.md @@ -3,16 +3,16 @@ ## Prerequisites * Java 8+ -* Java app server (Tomcat, Jetty, etc) [Optional] +* Java app server (Tomcat, Jetty, etc) (Optional) ## Running via Spring Boot -* Download WAR file (Binary packages are available for macOS, Windows, and Linux platforms on the [releases](https://github.com/ConsenSys/cakeshop/releases) page. -) +* Download WAR file (Binary packages are available for macOS, Windows, and Linux platforms on the [releases](https://github.com/ConsenSys/cakeshop/releases) page.) * Run `java -jar cakeshop.war` * Navigate to [http://localhost:8080/](http://localhost:8080/) -*Note: when running in Windows, -Dgeth.node=geth must be specified as Quorum is not yet available on Windows OS* +!!!note + when running in Windows, -Dgeth.node=geth must be specified as Quorum is not yet available on Windows OS* ## Running via App Server @@ -22,95 +22,106 @@ * Start app server * Navigate to [http://localhost:8080/](http://localhost:8080/) (default port is usually 8080) -*Note: when running in Windows, -Dgeth.node=geth must be specified as Quorum is not yet available on Windows OS* +!!!note + when running in Windows, -Dgeth.node=geth must be specified as Quorum is not yet available on Windows OS* ## Running modes There are a few ways in which you can run Cakeshop (see the sections below for details on each, as well as [configuration](https://github.com/ConsenSys/cakeshop/blob/master/docs/configuration.md#geth) page): -1\. **Default mode**: _Used when you want Cakeshop to start up an Ethereum node._ +1. **Default mode**: _Used when you want Cakeshop to start up an Ethereum node._ + Running Cakeshop in the Default mode will start up Cakeshop and also start running a regular geth node (on a private/test network). - Running Cakeshop in the Default mode will start up Cakeshop and also start running a regular geth node (on a private/test network). +1. **'Attach/Unmanaged' mode**: _Used when you want to attach Cakeshop to an already running Ethereum-like node._ + Running Cakeshop in 'Attach' a.k.a 'unmanaged' mode will initialize Cakeshop but not start it nor start any Ethereum node. Once Cakeshop initialization is complete you can configure it to use the RPC details of your running node . When you then start Cakeshop it will attach to your node. -2\. **'Attach/Unmanaged' mode**: _Used when you want to attach Cakeshop to an already running Ethereum-like node._ + !!!note + if different parties on the network are using Cakeshop to deploy contracts to the network then they need to ensure they are using the same ContractRegistry address. See details below for setting up the ContractRegistry address in this case. - Running Cakeshop in 'Attach' a.k.a 'unmanaged' mode will initialize Cakeshop but not start it nor start any Ethereum node. Once Cakeshop initialization is complete you can configure it to use the RPC details of your running node . When you then start Cakeshop it will attach to your node. +1. **Multi-Instance Set Up**: _Used when you want to run Cakeshop on more than one node in your network._ + Cakeshop is currently designed such that a given instance of Cakeshop works directly with a single Ethereum-like node, however you can set up multiple instances of Cakeshop on the same machine (each which could either have been started in 'Default' mode or 'Attach' mode) such that each can talk to a different node. - NOTE: if different parties on the network are using Cakeshop to deploy contracts to the network then they need to ensure they are using the same ContractRegistry address. See details below for setting up the ContractRegistry address in this case. + !!!note + You can use the Attach mode and/or Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. -3\. **Multi-Instance Set Up**: _Used when you want to run Cakeshop on more than one node in your network._ - - Cakeshop is currently designed such that a given instance of Cakeshop works directly with a single Ethereum-like node, however you can set up multiple instances of Cakeshop on the same machine (each which could either have been started in 'Default' mode or 'Attach' mode) such that each can talk to a different node. - -Note: you can use the Attach mode and/or Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. - - -#### The below commands assume you have renamed the WAR file to cakeshop.war +!!!warning + The following commands assume you have renamed the WAR file to cakeshop.war ### Default Mode -1. In a terminal window run: - ``` - $ cd path/to/cakeshop/war - $ java -jar cakeshop.war +1. In a terminal run: + + ```bash + cd path/to/cakeshop/war + java -jar cakeshop.war ``` -2. Open **http://localhost:8080/** in your browser (Firefox/Chrome supported) +1. Open **http://localhost:8080/** in your browser (Firefox/Chrome supported) ### Attach Mode + 1. In a terminal window run: - ``` - $ cd path/to/cakeshop/war + ```bash + cd path/to/cakeshop/war # The 'example' arg below will unpack the war file and set up the cakeshop data folders but will not actually start a node - $ java -jar cakeshop.war example + java -jar cakeshop.war example ``` -2. Navigate to path/to/cakeshop/war/data/local +1. Navigate to path/to/cakeshop/war/data/local -3. Make the following edits to the application.properties file: +1. Make the following edits to the application.properties file: - ``` + ```properties geth.auto.start=false geth.auto.stop=false ``` -4. Run: +1. Run: - ``` - $ java -jar cakeshop.war + ```bash + java -jar cakeshop.war ``` -5. Open **http://localhost:8080/** in your browser (Firefox/Chrome supported) +1. Open **http://localhost:8080/** in your browser (Firefox/Chrome supported) -6. The dropdown menu on the top right of the page should show "Manage Nodes" if you haven't attached to any yet. Click on that to go to the Manage Nodes page. +1. The dropdown menu on the top right of the page should show "Manage Nodes" if you haven't attached to any yet. Click on that to go to the Manage Nodes page. -7. Click Add Node and input the RPC url of your GoQuorum node (i.e. http://localhost:22000) and the path to the Tessera P2P Party Info endpoint (i.e. http://localhost:9001/partyinfo). +1. Click Add Node and input the RPC url of your GoQuorum node (i.e. http://localhost:22000) and the path to the Tessera P2P Party Info endpoint (i.e. http://localhost:9001/partyinfo). -8. Once added, click on View to attach to the node and return to the main Cakeshop page +1. Once added, click on View to attach to the node and return to the main Cakeshop page ### Multi-Instance Setup -Although Cakeshop currently has a one-to-one mapping with the underlying Ethereum-like node that it connects to, it is possible to have multiple Cakeshop instances running on the same machine, each connecting to a different Ethereum-like node. The best way to achieve this is to create separate Cakeshop folders for each node and then attach to each separately. You should also configure the ContractRegistry address as per the below: +Although Cakeshop currently has a one-to-one mapping with the underlying Ethereum-like node that it connects to, it is possible to have multiple Cakeshop instances running on the same machine, each connecting to a different Ethereum-like node. -> ** Cakeshop ContractRegistry contract** +The best way to achieve this is to create separate Cakeshop folders for each node and then attach to each separately. ->Cakeshop deploys a ContractRegistry contract upon start up that is used to track those contracts that have been deployed to the chain using Cakeshop or the Cakeshop APIs. When running a multi-instance setup, you'll want to ensure that each instance of Cakeshop references the same ContractRegistry contract in order that each provides a consistent view within the Contracts Explorer. +!!!exemple "Configure the ContractRegistry address" ->There are two cmd flags that can be set to achieve this: + #### Cakeshop ContractRegistry contract -> * `CAKESHOP_SHARED_CONFIG` (recommended): When this flag is set, Cakeshop will try to load a file called 'shared.properties' and read the ContractRegistry address from it. If the file doesn't exist, Cakeshop will deploy the ContractRegistry contract, create this file and store the address in the file. + Cakeshop deploys a ContractRegistry contract upon start up that is used to track those contracts that have been deployed to the chain using Cakeshop or the Cakeshop APIs. -> USAGE: `$ CAKESHOP_SHARED_CONFIG="{fileLocation}" java -jar cakeshop.war` + When running a multi-instance setup, you'll want to ensure that each instance of Cakeshop references the same ContractRegistry contract in order that each provides a consistent view within the Contracts Explorer. -> * `CAKESHOP_REGISTRY_ADDR`: This flag will directly override whatever ContractRegistry address is configured (or not) and run with that address. Using this flag doesn't change any local Cakeshop settings nor save this address to file and so you would have to run with this flag again to use this address again. + There are two cmd flags that can be set to achieve this: -> USAGE: `$ CAKESHOP_REGISTRY_ADDR="0xabcdefgh.." java -jar cakeshop.war` + * `CAKESHOP_SHARED_CONFIG` (recommended): When this flag is set, Cakeshop will try to load a file called 'shared.properties' and read the ContractRegistry address from it. If the file doesn't exist, Cakeshop will deploy the ContractRegistry contract, create this file and store the address in the file. + === "Usage" + + `CAKESHOP_SHARED_CONFIG="{fileLocation}" java -jar cakeshop.war` + + * `CAKESHOP_REGISTRY_ADDR`: This flag will directly override whatever ContractRegistry address is configured (or not) and run with that address. Using this flag doesn't change any local Cakeshop settings nor save this address to file and so you would have to run with this flag again to use this address again. + + === "Usage" + + `CAKESHOP_REGISTRY_ADDR="0xabcdefgh.." java -jar cakeshop.war` 1. In terminal window 1 run: - ``` + ```bash mkdir myNetwork && cd myNetwork cp path/to/cakeshop/download /myNetwork cd myNetwork @@ -119,41 +130,43 @@ Although Cakeshop currently has a one-to-one mapping with the underlying Ethereu CAKESHOP_SHARED_CONFIG=".." java -jar ../cakeshop.war example ``` -2. Assuming you want to attach to an existing node, navigate to /myNetwork/node1/ and edit **application.properties** per the instructions for [attach mode](#attach-mode) as described above +1. Assuming you want to attach to an existing node, navigate to /myNetwork/node1/ and edit **application.properties** per the instructions for [attach mode](#attach-mode) as described above -3. In terminal window 2 run: +1. In terminal window 2 run: - ``` + ```bash cd myNetwork/node2 CAKESHOP_SHARED_CONFIG=".." java -jar ../cakeshop.war example ``` -4. Navigate to myNetwork/node2 and edit **application.properties** per the instructions for [attach mode](#attach-mode) as described above -5. In terminal window 1 run: +1. Navigate to myNetwork/node2 and edit **application.properties** per the instructions for [attach mode](#attach-mode) as described above +1. In terminal window 1 run: - ``` + ```bash CAKESHOP_SHARED_CONFIG=".." java -jar ../cakeshop.war ``` -6. In terminal window 2 run: +1. In terminal window 2 run: - ``` + ```bash CAKESHOP_SHARED_CONFIG=".." java -Dserver.port=8081 -jar cakeshop.war # Cakeshop will now be available on localhost:8081 ``` -7. In browser window 1 open http://localhost:8080/ +1. In browser window 1 open http://localhost:8080/ -8. In browser window 2 open http://localhost:8081/ +1. In browser window 2 open http://localhost:8081/ ### Running Cakeshop on quorum-examples + You can use the 'Attach' mode to use Cakeshop to explore the quorum-examples [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network. To do so: 1. Follow the instructions in the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) example to start the 7nodes network (running vagrant up, init.sh, start.sh etc.) -2. Follow the instructions listed under the [Attach](#attach-mode) mode as described above, using the `rpcport` of the node you want to explore as found in the 7nodes [start.sh](https://github.com/ConsenSys/quorum-examples/blob/master/examples/7nodes/start.sh) file. Equally, follow the [Multi-Instance](#multi-instance-setup) setup to attach to more than one of the GoQuorum nodes. +1. Follow the instructions listed under the [Attach](#attach-mode) mode as described above, using the `rpcport` of the node you want to explore as found in the 7nodes [start.sh](https://github.com/ConsenSys/quorum-examples/blob/master/examples/7nodes/start.sh) file. Equally, follow the [Multi-Instance](#multi-instance-setup) setup to attach to more than one of the GoQuorum nodes. ### Confirming Cakeshop Start Up + In all cases, Cakeshop will be running once you see the below image, which shows the Cakeshop build and url that you can access that instance of Cakeshop on: ![image](https://raw.githubusercontent.com/jpmorganchase/cakeshop-docs/master/images/happylion.png) diff --git a/docs/HowTo/GetStarted/GettingStartedOverview.md b/docs/HowTo/GetStarted/GettingStartedOverview.md index 1a94a58f..fb60fcb8 100644 --- a/docs/HowTo/GetStarted/GettingStartedOverview.md +++ b/docs/HowTo/GetStarted/GettingStartedOverview.md @@ -11,12 +11,13 @@ local network, to configuring and creating a full network from scratch. The easiest way to get a network up and running is by using the [GoQuorum Wizard](Wizard/GettingStarted.md). This command-line tool creates a local GoQuorum network that can be started and be ready for use in minutes. + The wizard provides options for configuring the network and generates all the resources to run either in containers using `docker-compose`, or locally through the use of bash scripts. The wizard requires [NodeJS](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) and runs on Linux/Mac only. -``` +```bash npm install -g quorum-wizard quorum-wizard ``` @@ -29,7 +30,7 @@ To explore the features of GoQuorum and deploy a private contract, follow the in network that can be run either in a virtual-machine environment using Vagrant, in containers using docker-compose, or locally through the use of bash scripts to automate creation of the network. -## ![k8s-logo](../../images/qubernetes/k8s-logo.png){: style="height:20px;width:20px"} GoQuorum on Kubernetes +## GoQuorum on Kubernetes ![k8s-logo](../../images/qubernetes/k8s-logo.png){: style="height:20px;width:20px"} Use [qubernetes](https://github.com/ConsenSys/qubernetes) to run configurable N node GoQuorum networks on Kubernetes. diff --git a/docs/HowTo/GetStarted/Install.md b/docs/HowTo/GetStarted/Install.md index 747b0d48..f45e08c5 100644 --- a/docs/HowTo/GetStarted/Install.md +++ b/docs/HowTo/GetStarted/Install.md @@ -1,17 +1,23 @@ +--- +description: GoQuorum and Tessera installation +--- + # Installing GoQuorum and [Tessera](https://docs.tessera.consensys.net) can be installed and used as Docker containers, by building from source, or by downloading pre-built release binaries. ## As containers + Docker containers exist for GoQuorum and Tessera and can be found at the [`quorumengineering` Docker repository](https://hub.docker.com/u/quorumengineering/): -``` +```bash docker pull quorumengineering/quorum docker pull quorumengineering/tessera ``` ## From source + ### GoQuorum 1. Clone the repository and build the source: diff --git a/docs/HowTo/GetStarted/Wizard/GettingStarted.md b/docs/HowTo/GetStarted/Wizard/GettingStarted.md index 38c6c541..cc5cf1c5 100644 --- a/docs/HowTo/GetStarted/Wizard/GettingStarted.md +++ b/docs/HowTo/GetStarted/Wizard/GettingStarted.md @@ -1,4 +1,9 @@ +--- +description: GoQuorum network setup wizard command line tool +--- + # GoQuorum Wizard + [GoQuorum Wizard](https://github.com/ConsenSys/quorum-wizard) is a command line tool that allows users to set up a development GoQuorum network on their local machine in less than 2 minutes. @@ -41,9 +46,10 @@ You can also provide these flags when running quorum-wizard: * `--version` Show version number * `-h`, `--help` Show help - -Note: `npx` is also way to run npm modules without the need to actually install the module. Due to -quorum-wizard needing to download and cache the quorum binaries during network setup, using `npx quorum-wizard` will not work at this time. +!!!note + `npx` is also way to run npm modules without the need to actually install the module. + Due to quorum-wizard needing to download and cache the quorum binaries during network setup, + **using `npx quorum-wizard` will not work at this time.** ## Interacting with the Network @@ -53,23 +59,20 @@ To explore the features of GoQuorum and deploy a private contract, follow the in **EACCES error when doing global npm install**: -- Sometimes npm is installed in a location where the user doesn't have write permissions. On Mac, installing via [Homebrew](https://brew.sh) usually works better than the standalone installer. -- [Here is the recommended solution from NPM](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) +* Sometimes npm is installed in a location where the user doesn't have write permissions. On Mac, installing via [Homebrew](https://brew.sh) usually works better than the standalone installer. +* [Here is the recommended solution from NPM](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) ## Developing -Clone this repo to your local machine. - -`yarn install` to get all the dependencies. -`yarn test:watch` to automatically run tests on changes - -`yarn start` to automatically build on changes to any files in the src directory - -`yarn link` to use your development build when you run the global npm command - -`quorum-wizard` to run (alternatively, you can run `node build/index.js`) +1. Clone this repo to your local machine. +1. `yarn install` to get all the dependencies. +1. `yarn test:watch` to automatically run tests on changes +1. `yarn start` to automatically build on changes to any files in the src directory +1. `yarn link` to use your development build when you run the global npm command +1. `quorum-wizard` to run (alternatively, you can run `node build/index.js`) ## Contributing + [GoQuorum Wizard](https://github.com/ConsenSys/quorum-wizard) is built on open source and we invite you to contribute enhancements. Upon review you will be required to complete a Contributor License Agreement (CLA) before we are able to merge. If you have any questions about the contribution process, please feel free to diff --git a/docs/HowTo/GetStarted/Wizard/Interacting.md b/docs/HowTo/GetStarted/Wizard/Interacting.md index df098726..99787f24 100644 --- a/docs/HowTo/GetStarted/Wizard/Interacting.md +++ b/docs/HowTo/GetStarted/Wizard/Interacting.md @@ -1,17 +1,25 @@ -## Interacting with the Network +--- +description: Interact with a GoQuorum network created using the wizard +--- + +# Interacting with the Network + After following the instructions in [Getting Started](GettingStarted.md), you should have a fully generated local Quorum network. Here are some ways you can interact with the network to try out the features of Quorum. ## Start the Network If you haven't done so already, go into the network directory and run start.sh (`network/3-nodes-raft-tessera-bash` is the quickstart default, if you changed any settings the folder name will be different). -```sh + +```bash cd network/3-nodes-raft-tessera-bash ./start.sh ``` -Note: Run `./stop.sh` if you want to stop all GoQuorum, Tessera, and Cakeshop instances running on your machine +!!!note + Run `./stop.sh` if you want to stop all GoQuorum, Tessera, and Cakeshop instances running on your machine ## Demonstrating Privacy + The network comes with some simple contracts to demonstrate the privacy features of GoQuorum. In this demo we: - Send a private transaction between nodes 1 and 2 @@ -23,10 +31,12 @@ The network comes with some simple contracts to demonstrate the privacy features ### Sending a private transaction Send an example private contract from Node 1 to Node 2 (this is denoted by Node 2's public key passed via `privateFor: ["QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc="]` in `private-contract.js`): -```sh + +```bash ./runscript.sh private_contract.js ``` -Make note of the `TransactionHash` printed to the terminal. + +Take note of the `TransactionHash` printed to the terminal. ### Inspecting the GoQuorum nodes @@ -39,11 +49,14 @@ It is recommended to use separate terminal windows for each node we are inspecti - In terminal 3 run `./attach.sh 3` to attach to node 3 To look at the private transaction that was just sent, run the following command in one of the terminals: -```sh + +```bash eth.getTransaction("0xe28912c5694a1b8c4944b2252d5af21724e9f9095daab47bac37b1db0340e0bf") ``` + where you should replace this hash with the TransactionHash that was previously printed to the terminal. This will print something of the form: -```sh + +```json { blockHash: "0x4d6eb0d0f971b5e0394a49e36ba660c69e62a588323a873bb38610f7b9690b34", blockNumber: 1, @@ -62,70 +75,87 @@ where you should replace this hash with the TransactionHash that was previously } ``` -Note the `v` field value of `"0x25"` or `"0x26"` (37 or 38 in decimal) which indicates this transaction has a private payload (input). - +Take note of the `v` field value of `"0x25"` or `"0x26"` (37 or 38 in decimal) which indicates this transaction has a private payload (input). #### Checking the state of the contract + For each of the 3 nodes we'll use the Geth JavaScript console to create a variable called `address` which we will assign to the address of the contract created by Node 1. The contract address can be found in two ways: - In Node 1's log file: `qdata/logs/1.log` - By reading the `contractAddress` param after calling `eth.getTransactionReceipt(txHash)` ([Ethereum API documentation](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgettransactionreceipt)) where `txHash` is the hash printed to the terminal after sending the transaction. Once you've identified the contract address, run the following command in each terminal: -``` + +```js > var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"; //replace with your contract address ``` Next we'll use ```eth.contract``` to define a contract class with the simpleStorage ABI definition in each terminal: -``` + +```js > var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}]; > var private = eth.contract(abi).at(address) ``` The function calls are now available on the contract instance and you can call those methods on the contract. Let's start by examining the initial value of the contract to make sure that only nodes 1 and 2 can see the initialized value. + - In terminal window 1 (Node 1): -``` -> private.get() -42 -``` + + ```js + > private.get() + 42 + ``` + - In terminal window 2 (Node 2): -``` -> private.get() -42 -``` + + ```js + > private.get() + 42 + ``` + - In terminal window 3 (Node 3): -``` -> private.get() -0 -``` -So we can see nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. If you look in `private-contract.js` you will see that this was the value set when the contract was created. Node 3 is unable to read the state. + ```js + > private.get() + 0 + ``` + +So we can see nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. + +If you look in `private-contract.js` you will see that this was the value set when the contract was created. + +Node 3 is unable to read the state. ### Updating the state of the contract Next we'll have Node 1 set the state to the value `4` and verify only nodes 1 and 2 are able to view the new state. In terminal window 1 (Node 1): -``` + +```js > private.set(4,{from:eth.accounts[0],privateFor:["QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc="]}); "0xacf293b491cccd1b99d0cfb08464a68791cc7b5bc14a9b6e4ff44b46889a8f70" ``` + You can check the log files in `qdata/logs/` to see each node validating the block with this new private transaction. Once the block containing the transaction has been validated we can once again check the state from each node 1, 4, and 2. - In terminal window 1 (Node 1): -``` + +```js > private.get() 4 ``` - In terminal window 2 (Node 2): -``` + +```js > private.get() 4 ``` - In terminal window 3 (Node 3): -``` + +```js > private.get() 0 ``` @@ -156,7 +186,7 @@ Node 3 defaults: If you chose to include Cakeshop in your network (included in the Quickstart option), you can try to do the above steps in that UI as well. 1. Open http://localhost:8999 in your browser. -2. Go to the Contracts tab and Deploy the contract registry -3. Go to the Sandbox, select the SimpleStorage sample contract from the Contract Library, and deploy with Private For set to the second node's public key (`QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc=`) -4. Go back to the main Cakeshop page, go to the Contracts tab again, and you should be able to see the contract you just deployed. -5. Interact with it from there, and switch between nodes using the dropdown in the top right corner of the page. +1. Go to the Contracts tab and Deploy the contract registry +1. Go to the Sandbox, select the SimpleStorage sample contract from the Contract Library, and deploy with Private For set to the second node's public key (`QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc=`) +1. Go back to the main Cakeshop page, go to the Contracts tab again, and you should be able to see the contract you just deployed. +1. Interact with it from there, and switch between nodes using the dropdown in the top right corner of the page. diff --git a/docs/HowTo/GetStarted/migration.md b/docs/HowTo/GetStarted/migration.md index fd2aaf35..d44aa947 100644 --- a/docs/HowTo/GetStarted/migration.md +++ b/docs/HowTo/GetStarted/migration.md @@ -3,55 +3,72 @@ GoQuorum 2.6.0 upgrades the base `geth` version from 1.8.18 to 1.9.7 See [ethereum 1.9.0](https://blog.ethereum.org/2019/07/10/geth-v1-9-0/) for the complete list if new features added as a part of `geth` 1.9.7. -**Note** `geth` 1.9.7 has several enhancements at the database layer which are part of GoQuorum 2.6.0. Hence, once migrates to 2.6.0, it cannot rollback to older version of Quourm. The recommendation is to keep the back of the data directory before upgrading to 2.6.0 which can be used to revert back to older version if necessary. +!!!note + `geth` 1.9.7 has several enhancements at the database layer which are part of GoQuorum 2.6.0. + Hence, once migrates to 2.6.0, it cannot rollback to older version of Quorum. + The recommendation is to keep the back of the data directory before upgrading to 2.6.0 which can be used to revert back to older version if necessary. A node running on GoQuorum 2.6.0 can coexist on a network where other nodes are running on lower version of GoQuorum and thus supports node by node upgrade to GoQuorum 2.6.0. The suggested upgrade process is as described below: -* Bring down the node which needs to be upgraded to GoQuorum 2.6.0. Modify the `genesis.json` file to include `istanbulBlock` and `petersburgBlock`. The values for this should be set to an appropriate value in future by when the entire network would have upgraded to GoQuorum 2.6.0. This is important as the gas calculation logic has changed in `geth` 1.9.7. Not setting this value properly can result in `Bad block error` - -* GoQuorum 2.6.0 has deprecated genesis attributes `maxCodeSize` and `maxCodeSizeChangeBlock`. To allow tracking of multiple `maxCodeSize` value changes, a new attribute `maxCodeSizeConfig` is added to genesis. If the `maxCodeSize` was changed multiple times, it could possibly result in `Bad block` error for any new node joining the network. The changes in GoQuorum 2.6.0 address this and enable tracking of historical changes of `maxCodeSize` in genesis and thus allow it to be changed multiple times in network life. With this change when `init` is executed in GoQuorum 2.6.0, `geth` will force usage of `maxCodeSizeConfig`. A sample example is shown below. - -```javascript -"config": { - "homesteadBlock": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "chainId": 10, - "eip150Block": 0, - "eip155Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip158Block": 0, - "isQuorum": true, - "maxCodeSizeConfig": [ - { - "block": 5, - "size": 35 - }, - { - "block": 15, - "size": 24 - }, - { - "block": 20, - "size": 35 - } - ] - }, -``` +* Bring down the node which needs to be upgraded to GoQuorum 2.6.0. Modify the `genesis.json` file to include `istanbulBlock` and `petersburgBlock`. + The values for this should be set to an appropriate value in future by when the entire network would have upgraded to GoQuorum 2.6.0. + This is important as the gas calculation logic has changed in `geth` 1.9.7. + Not setting this value properly can result in `Bad block error` + +* GoQuorum 2.6.0 has deprecated genesis attributes `maxCodeSize` and `maxCodeSizeChangeBlock`. + To allow tracking of multiple `maxCodeSize` value changes, a new attribute `maxCodeSizeConfig` is added to genesis. + If the `maxCodeSize` was changed multiple times, it could possibly result in `Bad block` error for any new node joining the network. + The changes in GoQuorum 2.6.0 address this and enable tracking of historical changes of `maxCodeSize` in genesis and thus allow it to be changed multiple times in network life. + With this change when `init` is executed in GoQuorum 2.6.0, `geth` will force usage of `maxCodeSizeConfig`. + + !!! example + + ```javascript + "config": { + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "chainId": 10, + "eip150Block": 0, + "eip155Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip158Block": 0, + "isQuorum": true, + "maxCodeSizeConfig": [ + { + "block": 5, + "size": 35 + }, + { + "block": 15, + "size": 24 + }, + { + "block": 20, + "size": 35 + } + ] + }, + ``` + * Execute `geth --datadir path/to/datadir init genesis.json` with the modified `genesis.json` * Bring up the node in GoQuorum 2.6.0 !!! Note -* freezerdb - `geth` 1.9.7 brings in the feature of freezer db where in block data beyond certain threshold is moved to a different file based storage area. The location for freezerdb can be provided by geth command lines arguments as shown below: -``` ---datadir.ancient value Data directory for ancient chain segments (default = inside chaindata) -``` -* When a node is migrated to this version, `geth` by default will create the `ancient` data folder and start moving blocks below the immutability threshold (default: 3162240) into the ancient data. If you do not want this movement to happen, use `--immutabilitythreshold` to set the immutability threshold to an appropriate value while bringing up `geth` + * **freezerdb** - `geth` 1.9.7 brings in the feature of freezer db where in block data beyond certain threshold is moved to a different file based storage area. The location for freezerdb can be provided by geth command lines arguments as shown below: + + ```bash + --datadir.ancient value Data directory for ancient chain segments (default = inside chaindata) + ``` + + * When a node is migrated to this version, `geth` by default will create the `ancient` data folder and start moving blocks below the immutability threshold (default: 3162240) into the ancient data. + If you do not want this movement to happen, use `--immutabilitythreshold` to set the immutability threshold to an appropriate value while bringing up `geth` + + * `geth 1.9.7` by default does not allow keystore based accounts to be unlocked in the start up process. `geth` will crash if the unlock is attempted as a part of start up. To enable account unlocking explicitly use `--allow-insecure-unlock` -* `geth 1.9.7` by default does not allow keystore based accounts to be unlocked in the start up process. `geth` will crash if the unlock is attempted as a part of start up. To enable account unlocking explicitly use `--allow-insecure-unlock` -``` ---allow-insecure-unlock Allow insecure account unlocking when account-related RPCs are exposed by http -``` + ```bash + --allow-insecure-unlock Allow insecure account unlocking when account-related RPCs are exposed by http + ``` diff --git a/docs/HowTo/Logging and Errors.md b/docs/HowTo/Logging and Errors.md index 48e7747b..cf8fc57e 100644 --- a/docs/HowTo/Logging and Errors.md +++ b/docs/HowTo/Logging and Errors.md @@ -139,7 +139,7 @@ In the event of database corruption, see instructions below for [Resolution of d This can occur if there was an issue when inserting a new block into the chain and is logged in the form: -``` +```text ########## BAD BLOCK ######### Chain config: %v Number: %v diff --git a/docs/HowTo/ManageKeys/AccountPlugins.md b/docs/HowTo/ManageKeys/AccountPlugins.md index 66e490cb..24023a04 100644 --- a/docs/HowTo/ManageKeys/AccountPlugins.md +++ b/docs/HowTo/ManageKeys/AccountPlugins.md @@ -14,13 +14,13 @@ We recommended reading the [Plugins overview](../../Concepts/Plugins/Plugins.md) === "Quorum" - ```shell + ```bash geth --plugins file:///path/to/plugins.json ... ``` === "clef" - ```shell + ```bash clef --plugins file:///path/to/plugins.json ... ``` @@ -57,7 +57,7 @@ Create a plugin-managed account with a new key: === "quorum" - ```shell + ```bash curl -X POST \ -H "Content-Type:application/json" \ -d ' @@ -78,7 +78,7 @@ Create a plugin-managed account with a new key: === "clef" - ```shell + ```bash echo ' { "jsonrpc":"2.0", @@ -105,7 +105,7 @@ Create a plugin-managed account from an existing private key: === "quorum" - ```shell + ```bash curl -X POST \ -H "Content-Type:application/json" \ -d ' @@ -134,7 +134,7 @@ Create a plugin-managed account from an existing private key: A limited CLI allows users to interact directly with `account` plugins: -```shell +```bash geth account plugin --help ``` @@ -151,7 +151,7 @@ Create a plugin-managed account from an existing key: === "json file" - ```shell + ```bash geth account plugin new \ --plugins file:///path/to/plugin-config.json \ --plugins.account.config file:///path/to/new-acct-config.json @@ -159,7 +159,7 @@ Create a plugin-managed account from an existing key: === "inline json" - ```shell + ```bash geth account plugin new \ --plugins file:///path/to/plugin-config.json \ --plugins.account.config '{}' @@ -176,7 +176,7 @@ Create a plugin-managed account from an existing private key: === "json file" - ```shell + ```bash geth account plugin import \ --plugins file:///path/to/plugin-config.json \ --plugins.account.config file:///path/to/new-acct-config.json \ @@ -185,7 +185,7 @@ Create a plugin-managed account from an existing private key: === "inline json" - ```shell + ```bash geth account plugin import \ --plugins file:///path/to/plugin-config.json \ --plugins.account.config '{}' @@ -196,7 +196,7 @@ Create a plugin-managed account from an existing private key: List all plugin-managed accounts for a given config: -```shell +```bash geth account plugin list \ --plugins file:///path/to/plugin-config.json ``` diff --git a/docs/HowTo/ManageKeys/clef.md b/docs/HowTo/ManageKeys/clef.md index 5437589a..311dcb78 100644 --- a/docs/HowTo/ManageKeys/clef.md +++ b/docs/HowTo/ManageKeys/clef.md @@ -1,3 +1,7 @@ +--- +description: Clef Ethereum account manager +--- + # Using Clef ## What is Clef? @@ -11,19 +15,20 @@ features, including: * Ability to extend functionality with [`account` plugins](AccountPlugins.md) `clef` runs as a separate process to `geth` and provides an alternative method of managing accounts -and signing transactions/data. Instead of `geth` loading and using accounts directly, `geth` delegates -account management responsibilities to `clef`. +and signing transactions/data. + +Instead of `geth` loading and using accounts directly, `geth` delegates account management +responsibilities to `clef`. -Account management will be deprecated within `geth` in the future and replaced with `clef`. +!!!important + Account management will be deprecated within `geth` in the future and replaced with `clef`. Using `clef` instead of `geth` for account management has several benefits: * Users and DApps no longer have a dependency on access to a synchronised local node loaded with accounts. - -Transactions and DApp data can instead be signed using `clef` - +* Transactions and DApp data can instead be signed using `clef` * Future account-related features will likely only be available in `clef` and not found in `geth` -(e.g. [EIP-191 and EIP-712 have been implemented in `clef`, but there is no intention of implementing them in `geth`](https://github.com/ethereum/go-ethereum/pull/17789/)) + (for example, [EIP-191 and EIP-712 have been implemented in `clef`, but there is no intention of implementing them in `geth`](https://github.com/ethereum/go-ethereum/pull/17789/)) * User-experience improvements to ease use and improve security. ## Installing @@ -33,7 +38,7 @@ Transactions and DApp data can instead be signed using `clef` Verify the installation with: -```shell +```bash clef help ``` @@ -61,24 +66,26 @@ for an overview and step-by-step guide on initialising and starting `clef`, as w Using `clef` as an external signer requires interacting with `clef` through its RPC API. By default this is exposed over IPC socket. The API can also be exposed over HTTP by using the `--rpcaddr` CLI flag. -An example workflow would be: +!!!example -1. Start `clef` and make your accounts available to it -1. Sign a transaction with the account by using `clef`'s `account_signTransaction` API. `clef` will return the signed transaction. -1. Use `eth_sendRawTransaction` or `eth_sendRawPrivateTransaction` to send the signed transaction to a GoQuorum node that does not have your accounts available to it -1. The GoQuorum node validates the transaction and propagates it through the network for minting. + An example workflow would be: -#### Example: List accounts + 1. Start `clef` and make your accounts available to it + 1. Sign a transaction with the account by using `clef`'s `account_signTransaction` API. `clef` will return the signed transaction. + 1. Use `eth_sendRawTransaction` or `eth_sendRawPrivateTransaction` to send the signed transaction to a GoQuorum node that does not have your accounts available to it + 1. The GoQuorum node validates the transaction and propagates it through the network for minting. -```shell -echo '{"id": 1, "jsonrpc": "2.0", "method": "account_list"}' | nc -U /path/to/clef.ipc -``` + === "List accounts" -#### Example: Sign data + ```bash + echo '{"id": 1, "jsonrpc": "2.0", "method": "account_list"}' | nc -U /path/to/clef.ipc + ``` -```shell -echo '{"id": 1, "jsonrpc": "2.0", "method": "account_signData", "params": ["data/plain", "0x6038dc01869425004ca0b8370f6c81cf464213b3", "0xaaaaaa"]}' | nc -U /path/to/clef.ipc -``` + === "Sign data" + + ```bash + echo '{"id": 1, "jsonrpc": "2.0", "method": "account_signData", "params": ["data/plain", "0x6038dc01869425004ca0b8370f6c81cf464213b3", "0xaaaaaa"]}' | nc -U /path/to/clef.ipc + ``` ### As a geth signer @@ -102,7 +109,7 @@ By default, `clef` manages file-stored `keystore` accounts. Alternative account can be enabled through the use of [`account` plugins](AccountPlugins.md). See the [Pluggable Architecture Overview](../../Concepts/Plugins/Plugins.md) for more info on using plugins with `clef`. -```shell +```bash clef --plugins file:///path/to/plugin-config.json ``` diff --git a/docs/HowTo/Use/AddingIBFTValidators.md b/docs/HowTo/Use/AddingIBFTValidators.md index 4cb5d5f1..7093f817 100644 --- a/docs/HowTo/Use/AddingIBFTValidators.md +++ b/docs/HowTo/Use/AddingIBFTValidators.md @@ -16,7 +16,7 @@ Adding a new validator requires that a majority of existing validators propose t achieved by calling the `propose` RPC method with the value `true` and replacing the address to your required one: ```bash - $ geth attach /qdata/dd/geth.ipc + geth attach /qdata/dd/geth.ipc > istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true); null @@ -37,14 +37,15 @@ repository. for more details. To set the project name, run the following: + ```bash - $ export COMPOSE_PROJECT_NAME=addnode + export COMPOSE_PROJECT_NAME=addnode ``` -2. Bring up the network, which contains 7 nodes, of which 6 are validators. +1. Bring up the network, which contains 7 nodes, of which 6 are validators. ```bash - $ docker-compose -f ibft-6-validators.yml up + docker-compose -f ibft-6-validators.yml up ``` We will be adding the 7th node as a validator. You may notice in the logs of node 7 messages along the lines of @@ -52,7 +53,7 @@ repository. the node was started up with minting enabled, but doesn't have the authority to create blocks, and so throws this error. -3. Now we need to propose node 7 as a new proposer from the existing nodes. +1. Now we need to propose node 7 as a new proposer from the existing nodes. !!! note Remember, you could do this stage before starting node 7 in your network @@ -63,11 +64,11 @@ repository. ```bash # Propose node 7 from node 1 - $ docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null # Wait about 5 seconds, and then run: - $ docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc + docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { epoch: 30000, hash: "0xf814863d809ce3a683ee0a2197b15a8152d2696fc9c4e47cd82d0bd5cdaa3e45", @@ -97,14 +98,14 @@ repository. We can see that the new address has 1 vote under the `tally` section, and that one vote is described under the `votes` section. So we know our vote was registered! -4. Let's run this from node 2 and see similar results: +1. Let's run this from node 2 and see similar results: ```bash - $ docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null # Again, you may have to wait 5 - 10 seconds for the snapshot to show the vote - $ docker exec -it addnode_node2_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc + docker exec -it addnode_node2_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { epoch: 30000, hash: "0x93efcd458f3b875902a4532bb77d5e7ebb701791ea95486ecd58baf682312d74", @@ -133,17 +134,17 @@ repository. True to form, we have the second vote registered! -5. Ok, let's finally vote on nodes 3 and 4. +1. Ok, let's finally vote on nodes 3 and 4. ```bash - $ docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null - $ docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", true);' attach /qdata/dd/geth.ipc null ``` -6. Now we have a majority of votes, let's check the snapshot again: +1. Now we have a majority of votes, let's check the snapshot again: ```bash docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc @@ -176,7 +177,7 @@ Removing a new validator requires that a majority of existing validators propose achieved by calling the `propose` RPC method with the value `false` and replacing the address to your required one: ```bash - $ geth attach /qdata/dd/geth.ipc + geth attach /qdata/dd/geth.ipc > istanbul.propose("0xb131288f355bc27090e542ae0be213c20350b767", false); null @@ -194,21 +195,22 @@ repository. for more details. To set the project name, run the following: + ```bash - $ export COMPOSE_PROJECT_NAME=addnode + export COMPOSE_PROJECT_NAME=addnode ``` -2. Bring up the network, which contains 7 nodes, of which 6 are validators. +1. Bring up the network, which contains 7 nodes, of which 6 are validators. ```bash # Set the environment variable for docker-compose - $ export COMPOSE_PROJECT_NAME=addnode + export COMPOSE_PROJECT_NAME=addnode # Start the 7 node network, of which 6 are validators - $ docker-compose -f ibft-6-validators.yml up + docker-compose -f ibft-6-validators.yml up ``` -3. Now we need to propose node 6 as the node to remove. +1. Now we need to propose node 6 as the node to remove. !!! note We need a majority of existing validators to propose the new node before the changes will take effect. @@ -217,11 +219,11 @@ repository. ```bash # Propose node 7 from node 1 - $ docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node1_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null # Wait about 5 seconds, and then run: - $ docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc + docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { epoch: 30000, hash: "0xba9f9b72cad90ae8aee39f352b45f21d5ed5535b4479743e3f39b231fd717792", @@ -252,23 +254,23 @@ repository. `votes` section. Here, the `authorize` section is set to `false`, which is inline with our proposal to *remove* the validator. -4. We need to get a majority, so let's run the proposal on 3 more nodes: +1. We need to get a majority, so let's run the proposal on 3 more nodes: ```bash - $ docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null - $ docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node3_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null - $ docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc + docker exec -it addnode_node4_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc null ``` -5. Let's check the snapshot now all the required votes are in: +1. Let's check the snapshot now all the required votes are in: ```bash - $ docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc + docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc { epoch: 30000, hash: "0x25815a32b086926875ea2c44686e4b20effabc731b2b121ebf0e0f395101eea5", diff --git a/docs/HowTo/Use/DevelopingSmartContracts.md b/docs/HowTo/Use/DevelopingSmartContracts.md index c953792e..592f8f6a 100644 --- a/docs/HowTo/Use/DevelopingSmartContracts.md +++ b/docs/HowTo/Use/DevelopingSmartContracts.md @@ -71,4 +71,4 @@ See the [GoQuorum API](../../Reference/APIs/PrivacyAPI.md) page for details on t ## GoQuorum contract design considerations 1. *Private contracts cannot update public contracts.* This is because not all participants will be able to execute a private contract, and so if that contract can update a public contract, then each participant will end up with a different state for the public contract. -2. *Once a contract has been made public, it can't later be made private.* If you do need to make a public contract private, it would need to be deleted from the blockchain and a new private contract created. +1. *Once a contract has been made public, it can't later be made private.* If you do need to make a public contract private, it would need to be deleted from the blockchain and a new private contract created. diff --git a/docs/HowTo/Use/EnhancedPermissions.md b/docs/HowTo/Use/EnhancedPermissions.md index ed47fe5f..a292680c 100644 --- a/docs/HowTo/Use/EnhancedPermissions.md +++ b/docs/HowTo/Use/EnhancedPermissions.md @@ -1,9 +1,13 @@ +--- +description: Using enhanced smart contract based permissioning +--- + # Using enhanced permissioning Managing the [enhanced permissioning model](../../Concepts/Permissioning/Enhanced/EnhancedPermissionsOverview.md) can be broadly categorized into the following activities: -### Initial network set up +## Initial network set up Please refer to [set up](../Configure/EnhancedPermissions.md). For an existing network running with an older version of GoQuorum: @@ -28,376 +32,449 @@ As part of network initialization: * A network admin role is created with the `nwAdminRole` name specified in the config file. * All accounts given in the `accounts` array of the config file are assigned the network admin role. These accounts will have the ability to propose and approve new organizations into the network. -Assuming that the network was started with the `permission-config.json` given in the [set up](../Configure/EnhancedPermissions.md), and assuming the network was brought up with the `static-nodes.json` file given below: -```json -[ - "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0", - "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0", - "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0", - "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" -] -``` -then the network will have the following configuration once it has started up: -``` -> quorumPermission.orgList -[{ - fullOrgId: "ADMINORG", - level: 1, - orgId: "ADMINORG", - parentOrgId: "", - status: 2, - subOrgList: null, - ultimateParent: "ADMINORG" -}] -> quorumPermission.getOrgDetails("ADMINORG") -{ - acctList: [{ - acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", - isOrgAdmin: true, - orgId: "ADMINORG", - roleId: "ADMIN", - status: 2 - }, { - acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", - isOrgAdmin: true, - orgId: "ADMINORG", - roleId: "ADMIN", - status: 2 - }], - nodeList: [{ - orgId: "ADMINORG", - status: 2, - url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" - }, { - orgId: "ADMINORG", - status: 2, - url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" - }, { - orgId: "ADMINORG", - status: 2, - url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" - }, { - orgId: "ADMINORG", - status: 2, - url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" - }], - roleList: [{ - access: 3, - active: true, - isAdmin: true, - isVoter: true, - orgId: "ADMINORG", - roleId: "ADMIN" - }], - subOrgList: null -} -``` +!!!example + + Assuming that the network was started with the `permission-config.json` given in the [set up](../Configure/EnhancedPermissions.md), and assuming the network was brought up with the `static-nodes.json` file as the following: + + ```json + [ + "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0", + "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0", + "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0", + "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + ] + ``` + + then the network will have the following configuration once it has started up: + + ```js + > quorumPermission.orgList + [{ + fullOrgId: "ADMINORG", + level: 1, + orgId: "ADMINORG", + parentOrgId: "", + status: 2, + subOrgList: null, + ultimateParent: "ADMINORG" + }] + > quorumPermission.getOrgDetails("ADMINORG") + { + acctList: [{ + acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", + isOrgAdmin: true, + orgId: "ADMINORG", + roleId: "ADMIN", + status: 2 + }, { + acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", + isOrgAdmin: true, + orgId: "ADMINORG", + roleId: "ADMIN", + status: 2 + }], + nodeList: [{ + orgId: "ADMINORG", + status: 2, + url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" + }, { + orgId: "ADMINORG", + status: 2, + url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" + }, { + orgId: "ADMINORG", + status: 2, + url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" + }, { + orgId: "ADMINORG", + status: 2, + url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + }], + roleList: [{ + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "ADMINORG", + roleId: "ADMIN" + }], + subOrgList: null + } + ``` ### Proposing a new organization into the network -Once the network is up, the network admin accounts can then propose a new organization into the network. Majority approval from the network admin accounts is required before an organization is approved. The APIs for [proposing](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addorg) and [approving](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorg) an organization are documented in [permission APIs](../../Reference/APIs/PermissioningAPIs.md). - -#### Example -An example to propose and approve an organization by name `ORG1` is as shown below: - -```javascript -> quorumPermission.addOrg("ORG1", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) -"Action completed successfully" -``` - -Once the org is proposed, it will be in `Proposed` state awaiting approval from other network admin accounts. The org status is as shown below: -```javascript -> quorumPermission.orgList[1] -{ - fullOrgId: "ORG1", - level: 1, - orgId: "ORG1", - parentOrgId: "", - status: 1, - subOrgList: null, - ultimateParent: "ORG1" -} -``` - -The network admin accounts can then approve the proposed organizations and once the majority approval is achieved, the organization status is updated as `Approved` - -```javascript -> quorumPermission.approveOrg("ORG1", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"}) -"Action completed successfully" -> quorumPermission.orgList[1] -{ - fullOrgId: "ORG1", - level: 1, - orgId: "ORG1", - parentOrgId: "", - status: 2, - subOrgList: null, - ultimateParent: "ORG1" -} -``` - -The details of the new organization approved are as below: -```javascript -> quorumPermission.getOrgDetails("ORG1") -{ - acctList: [{ - acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", - isOrgAdmin: true, + +Once the network is up, the network admin accounts can then propose a new organization into the network. + +Majority approval from the network admin accounts is required before an organization is approved. + +The APIs for [proposing](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addorg) and [approving](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorg) an organization are documented in [permission APIs](../../Reference/APIs/PermissioningAPIs.md). + +!!!example + An example to propose and approve an organization by name `ORG1` is as shown below: + + ```javascript + > quorumPermission.addOrg("ORG1", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) + "Action completed successfully" + ``` + + Once the org is proposed, it will be in `Proposed` state awaiting approval from other network admin accounts. + + List the org status using the following command: + + ```javascript + > quorumPermission.orgList[1] + { + fullOrgId: "ORG1", + level: 1, orgId: "ORG1", - roleId: "ORGADMIN", - status: 2 - }], - nodeList: [{ + parentOrgId: "", + status: 1, + subOrgList: null, + ultimateParent: "ORG1" + } + ``` + + The network admin accounts can then approve the proposed organizations and once the majority approval is achieved, the organization status is updated as `Approved` + + ```javascript + > quorumPermission.approveOrg("ORG1", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"}) + "Action completed successfully" + > quorumPermission.orgList[1] + { + fullOrgId: "ORG1", + level: 1, orgId: "ORG1", + parentOrgId: "", status: 2, - url: "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0" - }], - roleList: [{ + subOrgList: null, + ultimateParent: "ORG1" + } + ``` + + The details of the new organization approved are as below: + + ```javascript + > quorumPermission.getOrgDetails("ORG1") + { + acctList: [{ + acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", + isOrgAdmin: true, + orgId: "ORG1", + roleId: "ORGADMIN", + status: 2 + }], + nodeList: [{ + orgId: "ORG1", + status: 2, + url: "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0" + }], + roleList: [{ + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "ORG1", + roleId: "ORGADMIN" + }], + subOrgList: null + } + ``` + + * A org admin role with name as given in `orgAdminRole` in `permission-config.json` has been created and linked to the organization `ORG1` + * The account given has been linked to the organization `ORG1` and org admin role. This account acts as the organization admin account and can in turn manage further roles, nodes and accounts at organization level + * The node has been linked to organization and status has been updated as `Approved` + + The new node belonging to the organization can now join the network. In case the network is running in `Raft` consensus mode, before the node joins the network, please ensure that: + + * The node has been added as a peer using `raft.addPeer(<>)` + * Bring up `geth` for the new node using `--raftjoinexisting` with the peer id as obtained in the above step + +### Organization admin managing the organization level permissions + +Once the organization is approved and the node of the organization has joined the network, the organization admin can: + +* create sub organizations, roles, add additional nodes at organization level. +* add accounts to the organization. +* change roles of existing organization level accounts. + +To add a sub org at `ORG1` level refer to [addSubOrg API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addsuborg). + +!!!example + + ```javascript + > quorumPermission.addSubOrg("ORG1", "SUB1", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0", {from: eth.accounts[0]}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1") + { + acctList: null, + nodeList: [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }], + roleList: null, + subOrgList: null + } + ``` + +For adding a sub org the enode id is not mandatory. + +For the newly created sub org if the org admin desires to add an administration account, the org admin account will have to first create a role with `isAdmin` flag as `Y` and then assign this role to the account which belongs to the sub org. + +Once assigned the account will act as org admin at sub org level. + +Refer to [addNewRole API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addnewrole). + +!!!example + + ```javascript + > quorumPermission.addNewRole("ORG1.SUB1", "SUBADMIN", 3, false, true,{from: eth.accounts[0]}) + "Action completed successfully" + > eth.accounts[0] + "0x0638e1574728b6d862dd5d3a3e0942c3be47d996" + ``` + +The role `SUBADMIN` can now be assigned to an account at sub org `SUB1` for making the account admin for the sub org. + +!!!example + + ```javascript + > quorumPermission.addAccountToOrg("0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", "ORG1.SUB1", "SUBADMIN", {from: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1") + { + acctList: [{ + acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN", + status: 2 + }], + nodeList: [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }], + roleList: [{ + access: 3, + active: true, + isAdmin: true, + isVoter: false, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN" + }], + subOrgList: null + } + ``` + + The account `0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0` is now the admin for sub org `SUB1` and will be able to add roles, accounts and nodes to the sub org. + +!!!example + + ```javascript + > quorumPermission.addNewRole("ORG1.SUB1", "TRANSACT", 1, false, true,{from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").roleList + [{ access: 3, active: true, isAdmin: true, - isVoter: true, - orgId: "ORG1", - roleId: "ORGADMIN" - }], - subOrgList: null -} -``` + isVoter: false, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN" + }, { + access: 1, + active: true, + isAdmin: true, + isVoter: false, + orgId: "ORG1.SUB1", + roleId: "TRANSACT" + }] + ``` -As can be seen from the above, as a part of approval: +!!!note + The org admin account at master org level has the admin rights on all the children sub organizations. -* A org admin role with name as given in `orgAdminRole` in `permission-config.json` has been created and linked to the organization `ORG1` -* The account given has been linked to the organization `ORG1` and org admin role. This account acts as the organization admin account and can in turn manage further roles, nodes and accounts at organization level -* The node has been linked to organization and status has been updated as `Approved` + However the admin account at sub org level has control only in the sub org to which it is linked. -The new node belonging to the organization can now join the network. In case the network is running in `Raft` consensus mode, before the node joins the network, please ensure that: +To add an account to an organization refer to [addAccountToOrg API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addaccounttoorg). -* The node has been added as a peer using `raft.addPeer(<>)` -* Bring up `geth` for the new node using `--raftjoinexisting` with the peer id as obtained in the above step +!!!example -### Organization admin managing the organization level permissions -Once the organization is approved and the node of the organization has joined the network, the organization admin can then create sub organizations, roles, add additional nodes at organization level, add accounts to the organization and change roles of existing organization level accounts. + ```javascript + > quorumPermission.addAccountToOrg("0x283f3b8989ec20df621166973c93b56b0f4b5455", "ORG1.SUB1", "SUBADMIN", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").acctList -To add a sub org at `ORG1` level refer to [addSubOrg API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addsuborg). -```javascript -> quorumPermission.addSubOrg("ORG1", "SUB1", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0", {from: eth.accounts[0]}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1") -{ - acctList: null, - nodeList: [{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" - }], - roleList: null, - subOrgList: null -} -``` - -For adding a sub org the enode id is not mandatory. For the newly created sub org if the org admin desires to add an administration account, the org admin account will have to first create a role with `isAdmin` flag as `Y` and then assign this role to the account which belongs to the sub org. Once assigned the account will act as org admin at sub org level. Refer to [addNewRole API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addnewrole). -```javascript -> quorumPermission.addNewRole("ORG1.SUB1", "SUBADMIN", 3, false, true,{from: eth.accounts[0]}) -"Action completed successfully" -> eth.accounts[0] -"0x0638e1574728b6d862dd5d3a3e0942c3be47d996" -``` + [{ + acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN", + status: 2 + }, { + acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "TRANSACT", + status: 2 + }] + ``` -The role `SUBADMIN` can now be assigned to an account at sub org `SUB1` for making the account admin for the sub org. -```javascript -> quorumPermission.addAccountToOrg("0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", "ORG1.SUB1", "SUBADMIN", {from: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1") -{ - acctList: [{ - acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN", - status: 2 - }], - nodeList: [{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" - }], - roleList: [{ - access: 3, - active: true, - isAdmin: true, - isVoter: false, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN" - }], - subOrgList: null -} -``` - -The account `0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0` is now the admin for sub org `SUB1` and will be able to add roles, accounts and nodes to the sub org. It should be noted that the org admin account at master org level has the admin rights on all the sub organizations below. However the admin account at sub org level has control only in the sub org to which it is linked. -```javascript -> quorumPermission.addNewRole("ORG1.SUB1", "TRANSACT", 1, false, true,{from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").roleList -[{ - access: 3, - active: true, - isAdmin: true, - isVoter: false, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN" -}, { - access: 1, - active: true, - isAdmin: true, - isVoter: false, - orgId: "ORG1.SUB1", - roleId: "TRANSACT" -}] -``` +To suspend an account [updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action with value `1`: -To add an account to an organization refer to [addAccountToOrg API](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addaccounttoorg). -```javascript -> quorumPermission.addAccountToOrg("0x283f3b8989ec20df621166973c93b56b0f4b5455", "ORG1.SUB1", "SUBADMIN", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").acctList - -[{ - acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN", - status: 2 -}, { - acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "TRANSACT", - status: 2 -}] -``` - -To suspend an account [updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action as 1. -```javascript -> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 1, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").acctList -[{ - acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN", - status: 2 -}, { - acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "TRANSACT", - status: 1 -}] -``` - -To revoke suspension of an account [updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action as 2. -```javascript -> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 2, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").acctList - -[{ - acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN", - status: 2 -}, { - acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "TRANSACT", - status: 2 -}] -``` - -To [blacklist an account updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action as 3. Once blacklisted no further activity will be possible on the account. -```javascript -> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 3, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").acctList - -[{ - acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "SUBADMIN", - status: 2 -}, { - acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", - isOrgAdmin: true, - orgId: "ORG1.SUB1", - roleId: "TRANSACT", - status: 5 -}] -``` - -To [add Nodes ](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addnode) at organization and sub organization level by the org admin. -```javascript -> quorumPermission.addNode("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList -[{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" -}, { - orgId: "ORG1.SUB1", - status: 2, - url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" -}] -``` - -Org admin can manage the status of the nodes by using [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API. To deactivate a node the API can be invoked with action 1. -```javascript -> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList -[{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" -}, { - orgId: "ORG1.SUB1", - status: 3, - url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" -}] -``` - -To activate the node back invoke [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API with action 2. -```javascript -> quorumPermission.updateNodeStatus("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0",2, {from:"0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) -"Action completed successfully" -> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList -[{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" -}, { - orgId: "ORG1.SUB1", - status: 2, - url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" -}] -``` - -To blacklist a node invoke [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API with action 3. Once blacklisted the node will never be able join the network again. -```javascript -> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList -[{ - orgId: "ORG1.SUB1", - status: 2, - url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" -}, { - orgId: "ORG1.SUB1", - status: 4, - url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" -}] -``` - -It should be noted that in the case of the `Raft` consensus mechanism, when the node is deactivated the peer id is lost and hence upon activation, the node needs to be added to Raft cluster again using `raft.addPeer` and the node should be brought up with new peer id. +!!!example + + ```javascript + > quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 1, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").acctList + [{ + acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN", + status: 2 + }, { + acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "TRANSACT", + status: 1 + }] + ``` + +To revoke suspension of an account [updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action with value `2`: + +!!!example + + ```javascript + > quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 2, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").acctList + + [{ + acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN", + status: 2 + }, { + acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "TRANSACT", + status: 2 + }] + ``` + +To [exclude an account updateAccountStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateaccountstatus) API can be invoked with action with value `3`. + +Once exclude, no further activity will be possible on the account. + +!!!example + + ```javascript + > quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 3, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").acctList + + [{ + acctId: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "SUBADMIN", + status: 2 + }, { + acctId: "0x283f3b8989ec20df621166973c93b56b0f4b5455", + isOrgAdmin: true, + orgId: "ORG1.SUB1", + roleId: "TRANSACT", + status: 5 + }] + ``` + +To [add Nodes](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_addnode) at organization and sub organization level by the org admin. + +!!!example + + ```javascript + > quorumPermission.addNode("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").nodeList + [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }, { + orgId: "ORG1.SUB1", + status: 2, + url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" + }] + ``` + +Org admin can manage the status of the nodes by using [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API. + +To deactivate a node the API can be invoked with action with value `1`. + +!!!example + + ```javascript + > quorumPermission.getOrgDetails("ORG1.SUB1").nodeList + [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }, { + orgId: "ORG1.SUB1", + status: 3, + url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" + }] + ``` + +To activate the node back invoke [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API with action with value `2`. + +!!!example + + ```javascript + > quorumPermission.updateNodeStatus("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0",2, {from:"0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"}) + "Action completed successfully" + > quorumPermission.getOrgDetails("ORG1.SUB1").nodeList + [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }, { + orgId: "ORG1.SUB1", + status: 2, + url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" + }] + ``` + +To exclude a node invoke [updateNodeStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updatenodestatus) API with action value `3`. + +Once excludeded the node will never be able join the network again. + +!!!example + + ```javascript + > quorumPermission.getOrgDetails("ORG1.SUB1").nodeList + [{ + orgId: "ORG1.SUB1", + status: 2, + url: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0" + }, { + orgId: "ORG1.SUB1", + status: 4, + url: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0" + }] + ``` + +!!!note + In the case of the `Raft` consensus mechanism, when the node is deactivated the peer id is lost and + hence upon activation, the node needs to be added to Raft cluster again using `raft.addPeer` + and the node should be brought up with new peer id. Further: @@ -405,91 +482,128 @@ Further: * If a node is deactivated no transaction will be allowed from that node ### Suspending an organization temporarily -If there is a need to temporarily suspend all activities of an organization [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) API can be invoked with action 1. This can be invoked only by the network admin accounts and will reuiqre majority voting. -```javascript -> quorumPermission.updateOrgStatus("ORG1", 1, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) -"Action completed successfully" -> quorumPermission.orgList[2] -{ - fullOrgId: "ORG1", - level: 1, - orgId: "ORG1", - parentOrgId: "", - status: 3, - subOrgList: null, - ultimateParent: "ORG1" -} -``` - -To approve the org, suspension majority approval from other network admin accounts is required. The api for the same is [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus). Once approved the org status is marked as suspended. -```javascript -> quorumPermission.approveOrgStatus("ORG1", 1, {from: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"}) -"Action completed successfully" -> quorumPermission.orgList[2] -{ - fullOrgId: "ORG1", - level: 1, - orgId: "ORG1", - parentOrgId: "", - status: 4, - subOrgList: null, - ultimateParent: "ORG1" -} -``` - -When the org is suspended no transaction from any of the account linked to the organization or sub organizations under it is allowed. However, the nodes linked to the organization will be active and will be syncing with the network. +If there is a need to temporarily suspend all activities of an organization [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) API can be invoked with action value `1`. + +This can be invoked only by the network admin accounts and will require majority voting. + +!!!example + + ```javascript + > quorumPermission.updateOrgStatus("ORG1", 1, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) + "Action completed successfully" + > quorumPermission.orgList[2] + { + fullOrgId: "ORG1", + level: 1, + orgId: "ORG1", + parentOrgId: "", + status: 3, + subOrgList: null, + ultimateParent: "ORG1" + } + ``` + +To approve the org, suspension majority approval from other network admin accounts is required. + +The api for the same is [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus). + +Once approved the org status is marked as suspended. + +!!!example + + ```javascript + > quorumPermission.approveOrgStatus("ORG1", 1, {from: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"}) + "Action completed successfully" + > quorumPermission.orgList[2] + { + fullOrgId: "ORG1", + level: 1, + orgId: "ORG1", + parentOrgId: "", + status: 4, + subOrgList: null, + ultimateParent: "ORG1" + } + ``` + +When the org is suspended no transaction from any of the account linked to the organization or sub +organizations under it is allowed. +However, the nodes linked to the organization will be active and will be syncing with the network. ### Revoking suspension of an organization -To revoke the suspension of an org [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) can be called with action as 2. This will require majority approval (API [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus) with action 2). -```javascript -> quorumPermission.updateOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) -"Action completed successfully" -> quorumPermission.approveOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) -"Action completed successfully" -> quorumPermission.orgList[0] -{ - fullOrgId: "ORG1.SUB1", - level: 2, - orgId: "SUB1", - parentOrgId: "ORG1", - status: 2, - subOrgList: null, - ultimateParent: "ORG1" -} -``` - -Once the revoke is approved, all accounts in the organization and sub organization will be able to transact as per role level access. + +To revoke the suspension of an org [updateOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_updateorgstatus) can be called with action value `2`. + +This will require majority approval (API [approveOrgStatus](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveorgstatus) with action value `2`). + +!!!example + + ```javascript + > quorumPermission.updateOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) + "Action completed successfully" + > quorumPermission.approveOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) + "Action completed successfully" + > quorumPermission.orgList[0] + { + fullOrgId: "ORG1.SUB1", + level: 2, + orgId: "SUB1", + parentOrgId: "ORG1", + status: 2, + subOrgList: null, + ultimateParent: "ORG1" + } + ``` + +Once the revoke is approved, all accounts in the organization and sub organization will be able to +transact as per role level access. ### Assigning admin privileges at organization and network level -There may be a scenario where one of the accounts at the organization level needs to have network admin level permissions and be able to perform network admin activities. Similarly there can be a need to change the admin account at organization level. Both these activities can be performed by existing network admin accounts only, and will require majority approval from the network admin accounts. The API usage details are as below. + +There may be a scenario where one of the accounts at the organization level needs to have network +admin level permissions and be able to perform network admin activities. + +Similarly there can be a need to change the admin account at organization level. + +Both these activities can be performed by existing network admin accounts only, and will require +majority approval from the network admin accounts. + +#### API usage details + To assign network admin or org admin role to an account invoke [assignAdminRole](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_assignadminrole). -```javascript -> quorumPermission.assignAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", "ADMIN", {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) -"Action completed successfully" -> quorumPermission.acctList[3] -{ - acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", - isOrgAdmin: true, - orgId: "ORG1", - roleId: "ADMIN", - status: 1 -} -``` + +!!!example + + ```javascript + > quorumPermission.assignAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", "ADMIN", {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"}) + "Action completed successfully" + > quorumPermission.acctList[3] + { + acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", + isOrgAdmin: true, + orgId: "ORG1", + roleId: "ADMIN", + status: 1 + } + ``` To approve the assignment of network admin role invoke [approveAdminRole](../../Reference/APIs/PermissioningAPIs.md#quorumpermission_approveadminrole) API. -```javascript -> quorumPermission.approveAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) -"Action completed successfully" -> quorumPermission.acctList[4] -{ - acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", - isOrgAdmin: true, - orgId: "ORG1", - roleId: "ADMIN", - status: 2 -} -``` + +!!!example + + ```javascript + > quorumPermission.approveAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + "Action completed successfully" + > quorumPermission.acctList[4] + { + acctId: "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", + isOrgAdmin: true, + orgId: "ORG1", + roleId: "ADMIN", + status: 2 + } + ``` The above account can now perform all activities allowable by a network admin account and can participate in the approval process for any actions at network level. diff --git a/docs/HowTo/Use/JSON-RPC-API-Security.md b/docs/HowTo/Use/JSON-RPC-API-Security.md index 9f38c3dd..6d1ae957 100644 --- a/docs/HowTo/Use/JSON-RPC-API-Security.md +++ b/docs/HowTo/Use/JSON-RPC-API-Security.md @@ -81,8 +81,9 @@ There are additional flags allowing to connect to secured Quorum node --rpcclitls.ciphersuites value Customize supported cipher suites when using TLS connection. Value is a comma-separated cipher suite string ``` -E.g.: Connect to the node with `--rpcclitls.insecureskipverify` to ignore the Server's certificate validation. -```shell +For example connect to the node with `--rpcclitls.insecureskipverify` to ignore the Server's certificate validation. + +```bash geth attach https://localhost:22000 --rpcclitls.insecureskipverify geth attach wss://localhost:23000 --rpcclitls.insecureskipverify ``` @@ -92,7 +93,7 @@ geth attach wss://localhost:23000 --rpcclitls.insecureskipverify `ethclient` provides a client for Ethereum RPC API. It's also enhanced to support Quorum-specific APIs and ability to invoke protected APIs. -**HTTP/HTTPS** +#### HTTP/HTTPS For HTTP endpoint, the preauthenticated token is populated in `Authorization` HTTP request header for each call. The token value is obtained from `rpc.HttpCredentialsProviderFunc` implementation which is configured after @@ -121,6 +122,7 @@ if err != nil { ``` To customize TLS client configuration: + ```go // instantiate a http.Client with custom TLS client config myHttpClient := ... @@ -128,7 +130,7 @@ myHttpClient := ... c, err := rpc.DialHTTPWithClient("https://...", myHttpClient) ``` -**WS/WSS** +#### WS/WSS For WS endpoint, the preauthenticated token is populated in `Authorization` HTTP request header only once during the handshake. The token value is obtained from `rpc.HttpCredentialsProviderFunc` implementation via @@ -153,6 +155,7 @@ if err != nil { ``` To customize TLS client configuration, use `rpc.DialWebsocketWithCustomTLS()` instead of `rpc.DialContext()` + ```go // create a tls.Config tlsConfig := &tls.Config{...} diff --git a/docs/HowTo/Use/add_node_examples.md b/docs/HowTo/Use/add_node_examples.md index 404619f0..a81752f4 100644 --- a/docs/HowTo/Use/add_node_examples.md +++ b/docs/HowTo/Use/add_node_examples.md @@ -1,3 +1,7 @@ +--- +description: Example scenarios for adding new nodes in a network +--- + # Adding node examples Below are some scenarios for adding a new node into a network, with a mix of different options such as @@ -5,23 +9,28 @@ consensus algorithm, permissioning, and discovery. You can find the resources required to run the examples in the [quorum-examples](https://github.com/ConsenSys/quorum-examples/tree/master/examples/adding_nodes) repository. + Checkout the repository through `git` or otherwise download all the resources your local machine to follow along. The examples use `docker-compose` for the container definitions. If you are following along by copying the commands described, then it is important to set the project name for Docker Compose, or to remember to change the prefix for -your directory. See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) -for more details. +your directory. + +See [Docker documentation](https://docs.docker.com/compose/reference/envvars/#compose_project_name) for more details. To set the project name, run the following: + ```bash -$ export COMPOSE_PROJECT_NAME=addnode +export COMPOSE_PROJECT_NAME=addnode ``` ## Non-permimssioned IBFT with discovery An example using IBFT, no permissioning and discover enabled via a bootnode. + There are no static peers in this network; instead, every node is set to talk to node 1 via the CLI flag `--bootnodes enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@172.16.239.11:21000`. + Node 1 will forward the details of all the nodes it knows about (in this case, everyone) and they will then initiate their own connections. @@ -29,287 +38,487 @@ own connections. ```bash # Ensure any old network is removed - $ docker-compose -f ibft-non-perm-bootnode.yml down + docker-compose -f ibft-non-perm-bootnode.yml down # Bring up 6 nodes - $ docker-compose -f ibft-non-perm-bootnode.yml up node1 node2 node3 node4 node5 node6 + docker-compose -f ibft-non-perm-bootnode.yml up node1 node2 node3 node4 node5 node6 ``` -2. Send in a public transaction and check it is minted. +1. Send in a public transaction and check it is minted. !!! note * The block creation period is set to 2 seconds, so you may have to wait upto that amount of time for the transaction to be minted. * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - ```bash - # Send in the transaction - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... - true - - # Retrieve the value of the contract - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + **Send in the transaction** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... + true + ``` + + **Retrieve the value of the contract** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. Bring up the last node. This node also has its bootnodes set to be node 1, so at startup will try to establish a -connection to node 1 only. After this, node 1 will share which nodes it knows about, and node 7 can then initiate -connections with those peers. +1. Bring up the last node. This node also has its bootnodes set to be node 1, so at startup will try to establish a + connection to node 1 only. After this, node 1 will share which nodes it knows about, and node 7 can then initiate + connections with those peers. - ```bash - # Bring up node 7 - $ docker-compose -f ibft-non-perm-bootnode.yml up node7 - ``` + === "Bring up node 7" + + ```bash + docker-compose -f ibft-non-perm-bootnode.yml up node7 + ``` -4. Let's check to see if the nodes are in sync. If they are, they will have similar block numbers, which is enough for -this example; there are other ways to tell if nodes are on the same chain, e.g. matching block hashes. +1. Let's check to see if the nodes are in sync. + If they are, they will have similar block numbers, which is enough for + this example; there are other ways to tell if nodes are on the same chain, for example matching block hashes. !!! note Depending on timing, the second may have an extra block or two. - ```bash - # Fetch the latest block number for node 1 - $ docker exec -it addnode_node1_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc - 45 + **Fetch the latest block number for node 1** - # Fetch the latest block number for node 7 - $ docker exec -it addnode_node7_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc - 45 - ``` + === "Request" -5. We can check that the transaction and contract we sent earlier now exist on node 7. + ```bash + docker exec -it addnode_node1_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc + ``` - ```bash - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + === "Result" -6. To be sure we have two way communication, let's send a transaction from node 7 to the network. + ```text + 45 + ``` - ```bash - $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... - true - ``` + **Fetch the latest block number for node 7** -7. Finally, we can check if the transaction was minted and the contract executed on each node. + === "Request" - ```bash - # Check on node 1 - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 + ```bash + docker exec -it addnode_node7_1 geth --exec 'eth.blockNumber' attach /qdata/dd/geth.ipc + ``` - # Check on node 7 - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + === "Result" + + ```text + 45 + ``` + +1. We can check that the transaction and contract we sent earlier now exist on node 7. + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + +1. To be sure we have two way communication, let's send a transaction from node 7 to the network. + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... + ``` + + === "Result" + + ```text + true + ``` + +1. Finally, we can check if the transaction was minted and the contract executed on each node. + + **Check on node 1** -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + + **Check on node 7** + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + +And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to read existing public data, as well as deploy its own transactions and contracts for others to see! ## Non-permissioned RAFT with discovery disabled -This example walks through adding a new node to a RAFT network. This network does not have permissioning for the -Ethereum peer-to-peer layer, and makes it connections solely based on who is listed in the nodes `static-nodes.json` -file. +This example walks through adding a new node to a RAFT network. + +This network does not have permissioning for the Ethereum peer-to-peer layer, and makes it connections +solely based on who is listed in the nodes `static-nodes.json` file. 1. Bring up an initial network of 6 nodes. ```bash # Ensure any old network is removed - $ docker-compose -f raft-non-perm-nodiscover.yml down + docker-compose -f raft-non-perm-nodiscover.yml down # Bring up 6 nodes - $ docker-compose -f raft-non-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 + docker-compose -f raft-non-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 ``` -2. Send in a public transaction and check it is minted. +1. Send in a public transaction and check it is minted. !!! note * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - ```bash - # Send in the transaction - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... - true - - # Retrieve the value of the contract - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + **Send in the transaction** - We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... + true + ``` + + **Retrieve the value of the contract** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + + You created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from -the RAFT communication layer; we also need to know what ID the new node should join with. +1. You need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from + the RAFT communication layer; we also need to know what ID the new node should join with. - ```bash - # Add the new node - $ docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc - 7 - ``` + **Add the new node** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 7 + ``` The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need this ID number handy. If it was lost, you can always view the full network, including IDs, by running the `raft.cluster` command on an existing node. -4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets -the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing -node there are fetch any bootstrap information. +1. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets + the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing + node there are fetch any bootstrap information. - ```bash - # Bring up node 7 - $ QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 - ``` + === "Bring up node 7" -5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on -node 7. + ```bash + QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 + ``` - ```bash - # Fetch the contracts value on node 7 - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` +1. Let's check to see if the nodes are in sync. You can do by seeing if you have the contract that you viewed earlier on node 7. -6. To be sure we have two way communication, let's send a transaction from node 7 to the network. + **Fetch the contracts value on node 7** - ```bash - $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... - true - ``` + === "Request" -7. Finally, we can check if the transaction was minted and the contract executed on each node. + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` - ```bash - # Check on node 1 - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 + === "Result" - # Check on node 7 - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + ```text + 42 + ``` + +1. To be sure you have two way communication, let's send a transaction from node 7 to the network. + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to + ```text + Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... + true + ``` + +1. Finally, you can check if the transaction was minted and the contract executed on each node. + + **Check on node 1** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + + **Check on node 7** + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + +And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to read existing public data, as well as deploy its own transactions and contracts for others to see! ## Permissioned RAFT with discovery disabled -This example walks through adding a new node to a RAFT network. This network does have permissioning enabled for the -Ethereum peer-to-peer layer; this means that for any Ethereum tasks, such as syncing the initial blockchain or -propagating transactions, the node must appear is others nodes' `permissioned-nodes.json` file. +This example walks through adding a new node to a RAFT network. + +This network does have permissioning enabled for the Ethereum peer-to-peer layer; this means that for +any Ethereum tasks, such as syncing the initial blockchain or propagating transactions, +the node must appear is others nodes' `permissioned-nodes.json` file. 1. Bring up an initial network of 6 nodes. ```bash # Ensure any old network is removed - $ docker-compose -f raft-perm-nodiscover.yml down + docker-compose -f raft-perm-nodiscover.yml down # Bring up 6 nodes - $ docker-compose -f raft-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 + docker-compose -f raft-perm-nodiscover.yml up node1 node2 node3 node4 node5 node6 ``` -2. Send in a public transaction and check it is minted. +1. Send in a public transaction and check it is minted. !!! note * The transaction hashes will likely be different, but the contract addresses will be the same for your network. - ```bash - # Send in the transaction - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... - true - - # Retrieve the value of the contract - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + **Send in the transaction** - We created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909 waiting to be mined... + true + ``` + + **Retrieve the value of the contract** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + + You created a transaction, in this case with hash `0xd1bf0c15546802e5a121f79d0d8e6f0fa45d4961ef8ab9598885d28084cfa909`, and then retrieved its value, which was set to be `42`. -3. We need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from -the RAFT communication layer; we also need to know what ID the new node should join with. +1. You need to add the new peer to the RAFT network before it joins, otherwise the existing nodes will reject it from + the RAFT communication layer; you also need to know what ID the new node should join with. - ```bash - # Add the new node - $ docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc - 7 - ``` + **Add the new node** - The return value is the RAFT ID of the new node. When the node joins the network for the first time, it will need - this ID number handy. If it was lost, you can always view the full network, including IDs, by running the - `raft.cluster` command on an existing node. + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400")' attach /qdata/dd/geth.ipc + ``` -4. Bring up the last node. Here, we pass the newly created ID number as a flag into the startup of node 7. This lets -the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing -node there are fetch any bootstrap information. + === "Result" + + ```text + 7 + ``` + + The return value is the RAFT ID of the new node. + + When the node joins the network for the first time, it will need this ID number handy. + + If it was lost, you can always view the full network, including IDs, by running the `raft.cluster` command on an existing node. + +1. Bring up the last node. Here, you pass the newly created ID number as a flag into the startup of node 7. This lets + the node know to not bootstrap a new network from the contents of `static-nodes.json`, but to connect to an existing + node there are fetch any bootstrap information. ```bash # Bring up node 7 - $ QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 + QUORUM_GETH_ARGS="--raftjoinexisting 7" docker-compose -f raft-non-perm-nodiscover.yml up node7 ``` -5. Let's check to see if the nodes are in sync. We can do by seeing if we have the contract that we viewer earlier on -node 7. +1. Let's check to see if the nodes are in sync. You can do by seeing if you have the contract that you viewer earlier on node 7. - ```bash - # Fetch the contracts value on node 7 - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 0 - ``` + **Fetch the contracts value on node 7** + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" - The value here is `0`, not the expected `42`! Node 7 is unable to sync the blockchain because the other peers in the - network are refusing to allow connections from node 7, due to it being missing in the `permissioned-nodes.json` file. + ```text + 0 + ``` + + The value here is `0`, not the expected `42`! + + Node 7 is unable to sync the blockchain because the other peers in the network are refusing to + allow connections from node 7, due to it being missing in the `permissioned-nodes.json` file. This does not affect the RAFT layer, so if node 7 was already is sync, it could still receive new blocks; this is okay though, since it would be permissioned on the RAFT side by virtue of being part of the RAFT cluster. -6. Let's update the permissioned nodes list on node 1, which will allow node 7 to connect to it. +1. Let's update the permissioned nodes list on node 1, which will allow node 7 to connect to it. ```bash - $ docker exec -it addnode_node1_1 cp /extradata/static-nodes-7.json /qdata/dd/permissioned-nodes.json - $ + docker exec -it addnode_node1_1 cp /extradata/static-nodes-7.json /qdata/dd/permissioned-nodes.json ``` -7. Node 7 should now be synced up through node 1. Let's see if we can see the contract we made earlier. +1. Node 7 should now be synced up through node 1. Let's see if you can see the contract you made earlier. !!! note GoQuorum attempts to re-establish nodes every 30 seconds, so you may have to wait for the sync to happen. - ```bash - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + === "Request" -8. To be sure we have two way communication, let's send a transaction from node 7 to the network. + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1932c48b2bf8102ba33b4a6b545c32236e342f34"); private.get();' attach /qdata/dd/geth.ipc + ``` - ```bash - $ docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... - true - ``` + === "Result" -9. Finally, we can check if the transaction was minted and the contract executed on each node. + ```text + 42 + ``` - ```bash - # Check on node 1 - $ docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 +1. To be sure you have two way communication, let's send a transaction from node 7 to the network. - # Check on node 7 - $ docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc - 42 - ``` + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'loadScript("/examples/public-contract.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0x84cefc3aab8ce5797dc73c70db604e5c8830fc7c2cf215876eb34fff533e2725 waiting to be mined... + true + ``` + +1. Finally, you can check if the transaction was minted and the contract executed on each node. + + **Check on node 1** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + 42 + ``` + + **Check on node 7** + + === "Request" + + ```bash + docker exec -it addnode_node7_1 geth --exec 'var private = eth.contract([{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"}]).at("0x1349f3e1b8d71effb47b840594ff27da7e603d17"); private.get();' attach /qdata/dd/geth.ipc + ``` + + === "Result" -And that's it. We deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to - read existing public data, as well as deploy its own transactions and contracts for others to see! + ```text + 42 + ``` + +And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to +read existing public data, as well as deploy its own transactions and contracts for others to see! ## Adding a Private Transaction Manager @@ -322,40 +531,58 @@ IP Whitelist isn't used, nor is key discovery disabled. ```bash # Ensure any old network is removed - $ docker-compose -f tessera-add.yml down + docker-compose -f tessera-add.yml down # Bring up 6 nodes - $ docker-compose -f tessera-add.yml up node1 node2 node3 node4 node5 node6 + docker-compose -f tessera-add.yml up node1 node2 node3 node4 node5 node6 ``` -2. We can verify that private transactions can be sent by sending one from node 1 to node 6. -We can also see that since node 7 doesn't exist yet, we can't send private transactions to it. +1. You can verify that private transactions can be sent by sending one from node 1 to node 6. + You can also see that since node 7 doesn't exist yet, you can't send private transactions to it. - ```bash - # Send a private transaction from node 1 to node 6 - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-6.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0xc8a5de4bb79d4a8c3c1156917968ca9b2965f2514732fc1cff357ec999b9aba4 waiting to be mined... - true - # Success! - - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-7.js")' attach /qdata/dd/geth.ipc - err creating contract Error: Non-200 status code: &{Status:404 Not Found StatusCode:404 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Server:[Jetty(9.4.z-SNAPSHOT)] Date:[Thu, 16 Jan 2020 12:44:19 GMT] Content-Type:[text/plain] Content-Length:[73]] Body:0xc028e87d40 ContentLength:73 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000287200 TLS:} - true - # An expected failure. The script content didn't succeed, but the script itself was run okay, so true was still returned - ``` + **Send a private transaction from node 1 to node 6** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-6.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0xc8a5de4bb79d4a8c3c1156917968ca9b2965f2514732fc1cff357ec999b9aba4 waiting to be mined... + true + # Success! + ``` + + **Send a private transaction on node 7** + + === "Request" -3. Let's first bring up node 7, then we can inspect what is happening and the configuration used. + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-7.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + err creating contract Error: Non-200 status code: &{Status:404 Not Found StatusCode:404 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Server:[Jetty(9.4.z-SNAPSHOT)] Date:[Thu, 16 Jan 2020 12:44:19 GMT] Content-Type:[text/plain] Content-Length:[73]] Body:0xc028e87d40 ContentLength:73 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc000287200 TLS:} + true + # An expected failure. The script content didn't succeed, but the script itself was run okay, so true was still returned + ``` + +1. Let's first bring up node 7, then you can inspect what is happening and the configuration used. ```bash # Bring up node 7 - $ docker-compose -f tessera-add.yml up node7 + docker-compose -f tessera-add.yml up node7 - $ docker exec -it addnode_node7_1 cat /qdata/tm/tessera-config.json - # ...some output... + docker exec -it addnode_node7_1 cat /qdata/tm/tessera-config.json ``` The last command will output Tessera 7's configuration. - The pieces we are interested in here are the following: + The pieces you are interested in here are the following: ```json { @@ -369,20 +596,28 @@ We can also see that since node 7 doesn't exist yet, we can't send private trans } ``` - We can see that the whitelist is not enabled, discovery is not specified so defaults to enabled, - and we have a single peer to start off with, which is node 1. + You can see that the whitelist is not enabled, discovery is not specified so defaults to enabled, + and you have a single peer to start off with, which is node 1. + This is all that is needed to connect to an existing network. Shortly after starting up, Tessera - will ask node 1 about all it's peers, and then will keep a record of them for it's own use. From - then on, all the nodes will know about node 7 and can send private transactions to it. + will ask node 1 about all it's peers, and then will keep a record of them for it's own use. + From then on, all the nodes will know about node 7 and can send private transactions to it. -4. Let's try it! Let's send a private transaction from node 1 to the newly added node 7. +1. Let's try it! Let's send a private transaction from node 1 to the newly added node 7. - ```bash - # Sending a transaction from node 1 to node 7 - $ docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-7.js")' attach /qdata/dd/geth.ipc - Contract transaction send: TransactionHash: 0x3e3b50768ffdb51979677ddb58f48abdabb82a3fd4f0bac5b3d1ad8014e954e9 waiting to be mined... - true - ``` + **Sending a transaction from node 1 to node 7** + + === "Request" + + ```bash + docker exec -it addnode_node1_1 geth --exec 'loadScript("/examples/private-contract-7.js")' attach /qdata/dd/geth.ipc + ``` + + === "Result" + + ```text + Contract transaction send: TransactionHash: 0x3e3b50768ffdb51979677ddb58f48abdabb82a3fd4f0bac5b3d1ad8014e954e9 waiting to be mined... + true + ``` - We got a success this time! Tessera 7 has been accepted into the network and can interact with the - other existing nodes. + You succeeded! Tessera 7 has been accepted into the network and can interact with the other existing nodes. diff --git a/docs/HowTo/Use/adding_nodes.md b/docs/HowTo/Use/adding_nodes.md index beba52e3..64bd1d77 100644 --- a/docs/HowTo/Use/adding_nodes.md +++ b/docs/HowTo/Use/adding_nodes.md @@ -1,13 +1,20 @@ +--- +description: Adding new nodes to an existing network +--- + # Adding nodes to the network -Adding new nodes to an existing network can range from a common occurence to never happening. +Adding new nodes to an existing network can range from a common occurrence to never happening. In public blockchains, such as the Ethereum Mainnet, new nodes continuously join and talk to the existing network. In permissioned blockchains, this may not happen as often, but it still an important task to achieve as your network evolves. When adding new nodes to the network, it is important understand that the GoQuorum network and Tessera - network are distinct and do not overlap in any way. Therefore, options applicable to one are not applicable to -the other. In some cases, they may have their own options to achieve similar tasks, but must be specified separately. +network are distinct and do not overlap in any way. + +Therefore, options applicable to one are not applicable to the other. + +In some cases, they may have their own options to achieve similar tasks, but must be specified separately. ## Prerequisites @@ -20,35 +27,39 @@ the other. In some cases, they may have their own options to achieve similar tas ### Raft 1. On an *existing* node, add the new peer to the raft network - ``` + + ```js > raft.addPeer("enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407") 7 ``` So in this example, our new node has a Raft ID of `7`. -2. If you are using permissioning, or discovery for Ethereum p2p, please refer [here](#extra-options). - -3. We now need to initialise the new node with the network's genesis configuration. +1. If you are using permissioning, or discovery for Ethereum p2p, please refer [here](#extra-options). - !!! note - Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. +1. We now need to initialise the new node with the network's genesis configuration. Initialising the new node is exactly the same an the original nodes. + ```bash - $ geth --datadir qdata/dd7 init genesis.json + geth --datadir qdata/dd7 init genesis.json ``` -4. Now we can start up the new node and let it sync with the network. The main difference now is the use of the + !!! note + Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. + +1. Now we can start up the new node and let it sync with the network. + The main difference now is the use of the `--raftjoinexisting` flag, which lets the node know that it is joining an existing network, which is handled -differently internally. The Raft ID obtained in step 1 is passed as a parameter to this flag. +differently internally. + The Raft ID obtained in step 1 is passed as a parameter to this flag: ```bash - $ PRIVATE_CONFIG=ignore geth --datadir qdata/dd7 ... OTHER ARGS ... --raft --raftport 50407 --rpcport 22006 --port 21006 --raftjoinexisting 7 + PRIVATE_CONFIG=ignore geth --datadir qdata/dd7 ... OTHER ARGS ... --raft --raftport 50407 --rpcport 22006 --port 21006 --raftjoinexisting 7 ``` - The new node is now up and running, and will start syncing the blockchain from existing peers. Once this has - completed, it can send new transactions just as any other peer. + The new node is now up and running, and will start syncing the blockchain from existing peers. Once this has + completed, it can send new transactions just as any other peer. ### IBFT/Clique @@ -57,18 +68,19 @@ pre-allocated on the network (permissioning aside). 1. Initialise the new node with the network's genesis configuration. - !!! note - Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. + Initialising the new node is exactly the same an the original nodes: - Initialising the new node is exactly the same an the original nodes. ```bash - $ geth --datadir qdata/dd7 init genesis.json + geth --datadir qdata/dd7 init genesis.json ``` -2. If you are using permissioning or discovery for Ethereum peer-to-peer, please refer [here](#extra-options). + !!! note + Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. + +1. If you are using permissioning or discovery for Ethereum peer-to-peer, please refer [here](#extra-options). -3. Start the new node, pointing either to a `bootnode` or listing an existing peer in the `static-nodes.json` file. -Once a connection is established, the node will start syncing the blockchain, after which transactions can be sent. +1. Start the new node, pointing either to a `bootnode` or listing an existing peer in the `static-nodes.json` file. + Once a connection is established, the node will start syncing the blockchain, after which transactions can be sent. ### Extra options @@ -77,17 +89,21 @@ Some options take effect regardless of the consensus mechanism used. #### Permissioned nodes If using the `permissioned-nodes.json` file for permissioning, then you must make sure this file is updated on all -nodes before the new node is able to communicate with existing nodes. You do not need to restart any nodes in -order for the changes to take effect. +nodes before the new node is able to communicate with existing nodes. + +You do not need to restart any nodes in order for the changes to take effect. #### Static node connections -If not using peer-to-peer node discovery (i.e. you have specified `--nodiscover`), then the only connections a node -made will be to peers defined in the `static-nodes.json` file. When adding a new node, you should make sure you have -peers defined in its `static-nodes.json` file. The more peers you have defined here, the better network connectivity -and fault tolerance you have. +If not using peer-to-peer node discovery (for example, you specified `--nodiscover`), then the only connections a node +made will be to peers defined in the `static-nodes.json` file. + +When adding a new node, you should make sure you have peers defined in its `static-nodes.json` file. + +The more peers you have defined here, the better network connectivity and fault tolerance you have. !!! note + * You do not need to update the existing peers static nodes for the connection to be established, although it is good practise to do so. * You do not need to specify every peer in your static nodes file if you do not wish to connect to every peer directly. @@ -96,14 +112,16 @@ and fault tolerance you have. If you are using discovery, then more options *in addition* to static nodes become available. - Any nodes that are connected to your peers, which at the start will be ones defined in the static node list, will -then be visible by you, allowing you to connect to them; this is done automatically. + then be visible by you, allowing you to connect to them; this is done automatically. -- You may specify any number of bootnodes, defined by the `--bootnodes` parameter. This takes a commas separated list -of enode URIs, similar to the `static-nodes.json` file. These act in the same way as static nodes, letting you connect -to them and then find out about other peers, whom you then connect to. +- You may specify any number of bootnodes, defined by the `--bootnodes` parameter. + This takes a commas separated list of enode URIs, similar to the `static-nodes.json` file. + These act in the same way as static nodes, letting you connect sto them and then find out about other peers, + whom you then connect to. !!! note - If you have discovery disabled, this means you will not try to find other nodes to connect to, but others can still find and connect to you. + If you have discovery disabled, this means you will not try to find other nodes to connect to, + but others can still find and connect to you. ## Adding Private Transaction Managers @@ -119,6 +137,7 @@ In a basic setting, adding a new PTM node is as simple as making sure you have o peer list. In Tessera, this would equate to the following in the configuration file: + ```json { "peers": [ @@ -138,7 +157,9 @@ of them in turn. ### IP whitelisting The IP Whitelist that Tessera provides allows you restrict connections much like the `permissioned-nodes.json` file -does for GoQuorum. Only IP addresses/hostnames listed in your peers list will be allowed to connect to you. +does for GoQuorum. + +Only IP addresses/hostnames listed in your peers list will be allowed to connect to you. See the [Tessera configuration page](https://docs.tessera.consensys.net) for details on setting it up. @@ -146,12 +167,14 @@ In order to make sure the new node is accepted into the network: 1. You will need to add the new peer to each of the existing nodes before communication is allowed. Tessera provides a way to do this without needing to restart an already running node: + ```bash - $ java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 + java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 ``` -2. The new peer can be started, setting the `peers` configuration to mirror the existing network. +1. The new peer can be started, setting the `peers` configuration to mirror the existing network. e.g. if there are 3 existing nodes in the network, then the new nodes configuration will look like this: + ```json { "peers": [ @@ -176,27 +199,32 @@ In order to make sure the new node is accepted into the network: Tessera discovery is very similar to the IP whitelist. The difference being that the IP whitelist blocks communications between nodes, whereas disabling discovery only affects which public keys we keep track of. -See the [Tessera configuration page](https://docs.tessera.consensys.net) for -details on setting it up. +See the [Tessera configuration page](https://docs.tessera.consensys.net) for details on setting it up. When discovery is disabled, Tessera will only allow keys that are owned by a node in its peer list to be available to -the users. This means that if any keys are found that are owned by a node NOT in our peer list, they are discarded and +the users. + +This means that if any keys are found that are owned by a node NOT in our peer list, they are discarded and private transactions cannot be sent to that public key. !!! note - This does not affect incoming transactions. Someone not in your peer list can still send transactions to your node, unless you also enable the IP Whitelist option. + This does not affect incoming transactions. + + Someone not in your peer list can still send transactions to your node, unless you also enable the IP Whitelist option. In order to make sure the new node is accepted into the network: 1. You will need to add the new peer to each of the existing nodes before they will accept public keys that are linked -to the new peer. + to the new peer. Tessera provides a way to do this without needing to restart an already running node: + ```bash - $ java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 + java -jar tessera.jar admin -configfile /path/to/existing-node-config.json -addpeer http://newpeer.com:8080 ``` -2. The new peer can be started, setting the `peers` configuration to mirror the existing network. - e.g. if there are 3 existing nodes in the network, then the new nodes configuration will look like this: +1. The new peer can be started, setting the `peers` configuration to mirror the existing network. + Foer example, if there are 3 existing nodes in the network, then the new nodes configuration will look like this: + ```json { "peers": [ @@ -216,7 +244,8 @@ to the new peer. The new node will now record public keys belonging to the existing peers, and then existing peers will record public keys belonging to the new peer; this allows private transactions to be sent both directions! - ## Examples For a walkthrough of some examples that put into action the above, check out [this guide](add_node_examples.md). + +*[PTM]: Private Transaction Manager diff --git a/docs/HowTo/Use/graphql.md b/docs/HowTo/Use/graphql.md index 9acc4af7..d17923ef 100644 --- a/docs/HowTo/Use/graphql.md +++ b/docs/HowTo/Use/graphql.md @@ -1,15 +1,19 @@ +--- +description: Using GoQuorum GraphQL API +--- # GoQuorum GraphQL ## Overview Ethereum has defined a GraphQL schema as part of -[EIP 1767](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1767.md). To support GoQuorum private transaction data, -a supplement schema and implementation has been added on top of the default. +[EIP 1767](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1767.md). -#### New Supplement Schema for GoQuorum +To support GoQuorum private transaction data, a supplement schema and implementation has been added on top of the default. -```json +### New Supplement Schema for GoQuorum + +```go # Transaction is an Ethereum transaction. type Transaction { ... @@ -20,9 +24,10 @@ type Transaction { } ``` -## Example +!!!example -```shell script -> curl http://localhost:8547/graphql -X POST -H "Content-Type: application/json" -d '{ "query": "{ transaction(hash:\"0x58462fa0b6074a8feb5d9b8cd0e6bb7ef4d1528471396070d9ae617c5dee40a8\") { isPrivate inputData privateInputData } }" }' -{"data":{"transaction":{"isPrivate":true,"inputData":"0xe9394a3620f2ef52a2001b08a79363dd467de866ab825877234ee66af5cac620877fdb88633114dd63c3c7a8048fc623e25eaa5914f5dc8004738dc0a52b62a3","privateInputData":"0x608060405234801561001057600080fd5b506040516020806101a18339810180604052602081101561003057600080fd5b81019080805190602001909291905050508060008190555050610149806100586000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006357806360fe47b1146100815780636d4ce63c146100af575b600080fd5b61006b6100cd565b6040518082815260200191505060405180910390f35b6100ad6004803603602081101561009757600080fd5b81019080803590602001909291905050506100d3565b005b6100b7610114565b6040518082815260200191505060405180910390f35b60005481565b806000819055507fefe5cb8d23d632b5d2cdd9f0a151c4b1a84ccb7afa1c57331009aa922d5e4f36816040518082815260200191505060405180910390a150565b6000805490509056fea165627a7a7230582061f6956b053dbf99873b363ab3ba7bca70853ba5efbaff898cd840d71c54fc1d0029000000000000000000000000000000000000000000000000000000000000002a"}}} -``` + ```bash + curl http://localhost:8547/graphql \ + -X POST -H "Content-Type: application/json" \ + -d '{ "query": "{ transaction(hash:\"0x58462fa0b6074a8feb5d9b8cd0e6bb7ef4d1528471396070d9ae617c5dee40a8\") { isPrivate inputData privateInputData } }" }' {"data":{"transaction":{"isPrivate":true,"inputData":"0xe9394a3620f2ef52a2001b08a79363dd467de866ab825877234ee66af5cac620877fdb88633114dd63c3c7a8048fc623e25eaa5914f5dc8004738dc0a52b62a3","privateInputData":"0x608060405234801561001057600080fd5b506040516020806101a18339810180604052602081101561003057600080fd5b81019080805190602001909291905050508060008190555050610149806100586000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006357806360fe47b1146100815780636d4ce63c146100af575b600080fd5b61006b6100cd565b6040518082815260200191505060405180910390f35b6100ad6004803603602081101561009757600080fd5b81019080803590602001909291905050506100d3565b005b6100b7610114565b6040518082815260200191505060405180910390f35b60005481565b806000819055507fefe5cb8d23d632b5d2cdd9f0a151c4b1a84ccb7afa1c57331009aa922d5e4f36816040518082815260200191505060405180910390a150565b6000805490509056fea165627a7a7230582061f6956b053dbf99873b363ab3ba7bca70853ba5efbaff898cd840d71c54fc1d0029000000000000000000000000000000000000000000000000000000000000002a"}}} + ``` diff --git a/docs/HowTo/Use/import-export.md b/docs/HowTo/Use/import-export.md index 8198a869..ab19fc35 100644 --- a/docs/HowTo/Use/import-export.md +++ b/docs/HowTo/Use/import-export.md @@ -1,48 +1,61 @@ +--- +description: Backup and restore GoQuorum Nodes with private transactions, permissioning, and supported consensus algorithms +--- + # Backup and Restore of GoQuorum Nodes -GoQuorum supports export and import of chain data with built in tooling. This is an effective node backup mechanism -adapted for the specific needs of GoQuorum such as private transactions, permissioning, and supported consensus -algorithms. +GoQuorum supports export and import of chain data with built in tooling. +This is an effective node backup mechanism adapted for the specific needs of GoQuorum such as private transactions, permissioning, and supported consensus +algorithms. !!! note GoQuorum chain data import and export must run after `geth` process is stopped. -### Node Backup (Export) +## Node Backup (Export) Backup functionality mimics original `geth export` command. GoQuorum export accepts 3 arguments: 1. Export file name **required** -3. First block -4. Last block *are optional but must be provided together when used* +1. First block +1. Last block *are optional but must be provided together when used* -##### Sample command +=== "Sample command" -`geth export --datadir ` + ```bash + geth export --datadir + ``` -### Node Restore (Import) +## Node Restore (Import) Restore functionality mimics original `geth import` command but requires transaction manager environment variable. -GoQuorum import must run on a new node with an initialized `--datadir` after `geth init` has been executed. Restore -supports arbitrary number of import files (at least 1). + +GoQuorum import must run on a new node with an initialized `--datadir` after `geth init` has been executed. + +Restore supports arbitrary number of import files (at least 1). !!! warning If private transactions are used in the chain data, Private Transaction Manager process for the original exported - node must be running on the PTM ipc endpoint during import chain. Otherwise, nil pointer exceptions will be raised. + node must be running on the PTM ipc endpoint during import chain. + Otherwise, nil pointer exceptions will be raised. + +### Sample command -##### Sample command +=== "Sample command" -`PRIVATE_CONFIG= geth import --datadir ` + ```bash + PRIVATE_CONFIG= geth import --datadir + ``` -### Special Consensus Considerations +## Special Consensus Considerations -##### IBFT +### IBFT IBFT block data contains sealer information in the header, to restore a copy of exported chain data, the new node must be initialized use an IBFT genesis file with exact same validator set encoded in extra data field as original exported node's genesis. -##### Raft +### Raft Raft backup do not account for current Raft state. An exported chain data from a Raft cluster can only be used by new nodes being added to that same cluster only. diff --git a/docs/Reference/APIs/PermissioningAPIs.md b/docs/Reference/APIs/PermissioningAPIs.md index d04270e3..afaa0011 100644 --- a/docs/Reference/APIs/PermissioningAPIs.md +++ b/docs/Reference/APIs/PermissioningAPIs.md @@ -1,3 +1,7 @@ +--- +description: Permission APIs +--- + # Permission APIs ## APIs @@ -20,40 +24,44 @@ None * `subOrgList`: list of sub orgs linked to the org * `ultimateParent`: Master org under which the org falls -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_orgList","id":10}' --header "Content-Type: application/json" - - // Response - { - fullOrgId: "INITORG", - level: 1, - orgId: "INITORG", - parentOrgId: "", - status: 2, - subOrgList: null, - ultimateParent: "INITORG" - } - ``` - -=== "geth console" - - ```javascript - > quorumPermission.orgList - [{ - fullOrgId: "INITORG", - level: 1, - orgId: "INITORG", - parentOrgId: "", - status: 2, - subOrgList: null, - ultimateParent: "INITORG" - }] - ``` +!!! Examples + + === "JSON-RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_orgList","id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + + { + fullOrgId: "INITORG", + level: 1, + orgId: "INITORG", + parentOrgId: "", + status: 2, + subOrgList: null, + ultimateParent: "INITORG" + } + ``` + + === "geth console" + + ```javascript + > quorumPermission.orgList + + [{ + fullOrgId: "INITORG", + level: 1, + orgId: "INITORG", + parentOrgId: "", + status: 2, + subOrgList: null, + ultimateParent: "INITORG" + }] + ``` ### `quorumPermission_acctList` @@ -71,48 +79,52 @@ None * `roleId`: role assigned to the account * `status`: account status. [refer](#account-status-types) for the complete list of account status. -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_acctList","id":10}' --header "Content-Type: application/json" - - // Response - { - acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }, { - acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - } - ``` - -=== "geth console" - - ```javascript - > quorumPermission.acctList - [{ - acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }, { - acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }] - ``` +!!! example + + === "JSON RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_acctList","id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + + { + acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }, { + acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + } + ``` + + === "geth console" + + ```javascript + > quorumPermission.acctList + + [{ + acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }, { + acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }] + ``` ### `quorumPermission_nodeList` @@ -128,56 +140,58 @@ None * `status`: status of the node. [refer](#node-status-types) for the complete list of node statuses * `url`: complete enode id -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_nodeList","id":10}' --header "Content-Type: application/json" - - // Response - { - orgId: "INITORG", - status: 2, - url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" - } - ``` - -=== "geth console" - - ```javascript - > quorumPermission.nodeList - [{ - orgId: "INITORG", - status: 2, - url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" - }] - ``` +!!! example + + === "JSON RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_nodeList","id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + { + orgId: "INITORG", + status: 2, + url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + } + ``` + + === "geth console" + + ```javascript + > quorumPermission.nodeList + [{ + orgId: "INITORG", + status: 2, + url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + }] + ``` ### `quorumPermission_roleList` @@ -196,38 +210,40 @@ None * `orgId`: org id to which the role is linked * `roleId`: unique role id -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_roleList","id":10}' --header "Content-Type: application/json" - - // Response - { - access: 3, - active: true, - isAdmin: true, - isVoter: true, - orgId: "INITORG", - roleId: "NWADMIN" - } - ``` - -=== "geth console" - - ```javascript - > quorumPermission.roleList - [{ - access: 3, - active: true, - isAdmin: true, - isVoter: true, - orgId: "INITORG", - roleId: "NWADMIN" - }] - ``` +!!! example + + === "JSON RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_roleList","id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + { + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "INITORG", + roleId: "NWADMIN" + } + ``` + + === "geth console" + + ```javascript + > quorumPermission.roleList + [{ + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "INITORG", + roleId: "NWADMIN" + }] + ``` ### `quorumPermission_getOrgDetails` @@ -245,104 +261,106 @@ This returns the list of accounts, nodes, roles, and sub organizations linked to * `subOrgList`: array of sub orgs linked to the org * Output: list of all accounts, nodes, roles, and sub orgs -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_getOrgDetails","params":["INITORG"],"id":10}' --header "Content-Type: application/json" - - // Response - { - acctList: [{ - acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }, { - acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }], - nodeList: [{ - orgId: "INITORG", - status: 2, - url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" - }], - roleList: [{ - access: 3, - active: true, - isAdmin: true, - isVoter: true, - orgId: "INITORG", - roleId: "NWADMIN" - }], - subOrgList: null - } - ``` - -=== "geth console" - - ```javascript - > quorumPermission_getOrgDetails("INITORG") - { - acctList: [{ - acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }, { - acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", - isOrgAdmin: true, - orgId: "INITORG", - roleId: "NWADMIN", - status: 2 - }], - nodeList: [{ - orgId: "INITORG", - status: 2, - url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" - }, { - orgId: "INITORG", - status: 2, - url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" - }], - roleList: [{ - access: 3, - active: true, - isAdmin: true, - isVoter: true, - orgId: "INITORG", - roleId: "NWADMIN" - }], - subOrgList: null - } - ``` +!!! example + + === "JSON RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_getOrgDetails","params":["INITORG"],"id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + { + acctList: [{ + acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }, { + acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }], + nodeList: [{ + orgId: "INITORG", + status: 2, + url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + }], + roleList: [{ + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "INITORG", + roleId: "NWADMIN" + }], + subOrgList: null + } + ``` + + === "geth console" + + ```javascript + > quorumPermission_getOrgDetails("INITORG") + { + acctList: [{ + acctId: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }, { + acctId: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", + isOrgAdmin: true, + orgId: "INITORG", + roleId: "NWADMIN", + status: 2 + }], + nodeList: [{ + orgId: "INITORG", + status: 2, + url: "enode://72c0572f7a2492cffb5efc3463ef350c68a0446402a123dacec9db5c378789205b525b3f5f623f7548379ab0e5957110bffcf43a6115e450890f97a9f65a681a@127.0.0.1:21000?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://7a1e3b5c6ad614086a4e5fb55b6fe0a7cf7a7ac92ac3a60e6033de29df14148e7a6a7b4461eb70639df9aa379bd77487937bea0a8da862142b12d326c7285742@127.0.0.1:21001?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://5085e86db5324ca4a55aeccfbb35befb412def36e6bc74f166102796ac3c8af3cc83a5dec9c32e6fd6d359b779dba9a911da8f3e722cb11eb4e10694c59fd4a1@127.0.0.1:21002?discport=0" + }, { + orgId: "INITORG", + status: 2, + url: "enode://28a4afcf56ee5e435c65b9581fc36896cc684695fa1db83c9568de4353dc6664b5cab09694d9427e9cf26a5cd2ac2fb45a63b43bb24e46ee121f21beb3a7865e@127.0.0.1:21003?discport=0" + }], + roleList: [{ + access: 3, + active: true, + isAdmin: true, + isVoter: true, + orgId: "INITORG", + roleId: "NWADMIN" + }], + subOrgList: null + } + ``` ### `quorumPermission_addOrg` @@ -359,50 +377,52 @@ This api can be executed by a network admin account (`from:` in transactions arg * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addOrg","params":["ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" - - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` - -=== "geth console" - - ```javascript - > quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) - "Action completed successfully" - ``` - -If there are any pending items for approval, proposal of any new organization will fail. Also the enode id and accounts can be linked to one organization only. - -=== "geth console" - - ```javascript - > quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) - Error: Pending approvals for the organization. Approve first - at web3.js:3143:20 - at web3.js:6347:15 - at web3.js:5081:36 - at :1:1 - - > quorumPermission.addOrg("XYZ", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) - Error: EnodeId already part of network. - at web3.js:3143:20 - at web3.js:6347:15 - at web3.js:5081:36 - at :1:1 - > quorumPermission.addOrg("XYZ", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) - Error: Account already in use in another organization - at web3.js:3143:20 - at web3.js:6347:15 - at web3.js:5081:36 - at :1:1 - ``` +!!! example + + === "JSON RPC" + + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addOrg","params":["ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` + + ```javascript + // Response + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` + + === "geth console" + + ```javascript + > quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + "Action completed successfully" + ``` + + If there are any pending items for approval, proposal of any new organization will fail. Also the enode id and accounts can be linked to one organization only. + + === "geth console" + + ```javascript + > quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + Error: Pending approvals for the organization. Approve first + at web3.js:3143:20 + at web3.js:6347:15 + at web3.js:5081:36 + at :1:1 + + > quorumPermission.addOrg("XYZ", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + Error: EnodeId already part of network. + at web3.js:3143:20 + at web3.js:6347:15 + at web3.js:5081:36 + at :1:1 + > quorumPermission.addOrg("XYZ", "enode://de9c2d5937e599930832cecc1df8cc90b50839bdf635c1a4e68e1dab2d001cd4a11c626e155078cc65958a72e2d72c1342a28909775edd99cc39470172cce0ac@127.0.0.1:21004?discport=0", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + Error: Account already in use in another organization + at web3.js:3143:20 + at web3.js:6347:15 + at web3.js:5081:36 + at :1:1 + ``` ### `quorumPermission_approveOrg` @@ -419,24 +439,27 @@ This api can be executed by a network admin account (`from:` in transactions arg * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveOrg","params":["ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveOrg","params":["ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - quorumPermission.approveOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + quorumPermission.approveOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]}) + "Action completed successfully" + ``` ### `quorumPermission_updateOrgStatus` @@ -454,23 +477,26 @@ This api can only be executed by a network admin account and is used for tempora * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateOrgStatus","params":["ABC", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" - //Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateOrgStatus","params":["ABC", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` -=== "geth console" + ```javascript + //Response + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.updateOrgStatus("ABC", 1, {from:eth.accounts[0]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.updateOrgStatus("ABC", 1, {from:eth.accounts[0]}) + "Action completed successfully" + ``` ### `quorumPermission_approveOrgStatus` @@ -488,24 +514,26 @@ This api can only be executed by a network admin account and is used for approvi * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveOrgStatus","params":["ABC", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveOrgStatus","params":["ABC", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - //Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + //Response + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` -=== "geth console" + === "geth console" - ```javascript - quorumPermission.approveOrgStatus("ABC", 1, {from: eth.accounts[0]}) - "Action completed successfully" - ``` + ```javascript + quorumPermission.approveOrgStatus("ABC", 1, {from: eth.accounts[0]}) + "Action completed successfully" + ``` When an organization is in suspended status, no transactions or contract deploy activities are allowed from any nodes linked to the org and sub organizations under it. Similarly no transactions will be allowed from any accounts linked to the organization @@ -524,26 +552,29 @@ This api can be executed by a organization admin account to create a sub organiz * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addSubOrg","params":["ABC", "SUB1","", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addSubOrg","params":["ABC", "SUB1","", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.addSubOrg("ABC", "SUB1", "", {from: eth.accounts[0]}) - "Action completed successfully" - ``` + === "geth console" -Few examples of adding sub org in nested hierarchy: + ```javascript + > quorumPermission.addSubOrg("ABC", "SUB1", "", {from: eth.accounts[0]}) + "Action completed successfully" + ``` + + Few examples of adding sub org in nested hierarchy: ```javascript > quorumPermission.addSubOrg("ABC.SUB1", "SUB2","", {from: eth.accounts[0]}) @@ -570,26 +601,29 @@ This api can be executed by an organization admin account to create a new role f * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addNewRole","params":["ABC", "TRANSACT",1,false,false, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addNewRole","params":["ABC", "TRANSACT",1,false,false, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.addNewRole("ABC", "TRANSACT", 1, false, false,{from: eth.accounts[0]}) - "Action completed successfully" - > quorumPermission.addNewRole("ABC.SUB1.SUB2.SUB3", "TRANSACT", 1, false, false,{from: eth.accounts[0]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.addNewRole("ABC", "TRANSACT", 1, false, false,{from: eth.accounts[0]}) + "Action completed successfully" + > quorumPermission.addNewRole("ABC.SUB1.SUB2.SUB3", "TRANSACT", 1, false, false,{from: eth.accounts[0]}) + "Action completed successfully" + ``` ### `quorumPermission_removeRole` @@ -605,24 +639,27 @@ This api can be executed by an organization admin account to create a new role f * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_removeRole","params":["ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_removeRole","params":["ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.removeRole("ABC.SUB1.SUB2.SUB3", "TRANSACT", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.removeRole("ABC.SUB1.SUB2.SUB3", "TRANSACT", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_addAccountToOrg` @@ -639,24 +676,27 @@ This api can be executed by an organization admin to add an account to an organi * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addAccountToOrg","params":["0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addAccountToOrg","params":["0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.addAccountToOrg("0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.addAccountToOrg("0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {from: eth.accounts[1]}) + "Action completed successfully" + ``` The account can at best be linked to a single organization or sub organization and cannot belong to multiple organizations or sub organizations @@ -684,24 +724,27 @@ This api can be executed by an organization admin account to assign a role to an * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_changeAccountRole","params":["0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_changeAccountRole","params":["0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.changeAccountRole("0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.changeAccountRole("0xf017976fdf1521de2e108e63b423380307f501f8", "ABC", "TRANSACT", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_updateAccountStatus` @@ -721,24 +764,27 @@ This api can be executed by an organization admin account to update the account * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateAccountStatus","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateAccountStatus","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", 1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.updateAccountStatus("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", 1, {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.updateAccountStatus("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", 1, {from: eth.accounts[1]}) + "Action completed successfully" + ``` Once a account is blacklisted it can only be recovered by network admins. Refer to [quorumPermission_recoverBlackListedAccount](#quorumpermission_recoverblacklistedaccount) @@ -760,23 +806,25 @@ Post majority approval from network admin accounts, the blacklisted account will * `msg`: response message * `status`: `bool` indicating if the operation was success or failure + === "JSON RPC" -=== "JSON RPC" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_recoverBlackListedAccount","params":["ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_recoverBlackListedAccount","params":["ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```javascript + // Response - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` -=== "geth console" + === "geth console" - ```javascript - > quorumPermission.recoverBlackListedAccount("ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + ```javascript + > quorumPermission.recoverBlackListedAccount("ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_approveBlackListedAccountRecovery` @@ -793,24 +841,27 @@ Once majority approvals from network admin accounts is received, the account is * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveBlackListedNodeRecovery","params":["ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveBlackListedNodeRecovery","params":["ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.approveBlackListedNodeRecovery("ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.approveBlackListedNodeRecovery("ABC.SUB1.SUB2.SUB3", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_assignAdminRole` @@ -828,23 +879,27 @@ org admin account for an organization. * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_assignAdminRole","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", "NWADMIN", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_assignAdminRole","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", "NWADMIN", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` -=== "geth console" + ```javascript + // Response - ```javascript - > quorumPermission.assignAdminRole("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", "NWADMIN", {from: eth.accounts[0]}) - "Action completed successfully" - ``` + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` + + === "geth console" + + ```javascript + > quorumPermission.assignAdminRole("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", "NWADMIN", {from: eth.accounts[0]}) + "Action completed successfully" + ``` ### `quorumPermission_approveAdminRole` @@ -861,24 +916,27 @@ role assignment to an account. The role is approved once majority approval is re * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveAdminRole","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveAdminRole","params":["ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.approveAdminRole("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[0]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.approveAdminRole("ABC", "0xf017976fdf1521de2e108e63b423380307f501f8", {from: eth.accounts[0]}) + "Action completed successfully" + ``` ### `quorumPermission_addNode` @@ -895,24 +953,27 @@ organization. A node cannot be part of multiple organizations. * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addNode","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_addNode","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.addNode("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.addNode("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_updateNodeStatus` @@ -932,24 +993,27 @@ This api can be executed by the organization admin account to update the status * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateNodeStatus","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407",1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_updateNodeStatus","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407",1, {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.updateNodeStatus("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407",3, {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.updateNodeStatus("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407",3, {from: eth.accounts[1]}) + "Action completed successfully" + ``` Once a node is blacklisted it can only be recovered by network admins. Refer to [quorumPermission_recoverBlackListedNode](#quorumpermission_recoverblacklistednode) @@ -971,24 +1035,27 @@ Post majority approval from network admin accounts, the blacklisted node will be * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_recoverBlackListedNode","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_recoverBlackListedNode","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.recoverBlackListedNode("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.recoverBlackListedNode("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ### `quorumPermission_approveBlackListedNodeRecovery` @@ -1005,24 +1072,27 @@ Once majority approvals from network admin accounts is received, the node is mar * `msg`: response message * `status`: `bool` indicating if the operation was success or failure -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveBlackListedNodeRecovery","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ```bash + // Request + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPermission_approveBlackListedNodeRecovery","params":["ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d"}],"id":10}' --header "Content-Type: application/json" + ``` - // Response - {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} - ``` + ```javascript + // Response -=== "geth console" + {"jsonrpc":"2.0","id":10,"result":"Action completed successfully"} + ``` - ```javascript - > quorumPermission.approveBlackListedNodeRecovery("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) - "Action completed successfully" - ``` + === "geth console" + + ```javascript + > quorumPermission.approveBlackListedNodeRecovery("ABC.SUB1.SUB2.SUB3", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407", {from: eth.accounts[1]}) + "Action completed successfully" + ``` ## Roles diff --git a/docs/Reference/APIs/PrivacyAPI.md b/docs/Reference/APIs/PrivacyAPI.md index eb3e3977..ff2131e8 100644 --- a/docs/Reference/APIs/PrivacyAPI.md +++ b/docs/Reference/APIs/PrivacyAPI.md @@ -3,7 +3,7 @@ ## Privacy APIs -#### eth.sendTransaction +### eth.sendTransaction __To support private transactions in GoQuorum, the `web3.eth.sendTransaction(object)` API method has been modified.__ @@ -13,7 +13,7 @@ web3.eth.sendTransaction(transactionObject [, callback]) Sends a transaction to the network. -##### Parameters +#### Parameters 1. `Object` - The transaction object to send: - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. @@ -26,34 +26,33 @@ Sends a transaction to the network. - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. -2. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. +1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. -##### Returns +#### Returns `String` - The 32 Bytes transaction hash as HEX string. If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. -##### Example +!!! example -```js -// compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ -var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; - -web3.eth.sendTransaction({ - data: code, - privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] - }, - function(err, address) { - if (!err) { - console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" - } - } -}); -``` -*** + ```js + // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ + var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; -#### eth.sendRawPrivateTransaction + web3.eth.sendTransaction({ + data: code, + privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + }, + function(err, address) { + if (!err) { + console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" + } + } + }); + ``` + +### eth.sendRawPrivateTransaction __To support sending raw transactions in GoQuorum, the `web3.eth.sendRawPrivateTransaction(string, object)` API method has been created.__ @@ -65,45 +64,49 @@ Sends a pre-signed transaction. For example can be signed using: https://github. __Important:__ Before calling this API, a `storeraw` api need to be called first to Tessera. Instructions on how to do this can be found [here](https://docs.tessera.consensys.net). -##### Parameters - 1. `String` - Signed transaction data in HEX format - 2. `Object` - Private data to send +#### Parameters + +1. `String` - Signed transaction data in HEX format +1. `Object` - Private data to send - `privateFor`: `List` - When sending a private transaction, an array of the recipients' base64-encoded public keys. -3. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. +1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. + +#### Returns -##### Returns `String` - The 32 Bytes transaction hash as HEX string. If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. +!!! example + + ```js + var Tx = require('ethereumjs-tx'); + var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') + var rawTx = { + nonce: '0x00', + gasPrice: '0x09184e72a000', + gasLimit: '0x2710', + to: '0x0000000000000000000000000000000000000000', + value: '0x00', + // This data should be the hex value of the hash returned by Tessera after invoking storeraw api + data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057' + } + var tx = new Tx(rawTx); + tx.sign(privateKey); + var serializedTx = tx.serialize(); + //console.log(serializedTx.toString('hex')); + //f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f + web3.eth.sendRawPrivateTransaction('0x' + serializedTx.toString('hex'), {privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, function(err, hash) { + if (!err) + console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385" + }); + ``` + +### eth.fillTransaction -##### Example - -```js - var Tx = require('ethereumjs-tx'); - var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') - var rawTx = { - nonce: '0x00', - gasPrice: '0x09184e72a000', - gasLimit: '0x2710', - to: '0x0000000000000000000000000000000000000000', - value: '0x00', - // This data should be the hex value of the hash returned by Tessera after invoking storeraw api - data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057' - } - var tx = new Tx(rawTx); - tx.sign(privateKey); - var serializedTx = tx.serialize(); - //console.log(serializedTx.toString('hex')); - //f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f - web3.eth.sendRawPrivateTransaction('0x' + serializedTx.toString('hex'), {privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, function(err, hash) { - if (!err) - console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385" - }); -``` -#### eth.fillTransaction To support offline signing of transaction. This api fills and defaults `RLP` plus `json`. This can be used to fill and sign both public and private transactions -##### Parameters +#### Parameters + 1. `Object` - The transaction object to send: - `from`: `String` - The address for the sending account. - `to`: `String` - (optional) The destination address of the message, @@ -111,59 +114,64 @@ To support offline signing of transaction. This api fills and defaults `RLP` plu - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. -##### Returns +#### Returns + - `raw`: `RLP` encoded bytes for the passed transaction object - `tx` : transaction object -##### Example -An example of signing and sending a private transaction is as shown below. The transaction depicted below deploys a simple storage contract with an initial value of 42 -```javascript -> a = eth.fillTransaction({from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", data: "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}) -{ - raw: "0xf84d02808347b7608080b84075902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6258080", - tx: { - gas: "0x47b760", - gasPrice: "0x0", - hash: "0xc0bbb6326ebafb7b0b18cf85d7b93e73ec8ae72b1c8d043d77d7ac5fecd9ccb5", - input: "0x75902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6", - nonce: "0x2", - r: "0x0", - s: "0x0", - to: null, - v: "0x25", - value: "0x0" - } -} -``` -Once the transaction object is returned, explicitly set `tx.from` and sign the transaction. -```javascript -> a.tx.from = "0xed9d02e382b34818e88b88a309c7fe71e65f419d" -"0xed9d02e382b34818e88b88a309c7fe71e65f419d" -> a.tx.privateFor=["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] -["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] -> b = eth.signTransaction(a.tx) -{ - raw: "0xf88d02808347b7608080b84075902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d637a04ff24fa99cdf3cfbaec698857c006240aa79331432d7ddb86209ec7b0010097da071f42224ee42a35872ca13fa6ffa3f7f6e550f1edecc750cc0a3ea638bf05ed9", - tx: { - gas: "0x47b760", - gasPrice: "0x0", - hash: "0x1fa98e808d711ffadfce90c4db088057e3d5efd668883be0755f158349dc274b", - input: "0x75902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6", - nonce: "0x2", - r: "0x4ff24fa99cdf3cfbaec698857c006240aa79331432d7ddb86209ec7b0010097d", - s: "0x71f42224ee42a35872ca13fa6ffa3f7f6e550f1edecc750cc0a3ea638bf05ed9", - to: null, - v: "0x37", - value: "0x0" - } -} -``` -Call `eth.sendRawPrivateTransaction` to send the transaction to intended recipients +!!! example + An example of signing and sending a private transaction is as shown below. The transaction depicted below deploys a simple storage contract with an initial value of 42 + + ```javascript + > a = eth.fillTransaction({from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d", data: "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}) + { + raw: "0xf84d02808347b7608080b84075902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6258080", + tx: { + gas: "0x47b760", + gasPrice: "0x0", + hash: "0xc0bbb6326ebafb7b0b18cf85d7b93e73ec8ae72b1c8d043d77d7ac5fecd9ccb5", + input: "0x75902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6", + nonce: "0x2", + r: "0x0", + s: "0x0", + to: null, + v: "0x25", + value: "0x0" + } + } + ``` + + Once the transaction object is returned, explicitly set `tx.from` and sign the transaction. + + ```javascript + > a.tx.from = "0xed9d02e382b34818e88b88a309c7fe71e65f419d" + "0xed9d02e382b34818e88b88a309c7fe71e65f419d" + > a.tx.privateFor=["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + > b = eth.signTransaction(a.tx) + { + raw: "0xf88d02808347b7608080b84075902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d637a04ff24fa99cdf3cfbaec698857c006240aa79331432d7ddb86209ec7b0010097da071f42224ee42a35872ca13fa6ffa3f7f6e550f1edecc750cc0a3ea638bf05ed9", + tx: { + gas: "0x47b760", + gasPrice: "0x0", + hash: "0x1fa98e808d711ffadfce90c4db088057e3d5efd668883be0755f158349dc274b", + input: "0x75902a24f8f3248a8c6d342506f018b2ef735bca0badecbaf7dc98b5799b3c8db4cc65f1a9294f29f018ce603cf93a212ebdde4a8f2d83d44a98eb97ffa690d6", + nonce: "0x2", + r: "0x4ff24fa99cdf3cfbaec698857c006240aa79331432d7ddb86209ec7b0010097d", + s: "0x71f42224ee42a35872ca13fa6ffa3f7f6e550f1edecc750cc0a3ea638bf05ed9", + to: null, + v: "0x37", + value: "0x0" + } + } + ``` -```javascript -> eth.sendRawPrivateTransaction(b.raw, {privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}) -"0xcd8ab3f6dbdb8535a44d47df9c7d8a3862fe9fb4257a2d377bdd8bface016928" -``` + Call `eth.sendRawPrivateTransaction` to send the transaction to intended recipients + + ```javascript + > eth.sendRawPrivateTransaction(b.raw, {privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}) + "0xcd8ab3f6dbdb8535a44d47df9c7d8a3862fe9fb4257a2d377bdd8bface016928" + ``` ## JSON RPC Privacy API Reference @@ -171,101 +179,115 @@ Call `eth.sendRawPrivateTransaction` to send the transaction to intended recipie __In addition to the JSON-RPC provided by Ethereum, GoQuorum exposes below two API calls.__ -#### eth_storageRoot +### eth_storageRoot Returns the storage root of given address (Contract/Account etc) -##### Parameters +#### Parameters 1. `address`: `String` - The address to fetch the storage root for in hex -2. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. +1. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. -##### Returns +#### Returns `String` - 32 Bytes storageroot hash as HEX string at latest block height. When blocknumber is given, it provides the storageroot hash at that block height. -##### Example +!!! example -```js -// Request + === "Request" -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17"], "id": 67}' + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17"], "id": 67}' + ``` -// Response -{ - "id":67, - "jsonrpc": "2.0", - "result": "0x81d1fa699f807735499cf6f7df860797cf66f6a66b565cfcda3fae3521eb6861" -} + === "Response" -``` + ```json + { + "id":67, + "jsonrpc": "2.0", + "result": "0x81d1fa699f807735499cf6f7df860797cf66f6a66b565cfcda3fae3521eb6861" + } + ``` -```js -// When block number is provided... -// Request + **When block number is provided** -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17","0x1"], "id": 67}' + === "Request" -// Response -{ - "id":67, - "jsonrpc": "2.0", - "result": "0x81d1fa699f807735499cf6f7df860797cf66f6a66b565cfcda3fae3521eb6861" -} + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17","0x1"], "id": 67}' + ``` -// After private state of the contract is changed from '42' to '99' -// Request + === "Response" -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17", "0x2"], "id": 67}' + ```json + { + "id":67, + "jsonrpc": "2.0", + "result": "0x81d1fa699f807735499cf6f7df860797cf66f6a66b565cfcda3fae3521eb6861" + } + ``` -// Response -{ - "id":67, - "jsonrpc": "2.0", - "result": "0x0edb0e520c35df37a0d080d5245c9b8f9e1f9d7efab77c067d1e12c0a71299da" -} -``` + **After private state of the contract is changed from '42' to '99'** + + === "Request" + + ```bash + + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17", "0x2"], "id": 67}' + ``` -*** + === "Response" -#### eth_getQuorumPayload + ```json + { + "id":67, + "jsonrpc": "2.0", + "result": "0x0edb0e520c35df37a0d080d5245c9b8f9e1f9d7efab77c067d1e12c0a71299da" + } + ``` + +### eth_getQuorumPayload Returns the unencrypted payload from Tessera/constellation -##### Parameters +#### Parameters 1. `id`: `String` - the HEX formatted generated Sha3-512 hash of the encrypted payload from the Private Transaction Manager. This is seen in the transaction as the `input` field -##### Returns +#### Returns `String` - unencrypted transaction payload in HEX format. -##### Example +!!! example -```js -// Request - -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQuorumPayload", "params":["0x5e902fa2af51b186468df6ffc21fd2c26235f4959bf900fc48c17dc1774d86d046c0e466230225845ddf2cf98f23ede5221c935aac27476e77b16604024bade0"], "id":67}' - -// Response -{ - "id":67, - "jsonrpc": "2.0", - "result": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a" -} - -// On a node which is not party to the transaction -// Response -{ - "id":67, - "jsonrpc": "2.0", - "result": "0x" -} -``` + === "Request" + + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQuorumPayload", "params":["0x5e902fa2af51b186468df6ffc21fd2c26235f4959bf900fc48c17dc1774d86d046c0e466230225845ddf2cf98f23ede5221c935aac27476e77b16604024bade0"], "id":67}' + ``` + + === "Response" + + ```json + { + "id":67, + "jsonrpc": "2.0", + "result": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a" + } + ``` -*** + === "Response for a node not a party to the transaction" -#### eth_sendTransactionAsync + ```json + { + "id":67, + "jsonrpc": "2.0", + "result": "0x" + } + ``` + +### eth_sendTransactionAsync Sends a transaction to the network asynchronously. This will return immediately, potentially before the transaction has been submitted to the @@ -273,7 +295,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ submitting the transaction; a server must be set up to receive POST requests at the given URL. -##### Parameters +#### Parameters 1. `Object` - The transaction object to send: - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. @@ -288,85 +310,105 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction -##### Returns +#### Returns 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` The callback URL receives the following object: - 2. `Object` - The result object: + 1. `Object` - The result object: - `id`: `String` - the identifier in the original RPC call, used to match this result to the request - `txHash`: `String` - the transaction hash that was generated, if successful - `error`: `String` - the error that occurred whilst submitting the transaction. If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. -##### Example +!!! example -For the RPC call and the immediate response: + **For the RPC call and the immediate response:** -``` -// Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' - -// Response -{ - "id": 67, - "jsonrpc": "2.0", - "result": "0x0000000000000000000000000000000000000000000000000000000000000000" -} - - -// Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' - -//If a syntactic error occured with the RPC call. -//In this example the wallet address is the wrong length -//so the error is it cannot convert the parameter to the correct type -//it is NOT an error relating the the address not being managed by this node. - -//Response -{ - "id": 67, - "jsonrpc": "2.0", - "error": { - "code": -32602, - "message": "invalid argument 0: json: cannot unmarshal hex string of odd length into Go struct field AsyncSendTxArgs.from of type common.Address" - } -} -``` + === "Request" -If the callback URL is provided, the following response will be received after -the transaction has been submitted; this example assumes a webserver that can -be accessed by calling http://localhost:8080 has been set up to accept POST -requests: + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + ``` -``` + === "Response" + ```json + { + "id": 67, + "jsonrpc": "2.0", + "result": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` -// Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="], "callbackUrl": "http://localhost:8080"}], "id":67}' + **If a syntactic error occured with the RPC call.** -// Response -//Note that the ID is the same in the callback as the request - this can be used to match the request to the response. -{ - "id": 67, - "txHash": "0x75ebbf4fbe29355fc8a4b8d1e14ecddf0228b64ef41e6d2fce56047650e2bf17" -} + === "Wrong request" + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + ``` + In this example the wallet address is the wrong length + so the error is it cannot convert the parameter to the correct type + it is NOT an error relating the the address not being managed by this node. + === "Error response" -// Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + ```json + { + "id": 67, + "jsonrpc": "2.0", + "error": { + "code": -32602, + "message": "invalid argument 0: json: cannot unmarshal hex string of odd length into Go struct field AsyncSendTxArgs.from of type common.Address" + } + } + ``` -//If a semantic error occured with the RPC call. -//In this example the wallet address is not managed by the node -//So the RPC call will succeed (giving the empty hash), but the callback will show a failure + **If the callback URL is provided** -// In the callback -{ - "id": 67, - "error":"unknown account" -} -``` + the following response will be received after + the transaction has been submitted; this example assumes a webserver that can + be accessed by calling http://localhost:8080 has been set up to accept POST + requests: + + === "Request" + + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="], "callbackUrl": "http://localhost:8080"}], "id":67}' + ``` + + === "Response" + + ```json + { + "id": 67, + "txHash": "0x75ebbf4fbe29355fc8a4b8d1e14ecddf0228b64ef41e6d2fce56047650e2bf17" + } + ``` + + Note that the ID is the same in the callback as the request - this can be used to match the request to the response. + + + **If a semantic error occured with the RPC call.** + + === "Request" + + ```bash + curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + ``` + + In this example the wallet address is not managed by the node + So the RPC call will succeed (giving the empty hash), but the callback will show a failure + + === "Callback" + + ```json + { + "id": 67, + "error":"unknown account" + } + ``` diff --git a/docs/Reference/Consensus/IBFT-RPC-API.md b/docs/Reference/Consensus/IBFT-RPC-API.md index 9913f952..8a309113 100644 --- a/docs/Reference/Consensus/IBFT-RPC-API.md +++ b/docs/Reference/Consensus/IBFT-RPC-API.md @@ -2,7 +2,7 @@ ## Getting Started 1. Run Istanbul geth with `--rpcapi "istanbul"` -2. `geth attach` +1. `geth attach` ## API Reference diff --git a/docs/Reference/FAQ.md b/docs/Reference/FAQ.md index 6f76220e..4af5392d 100644 --- a/docs/Reference/FAQ.md +++ b/docs/Reference/FAQ.md @@ -9,8 +9,8 @@ GoQuorum achieves Transaction Privacy by: 1. Enabling transaction Senders to create a private transaction by marking who is privy to that transaction via the `privateFor` parameter - 2. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction - 3. Storing encrypted private data off-chain in a separate component called the Privacy Manager (provided by [Tessera](https://github.com/ConsenSys/tessera)). The Privacy Manager distributes the encrypted data to other parties that are privy to the transaction and returns the decrypted payload to those parties + 1. Replacing the payload of a private transaction with a hash of the encrypted payload, such that the original payload is not visible to participants who are not privy to the transaction + 1. Storing encrypted private data off-chain in a separate component called the Privacy Manager (provided by [Tessera](https://github.com/ConsenSys/tessera)). The Privacy Manager distributes the encrypted data to other parties that are privy to the transaction and returns the decrypted payload to those parties Please see the [Transaction and Contract Privacy](../Privacy/Overview) section for more info. diff --git a/docs/Reference/RemixPlugin/GettingStarted.md b/docs/Reference/RemixPlugin/GettingStarted.md index 6d239798..6e9d79d3 100644 --- a/docs/Reference/RemixPlugin/GettingStarted.md +++ b/docs/Reference/RemixPlugin/GettingStarted.md @@ -4,33 +4,33 @@ ![quorum_network](images/quorum_network.png) -2. Accept the permission to allow the plugin to retrieve compilation results. This allows our plugin to use the solidity compiler to get the compiled contract binary to deploy to your Quorum node. +1. Accept the permission to allow the plugin to retrieve compilation results. This allows our plugin to use the solidity compiler to get the compiled contract binary to deploy to your Quorum node. ![permission](images/permission.png) -3. The plugin should now be included in the icons on the left side. Click on the Quorum icon to show the plugin. +1. The plugin should now be included in the icons on the left side. Click on the Quorum icon to show the plugin. ![quorum_tab](images/tab_icon.png) -4. Input the Geth RPC url and hit enter. If you are currently running the quorum-examples 7nodes network, the first node's url is http://localhost:22000 +1. Input the Geth RPC url and hit enter. If you are currently running the quorum-examples 7nodes network, the first node's url is http://localhost:22000 ![geth_rpc](images/geth_rpc.png) -5. If the node is running, the plugin should now say Connected and the rest of the UI will have appeared. +1. If the node is running, the plugin should now say Connected and the rest of the UI will have appeared. ![ui_ready](images/ui_ready.png) -6. The Quorum plugin uses results from Remix's Solidity compiler, so pull up some contract code and compile it like you normally would in Remix. The plugin will automatically receive the compiled code on each new compilation. +1. The Quorum plugin uses results from Remix's Solidity compiler, so pull up some contract code and compile it like you normally would in Remix. The plugin will automatically receive the compiled code on each new compilation. -7. Once you have a contract compiled, it will automatically be selected in the Compiled Contracts dropdown. Input any constructor values and deploy. +1. Once you have a contract compiled, it will automatically be selected in the Compiled Contracts dropdown. Input any constructor values and deploy. ![deploy](images/deploy.png) -8. If successful, the contract will show up in a collapsed view under 'Deployed Contracts'. Click the caret to expand. +1. If successful, the contract will show up in a collapsed view under 'Deployed Contracts'. Click the caret to expand. ![contract_collapsed](images/contract_collapsed.png) -9. From here you can call methods on the contract. +1. From here you can call methods on the contract. ![method_call](images/method_call.png) diff --git a/docs/Tutorials/CreatePermissionedNetwork.md b/docs/Tutorials/CreatePermissionedNetwork.md index c4f7e883..681b119a 100644 --- a/docs/Tutorials/CreatePermissionedNetwork.md +++ b/docs/Tutorials/CreatePermissionedNetwork.md @@ -45,7 +45,7 @@ other peers in the network. You will first need to generate a bootnode key: bootnode -genkey tmp_file.txt // this will start a bootnode with an enode address and generate a key inside a “tmp_file.txt” file` ``` -2. To later restart the bootnode using the same key (and hence use the same enode url): +1. To later restart the bootnode using the same key (and hence use the same enode url): ``` bash bootnode -nodekey tmp_file.txt diff --git a/docs/Tutorials/Creating-A-Network-From-Scratch.md b/docs/Tutorials/Creating-A-Network-From-Scratch.md index bbb764c0..0edb1cc7 100644 --- a/docs/Tutorials/Creating-A-Network-From-Scratch.md +++ b/docs/Tutorials/Creating-A-Network-From-Scratch.md @@ -12,21 +12,21 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. On each machine build GoQuorum as described in the [Installing](../HowTo/GetStarted/Install.md) section. Ensure that PATH contains geth and bootnode ``` - $ git clone https://github.com/ConsenSys/quorum.git - $ cd quorum - $ make all - $ export PATH=$(pwd)/build/bin:$PATH + git clone https://github.com/ConsenSys/quorum.git + cd quorum + make all + export PATH=$(pwd)/build/bin:$PATH ``` -2. Create a working directory which will be the base for the new node(s) and change into it +1. Create a working directory which will be the base for the new node(s) and change into it ``` - $ mkdir fromscratch - $ cd fromscratch - $ mkdir new-node-1 + mkdir fromscratch + cd fromscratch + mkdir new-node-1 ``` -3. Generate one or more accounts for this node and take down the account address. A funded account may be required depending what you are trying to accomplish +1. Generate one or more accounts for this node and take down the account address. A funded account may be required depending what you are trying to accomplish ``` - $ geth --datadir new-node-1 account new + geth --datadir new-node-1 account new INFO [06-07|14:52:18.742] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. @@ -36,16 +36,16 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Please note the keystore file generated inside new-node-1 includes the address in the last part of its filename. - $ ls new-node-1/keystore + ls new-node-1/keystore UTC--2019-06-17T09-29-06.665107000Z--679fed8f4f3ea421689136b25073c6da7973418f ``` !!! note You could generate multiple accounts for a single node, or any number of accounts for additional nodes and pre-allocate them with funds in the genesis.json file (see below) -4. Create a `genesis.json` file see example [here](../Reference/genesis.md). The `alloc` field should be pre-populated with the account you generated at previous step +1. Create a `genesis.json` file see example [here](../Reference/genesis.md). The `alloc` field should be pre-populated with the account you generated at previous step ``` - $ vim genesis.json + vim genesis.json ... alloc holds 'optional' accounts with a pre-funded amounts. In this example we are funding the accounts 679fed8f4f3ea421689136b25073c6da7973418f (generated from the step above) and c5c7b431e1629fb992eb18a79559f667228cd055. { "alloc": { @@ -79,29 +79,29 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "timestamp": "0x00" } ``` -5. Generate node key and copy it into datadir +1. Generate node key and copy it into datadir ``` - $ bootnode --genkey=nodekey - $ cp nodekey new-node-1/ + bootnode --genkey=nodekey + cp nodekey new-node-1/ ``` -6. Execute below command to display enode id of the new node +1. Execute below command to display enode id of the new node ``` - $ bootnode --nodekey=new-node-1/nodekey --writeaddress > new-node-1/enode - $ cat new-node-1/enode + bootnode --nodekey=new-node-1/nodekey --writeaddress > new-node-1/enode + cat new-node-1/enode '70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8' ``` -7. Create a file called `static-nodes.json` and edit it to match this [example](permissioned-nodes.md). Your file should contain a single line for your node with your enode's id and the ports you are going to use for devp2p and raft. Ensure that this file is in your nodes data directory +1. Create a file called `static-nodes.json` and edit it to match this [example](permissioned-nodes.md). Your file should contain a single line for your node with your enode's id and the ports you are going to use for devp2p and raft. Ensure that this file is in your nodes data directory ``` - $ vim static-nodes.json + vim static-nodes.json .... paste below lines with enode generated in previous step, port 21000;IP 127.0.0.1 and raft port set as 50000 [ "enode://70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8@127.0.0.1:21000?discport=0&raftport=50000" ] - $ cp static-nodes.json new-node-1 + cp static-nodes.json new-node-1 ``` -8. Initialize new node with below command. +1. Initialize new node with below command. ``` - $ geth --datadir new-node-1 init genesis.json + geth --datadir new-node-1 init genesis.json INFO [06-07|15:45:17.508] Maximum peer count ETH=25 LES=0 total=25 INFO [06-07|15:45:17.516] Allocated cache and file handles database=/Users/krish/new-node-1/geth/chaindata cache=16 handles=16 @@ -113,15 +113,15 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co INFO [06-07|15:45:17.527] Persisted trie from memory database nodes=1 size=152.00B time=60.76µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-07|15:45:17.527] Successfully wrote genesis state database=lightchaindata hash=ec0542…9665bf ``` -9. Start your node by first creating a script as below and then starting it: +1. Start your node by first creating a script as below and then starting it: ``` - $ vim startnode1.sh + vim startnode1.sh ... paste below commands. It will start it in the background. #!/bin/bash PRIVATE_CONFIG=ignore nohup geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21000 >> node.log 2>&1 & - $ chmod +x startnode1.sh - $ ./startnode1.sh + chmod +x startnode1.sh + ./startnode1.sh ``` !!! note @@ -129,7 +129,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Your node is now operational and you may attach to it with below commands. ``` - $ geth attach new-node-1/geth.ipc + geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 @@ -158,20 +158,20 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. Complete steps 1, 2, 5, and 6 from the previous guide ``` - $ mkdir new-node-2 - $ bootnode --genkey=nodekey2 - $ cp nodekey2 new-node-2/nodekey - $ bootnode --nodekey=new-node-2/nodekey --writeaddress + mkdir new-node-2 + bootnode --genkey=nodekey2 + cp nodekey2 new-node-2/nodekey + bootnode --nodekey=new-node-2/nodekey --writeaddress 56e81550db3ccbfb5eb69c0cfe3f4a7135c931a1bae79ea69a1a1c6092cdcbea4c76a556c3af977756f95d8bf9d7b38ab50ae070da390d3abb3d7e773099c1a9 ``` -2. Retrieve current chains `genesis.json` and `static-nodes.json`. `static-nodes.json` should be placed into new nodes data dir +1. Retrieve current chains `genesis.json` and `static-nodes.json`. `static-nodes.json` should be placed into new nodes data dir ``` - $ cp static-nodes.json new-node-2 + cp static-nodes.json new-node-2 ``` -3. Edit `static-nodes.json` and add new entry for the new node you are configuring (should be last) +1. Edit `static-nodes.json` and add new entry for the new node you are configuring (should be last) ``` - $ vim new-node-2/static-nodes.json + vim new-node-2/static-nodes.json .... append new-node-2's enode generated in step 1, port 21001;IP 127.0.0.1 and raft port set as 50001 [ @@ -180,10 +180,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ] ``` -4. Initialize new node as given below: +1. Initialize new node as given below: ``` - $ geth --datadir new-node-2 init genesis.json + geth --datadir new-node-2 init genesis.json INFO [06-07|16:34:39.805] Maximum peer count ETH=25 LES=0 total=25 INFO [06-07|16:34:39.814] Allocated cache and file handles database=/Users/krish/fromscratch/new-node-2/geth/chaindata cache=16 handles=16 @@ -196,9 +196,9 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co INFO [06-07|16:34:39.819] Successfully wrote genesis state database=lightchaindata hash=f02d0b…ed214a ``` -5. Connect to an already running node of the chain and execute raft `addPeer` command. +1. Connect to an already running node of the chain and execute raft `addPeer` command. ``` - $ geth attach new-node-1/geth.ipc + geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 @@ -225,30 +225,30 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co }] > exit ``` -6. Start your node by first creating a script as previous step and changing the ports you are going to use for Devp2p and raft. +1. Start your node by first creating a script as previous step and changing the ports you are going to use for Devp2p and raft. ``` - $ cp startnode1.sh startnode2.sh - $ vim startnode2.sh + cp startnode1.sh startnode2.sh + vim startnode2.sh ..... paste below details #!/bin/bash PRIVATE_CONFIG=ignore nohup geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,raft --emitcheckpoints --port 21001 2>>node2.log & - $ ./startnode2.sh + ./startnode2.sh ``` -7. Optional: share new `static-nodes.json` with all other chain participants +1. Optional: share new `static-nodes.json` with all other chain participants ``` - $ cp new-node-2/static-nodes.json new-node-1 + cp new-node-2/static-nodes.json new-node-1 ``` Your additional node is now operational and is part of the same chain as the previously set up node. ### Removing node 1. Connect to an already running node of the chain and execute `raft.cluster` and get the `RAFT_ID` corresponding to the node that needs to be removed -2. Run `raft.removePeer(RAFT_ID)` -3. Stop the `geth` process corresponding to the node that was removed. +1. Run `raft.removePeer(RAFT_ID)` +1. Stop the `geth` process corresponding to the node that was removed. ``` - $ geth attach new-node-1/geth.ipc + geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 @@ -283,18 +283,18 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co raftPort: 50000 }] > exit - $ - $ - $ ps | grep geth + + + ps | grep geth PID TTY TIME CMD 10554 ttys000 0:00.01 -bash 9125 ttys002 0:00.50 -bash 10695 ttys002 0:31.42 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpoo 10750 ttys002 0:01.94 geth --datadir new-node-2 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50001 --raftjoinexisting 2 --rpc --rpcaddr 0.0.0.0 --rpcport 22001 --rpcapi admin,db,eth,debu - $ kill 10750 - $ - $ - $ ps + kill 10750 + + + ps PID TTY TIME CMD 10554 ttys000 0:00.01 -bash 9125 ttys002 0:00.51 -bash @@ -307,27 +307,27 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. On each machine build GoQuorum as described in the [Installing](../HowTo/GetStarted/Install.md) section. Ensure that PATH contains geth and boot node ``` - $ git clone https://github.com/ConsenSys/quorum.git - $ cd quorum - $ make all - $ export PATH=$(pwd)/build/bin:$PATH + git clone https://github.com/ConsenSys/quorum.git + cd quorum + make all + export PATH=$(pwd)/build/bin:$PATH ``` -2. Install [istanbul-tools](https://github.com/ConsenSys/istanbul-tools) +1. Install [istanbul-tools](https://github.com/ConsenSys/istanbul-tools) ``` - $ mkdir fromscratchistanbul - $ cd fromscratchistanbul - $ git clone https://github.com/ConsenSys/istanbul-tools.git - $ cd istanbul-tools - $ make + mkdir fromscratchistanbul + cd fromscratchistanbul + git clone https://github.com/ConsenSys/istanbul-tools.git + cd istanbul-tools + make ``` -3. Create a working directory for each of the X number of initial validator nodes +1. Create a working directory for each of the X number of initial validator nodes ``` - $ mkdir node0 node1 node2 node3 node4 + mkdir node0 node1 node2 node3 node4 ``` -4. Change into the lead (whichever one you consider first) node's working directory and generate the setup files for X initial validator nodes by executing `istanbul setup --num X --nodes --quorum --save --verbose` **only execute this instruction once, i.e. not X times**. This command will generate several items of interest: `static-nodes.json`, `genesis.json`, and nodekeys for all the initial validator nodes which will sit in numbered directories from 0 to X-1 +1. Change into the lead (whichever one you consider first) node's working directory and generate the setup files for X initial validator nodes by executing `istanbul setup --num X --nodes --quorum --save --verbose` **only execute this instruction once, i.e. not X times**. This command will generate several items of interest: `static-nodes.json`, `genesis.json`, and nodekeys for all the initial validator nodes which will sit in numbered directories from 0 to X-1 ``` - $ cd node0 - $ ../istanbul-tools/build/bin/istanbul setup --num 5 --nodes --quorum --save --verbose + cd node0 + ../istanbul-tools/build/bin/istanbul setup --num 5 --nodes --quorum --save --verbose validators { "Address": "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", @@ -411,7 +411,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" } - $ ls -l + ls -l total 16 drwxr-xr-x 9 krish staff 288 11 Jun 16:00 . drwxr-xr-x 8 krish staff 256 11 Jun 15:58 .. @@ -424,9 +424,9 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co -rwxr-xr-x 1 krish staff 832 11 Jun 16:00 static-nodes.json ``` -5. Update `static-nodes.json` to include the intended IP and port numbers of all initial validator nodes. In `static-nodes.json`, you will see a different row for each node. For the rest of the installation guide, row Y refers to node Y and row 1 is assumed to correspond to the lead node +1. Update `static-nodes.json` to include the intended IP and port numbers of all initial validator nodes. In `static-nodes.json`, you will see a different row for each node. For the rest of the installation guide, row Y refers to node Y and row 1 is assumed to correspond to the lead node ``` - $ cat static-nodes.json + cat static-nodes.json .... update the IP and port numbers as give below... [ "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@127.0.0.1:30300?discport=0", @@ -436,39 +436,39 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@127.0.0.1:30304?discport=0" ] ``` -6. In each node's working directory, create a data directory called `data`, and inside `data` create the `geth` directory +1. In each node's working directory, create a data directory called `data`, and inside `data` create the `geth` directory ``` - $ cd .. - $ mkdir -p node0/data/geth - $ mkdir -p node1/data/geth - $ mkdir -p node2/data/geth - $ mkdir -p node3/data/geth - $ mkdir -p node4/data/geth + cd .. + mkdir -p node0/data/geth + mkdir -p node1/data/geth + mkdir -p node2/data/geth + mkdir -p node3/data/geth + mkdir -p node4/data/geth ``` -7. Now we will generate initial accounts for any of the nodes in the required node's working directory. The resulting public account address printed in the terminal should be recorded. Repeat as many times as necessary. A set of funded accounts may be required depending what you are trying to accomplish +1. Now we will generate initial accounts for any of the nodes in the required node's working directory. The resulting public account address printed in the terminal should be recorded. Repeat as many times as necessary. A set of funded accounts may be required depending what you are trying to accomplish ``` - $ geth --datadir node0/data account new + geth --datadir node0/data account new INFO [06-11|16:05:53.672] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase: Repeat passphrase: Address: {8fc817d90f179b0b627c2ecbcc1d1b0fcd13ddbd} - $ geth --datadir node1/data account new + geth --datadir node1/data account new INFO [06-11|16:06:34.529] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase: Repeat passphrase: Address: {dce8adeef16a45d94be5e7804df6d35db834d94a} - $ geth --datadir node2/data account new + geth --datadir node2/data account new INFO [06-11|16:06:54.365] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase: Repeat passphrase: Address: {65a3ab6d4cf23395f544833831fc5d42a0b2b43a} ``` -8. To add accounts to the initial block, edit the `genesis.json` file in the lead node's working directory and update the `alloc` field with the account(s) that were generated at previous step +1. To add accounts to the initial block, edit the `genesis.json` file in the lead node's working directory and update the `alloc` field with the account(s) that were generated at previous step ``` - $ vim node0/genesis.json + vim node0/genesis.json .... update the accounts under 'alloc' { "config": { @@ -507,27 +507,27 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" } ``` -9. Next we need to distribute the files created in part 4, which currently reside in the lead node's working directory, to all other nodes. To do so, place `genesis.json` in the working directory of all nodes, place `static-nodes.json` in the data folder of each node and place `X/nodekey` in node (X-1)'s `data/geth` directory - ``` - $ cp node0/genesis.json node1 - $ cp node0/genesis.json node2 - $ cp node0/genesis.json node3 - $ cp node0/genesis.json node4 - $ cp node0/static-nodes.json node0/data/ - $ cp node0/static-nodes.json node1/data/ - $ cp node0/static-nodes.json node2/data/ - $ cp node0/static-nodes.json node3/data/ - $ cp node0/static-nodes.json node4/data/ - $ cp node0/0/nodekey node0/data/geth - $ cp node0/1/nodekey node1/data/geth - $ cp node0/2/nodekey node2/data/geth - $ cp node0/3/nodekey node3/data/geth - $ cp node0/4/nodekey node4/data/geth +1. Next we need to distribute the files created in part 4, which currently reside in the lead node's working directory, to all other nodes. To do so, place `genesis.json` in the working directory of all nodes, place `static-nodes.json` in the data folder of each node and place `X/nodekey` in node (X-1)'s `data/geth` directory + ``` + cp node0/genesis.json node1 + cp node0/genesis.json node2 + cp node0/genesis.json node3 + cp node0/genesis.json node4 + cp node0/static-nodes.json node0/data/ + cp node0/static-nodes.json node1/data/ + cp node0/static-nodes.json node2/data/ + cp node0/static-nodes.json node3/data/ + cp node0/static-nodes.json node4/data/ + cp node0/0/nodekey node0/data/geth + cp node0/1/nodekey node1/data/geth + cp node0/2/nodekey node2/data/geth + cp node0/3/nodekey node3/data/geth + cp node0/4/nodekey node4/data/geth ``` 10. Switch into working directory of lead node and initialize it. Repeat for every working directory X created in step 3. *The resulting hash given by executing `geth init` must match for every node* ``` - $ cd node0 - $ geth --datadir data init genesis.json + cd node0 + geth --datadir data init genesis.json INFO [06-11|16:14:11.883] Maximum peer count ETH=25 LES=0 total=25 INFO [06-11|16:14:11.894] Allocated cache and file handles database=/Users/krish/fromscratchistanbul/node0/data/geth/chaindata cache=16 handles=16 INFO [06-11|16:14:11.896] Writing custom genesis block @@ -537,7 +537,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co INFO [06-11|16:14:11.898] Writing custom genesis block INFO [06-11|16:14:11.898] Persisted trie from memory database nodes=6 size=1.01kB time=54.929µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-11|16:14:11.898] Successfully wrote genesis state database=lightchaindata hash=b992be…533db7 - $ + $ cd .. $ cd node1 $ geth --datadir data init genesis.json @@ -640,7 +640,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` $ mkdir node5 ``` -2. Change into the working directory for the new node and run `istanbul setup --num 1 --verbose --quorum --save`. This will generate the validator details including Address, NodeInfo and genesis.json +1. Change into the working directory for the new node and run `istanbul setup --num 1 --verbose --quorum --save`. This will generate the validator details including Address, NodeInfo and genesis.json ``` $ cd node5 $ ../istanbul-tools/build/bin/istanbul setup --num 1 --verbose --quorum --save @@ -686,7 +686,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co } ``` -3. Copy the address of the validator and run `istanbul.propose(
, true)` from more than half the number of current validators. +1. Copy the address of the validator and run `istanbul.propose(
, true)` from more than half the number of current validators. ``` $ cd .. $ geth attach node0/data/geth.ipc @@ -743,20 +743,20 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",true) ``` -4. Verify that the new validator has been added to the list of validators by running `istanbul.getValidators()` +1. Verify that the new validator has been added to the list of validators by running `istanbul.getValidators()` ``` ... you can see below command now displays 6 node address as validators. > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` -5. Copy `static-nodes.json` and genesis.json from the existing chain. `static-nodes.json` should be placed into new nodes data dir +1. Copy `static-nodes.json` and genesis.json from the existing chain. `static-nodes.json` should be placed into new nodes data dir ``` $ cd node5 $ mkdir -p data/geth $ cp ../node0/static-nodes.json data $ cp ../node0/genesis.json . ``` -6. Edit `static-nodes.json` and add the new validators node info to the end of the file. New validators node info can be got from the output of `istanbul setup --num 1 --verbose --quorum --save` command that was run in step 2. Update the IP address and port of the node info to match the IP address of the validator and port you want to use. +1. Edit `static-nodes.json` and add the new validators node info to the end of the file. New validators node info can be got from the output of `istanbul setup --num 1 --verbose --quorum --save` command that was run in step 2. Update the IP address and port of the node info to match the IP address of the validator and port you want to use. ``` $ vim data/static-nodes.json ...add new validate nodes details with correct IP and port details @@ -770,11 +770,11 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ] ``` -7. Copy the nodekey that was generated by `istanbul setup` command to the `geth` directory inside the working directory +1. Copy the nodekey that was generated by `istanbul setup` command to the `geth` directory inside the working directory ``` $ cp 0/nodekey data/geth ``` -8. Generate one or more accounts for this node and take down the account address. +1. Generate one or more accounts for this node and take down the account address. ``` $ geth --datadir data account new INFO [06-12|17:45:11.116] Maximum peer count ETH=25 LES=0 total=25 @@ -783,7 +783,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Repeat passphrase: Address: {37922bce824bca2f3206ea53dd50d173b368b572} ``` -9. Initialize new node with below command +1. Initialize new node with below command ``` $ geth --datadir data init genesis.json INFO [06-11|16:42:27.120] Maximum peer count ETH=25 LES=0 total=25 @@ -839,7 +839,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` -2. Run `istanbul.propose(
, false)` by passing the address of the validator that needs to be removed from more than half current validators +1. Run `istanbul.propose(
, false)` by passing the address of the validator that needs to be removed from more than half current validators ``` > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) null @@ -877,12 +877,12 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) null ``` -3. Verify that the validator has been removed by running `istanbul.getValidators()` +1. Verify that the validator has been removed by running `istanbul.getValidators()` ``` > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` -4. Stop the `geth` process corresponding to the validator that was removed. +1. Stop the `geth` process corresponding to the validator that was removed. ``` $ ps PID TTY TIME CMD @@ -924,7 +924,7 @@ Just execute **step 4** instruction from removing a validator node. $ mv tessera-app-0.9.2-app.jar tessera.jar ``` -2. Generate new keys using `java -jar /path-to-tessera/tessera.jar -keygen -filename new-node-1` +1. Generate new keys using `java -jar /path-to-tessera/tessera.jar -keygen -filename new-node-1` ``` $ mkdir new-node-1t $ cd new-node-1t @@ -938,7 +938,7 @@ Just execute **step 4** instruction from removing a validator node. 10:32:51.624 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved public key to /Users/krish/fromscratch/new-node-1t/new-node-1.pub 10:32:51.624 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved private key to /Users/krish/fromscratch/new-node-1t/new-node-1.key ``` -3. Create new configuration file with newly generated keys referenced. Name it `config.json` as done in this example +1. Create new configuration file with newly generated keys referenced. Name it `config.json` as done in this example ``` vim config.json { @@ -993,7 +993,7 @@ Just execute **step 4** instruction from removing a validator node. } ``` -4. If you want to start another Tessera node, please repeat step 2 & step 3 +1. If you want to start another Tessera node, please repeat step 2 & step 3 ``` $ cd .. $ mkdir new-node-2t @@ -1063,7 +1063,7 @@ Just execute **step 4** instruction from removing a validator node. } ``` -5. Start your Tessera nodes and send then into background +1. Start your Tessera nodes and send then into background ``` $ java -jar ../tessera.jar -configfile config.json >> tessera.log 2>&1 & [1] 38064 @@ -1080,7 +1080,7 @@ Just execute **step 4** instruction from removing a validator node. 38076 ttys002 1:15.86 /usr/bin/java -jar ../tessera.jar -configfile config.json ``` -6. Start GoQuorum nodes attached to running Tessera nodes from above and send it to background +1. Start GoQuorum nodes attached to running Tessera nodes from above and send it to background ``` ... update the start scripts to include PRIVATE_CONFIG $cd .. From 2be342636a77d0ec2594bbd22c9b45f7a5042105 Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Tue, 22 Sep 2020 11:12:45 +0200 Subject: [PATCH 4/9] vale pass - fix vale issues - add a specific config to exclude generated interface doc --- .circleci/config.yml | 6 +++- .circleci/vale.ini | 4 +++ .gitignore | 3 +- common | 2 +- docs/Concepts/AccountManagement.md | 2 +- docs/Concepts/Consensus/IBFT.md | 8 ++--- docs/Concepts/Consensus/Raft.md | 13 +++++-- .../Permissioning/Enhanced/ContractDesign.md | 2 +- docs/Concepts/Plugins/PluginsArchitecture.md | 2 -- docs/Concepts/Privacy/ContractExtension.md | 6 ++-- docs/Concepts/Privacy/Privacy.md | 2 +- docs/Concepts/Privacy/PrivateAndPublic.md | 2 +- .../Privacy/PrivateTransactionLifecycle.md | 10 +++--- .../SmartContractsSecurity.md | 4 +-- .../GoQuorumNetworkSecurity/Consortium.md | 4 +-- .../Framework/GoQuorumNetworkSecurity/Node.md | 4 +-- .../OpertionalConsiderations.md | 4 +-- docs/HowTo/Configure/Plugins.md | 2 +- docs/HowTo/Configure/dns.md | 2 +- docs/HowTo/DevelopPlugins.md | 6 ++-- docs/HowTo/GetStarted/Cakeshop.md | 6 ++-- .../GetStarted/GettingStartedOverview.md | 8 ++--- docs/HowTo/GetStarted/Install.md | 2 +- .../HowTo/GetStarted/Wizard/GettingStarted.md | 2 +- docs/HowTo/GetStarted/Wizard/Interacting.md | 16 ++++----- docs/HowTo/GetStarted/migration.md | 2 +- docs/HowTo/Logging and Errors.md | 2 +- docs/HowTo/ManageKeys/AccountPlugins.md | 6 ++-- docs/HowTo/ManageKeys/clef.md | 4 +-- docs/HowTo/Use/AddingIBFTValidators.md | 30 ++++++++-------- docs/HowTo/Use/DevelopingSmartContracts.md | 2 +- docs/HowTo/Use/JSON-RPC-API-Security.md | 2 +- docs/HowTo/Use/add_node_examples.md | 12 +++---- docs/HowTo/Use/adding_nodes.md | 14 ++++---- docs/Reference/APIs/PrivacyAPI.md | 34 +++++++++---------- docs/Reference/FAQ.md | 13 ++++--- docs/Reference/GoQuorum-Projects.md | 1 - .../Plugins/account/For-Developers.md | 2 +- .../Plugins/security/For-Developers.md | 2 +- docs/Reference/Plugins/security/For-Users.md | 1 + .../quorum.js/RawTransactionManager.md | 6 ++-- docs/Reference/quorum.js/extend.md | 2 +- .../Creating-A-Network-From-Scratch.md | 12 +++---- docs/Tutorials/permissioned-nodes.md | 4 ++- 44 files changed, 147 insertions(+), 126 deletions(-) create mode 100644 .circleci/vale.ini diff --git a/.circleci/config.yml b/.circleci/config.yml index 3485e34b..0e2497ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,10 +63,14 @@ jobs: name: Install dependencies command: | curl -sfL https://install.goreleaser.com/github.com/ValeLint/vale.sh | sh -s v1.7.1 + - run: + name: Cat config + command: | + cat ./common/build_tools/vale/.vale.ini .circleci/vale.ini > .circleci/cat-vale.ini - run: name: Run Vale command: | - ./bin/vale --config ./common/build_tools/vale/.vale.ini --glob='*.{md}' . | tee ./vale.out + ./bin/vale --config .circleci/cat-vale.ini --glob='*.{md}' . | tee ./vale.out - notify - store_artifacts: path: ./vale.out diff --git a/.circleci/vale.ini b/.circleci/vale.ini new file mode 100644 index 00000000..d60c8b82 --- /dev/null +++ b/.circleci/vale.ini @@ -0,0 +1,4 @@ +# Disable guidelines check for auto generated interfaces +[docs/Reference/Plugins/*/interface.md] +BasedOnStyles = +vale.Repetition = NO diff --git a/.gitignore b/.gitignore index d75da97c..71f796ad 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ env/ *.out node_modules/ .circleci/process.yml +.circleci/cat-vale.ini .DS_Store **/.DS_Store -*.iml \ No newline at end of file +*.iml diff --git a/common b/common index c0df5ddb..1b85aba1 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit c0df5ddb276278931e2263199514173e768c55dd +Subproject commit 1b85aba1f69903f08af315505c7d8d7704a7b64f diff --git a/docs/Concepts/AccountManagement.md b/docs/Concepts/AccountManagement.md index 71d1477a..ff555c6e 100644 --- a/docs/Concepts/AccountManagement.md +++ b/docs/Concepts/AccountManagement.md @@ -7,7 +7,7 @@ Both GoQuorum and the Privacy Manager use user-provided asymmetric key pairs. Ea of a public key and a private key. The public key can be shared freely, but **the private key should never be shared**. * GoQuorum derives the account address from the public key by taking the last 20 bytes of its keccak256 hash -* The Privacy Manager uses the public key as an identifier for the target nodes of a private transaction (i.e. the `privateFor` transaction field) +* The Privacy Manager uses the public key as an identifier for the target nodes of a private transaction (that is the `privateFor` transaction field) Key management determines how [GoQuorum](../HowTo/ManageKeys/ManagingKeys.md) and [Tessera](https://docs.tessera.consensys.net) store and use private keys. diff --git a/docs/Concepts/Consensus/IBFT.md b/docs/Concepts/Consensus/IBFT.md index 4b40ca0a..b6497847 100644 --- a/docs/Concepts/Consensus/IBFT.md +++ b/docs/Concepts/Consensus/IBFT.md @@ -28,7 +28,7 @@ IBFT inherits from the original PBFT by using a 3-phase consensus, `PRE-PREPARE` Istanbul BFT Consensus protocol begins at Round `0` with the validators picking a proposer from themselves in a round robin fashion. The proposer will then propose a new block proposal and broadcast it along with the `PRE-PREPARE` message. Upon receiving the `PRE-PREPARE` message from the proposer, other validators validate the incoming proposal and enter the state of `PRE-PREPARED` and broadcast `PREPARE` message. This step is to make sure all validators are working on the same sequence and on the same round. When `ceil(2N/3)` of `PREPARE` messages is received by the validator from other validators, the validator switches to the state of `PREPARED` and broadcasts `COMMIT` message. This step is to inform other validators that it accepts the proposed block and is going to insert the block to the chain. Lastly, validators wait for `ceil(2N/3)` of `COMMIT` messages to enter `COMMITTED` state and then append the block to the chain. -Blocks in Istanbul BFT protocol are final, which means that there are no forks and any valid block must be somewhere in the main chain. To prevent a faulty node from generating a totally different chain from the main chain, each validator appends `ceil(2N/3)` of received `COMMIT` signatures to `extraData` field in the header before inserting it into the chain. Thus all blocks are self-verifiable. However, the dynamic `extraData` would cause an issue on block hash calculation. Since the same block from different validators can have different set of `COMMIT` signatures, the same block can have different block hashes as well. To solve this, we calculate the block hash by excluding the `COMMIT` signatures part. Therefore, we can still keep the block/block hash consistency as well as put the consensus proof in the block header. +Blocks in Istanbul BFT protocol are final, which means that there are no forks and any valid block must be somewhere in the main chain. To prevent a faulty node from generating a totally different chain from the main chain, each validator appends `ceil(2N/3)` of received `COMMIT` signatures to `extraData` field in the header before inserting it into the chain. Thus all blocks are self-verifiable. However, the dynamic `extraData` would cause an issue on block hash calculation. Since the same block from different validators can have different set of `COMMIT` signatures, the same block can have different block hashes as well. To solve this, we calculate the block hash by excluding the `COMMIT` signatures part. Therefore, we can still keep the block/block hash consistency and put the consensus proof in the block header. #### Consensus States @@ -72,7 +72,7 @@ Istanbul BFT is a state machine replication algorithm. Each validator maintains #### Round change flow -- There are three conditions that would trigger `ROUND CHANGE`: +- Three conditions can trigger `ROUND CHANGE`: - Round change timer expires. - Invalid `PREPREPARE` message. - Block insertion fails. @@ -101,7 +101,7 @@ For all transactions blocks: - Votes are tallied live as the chain progresses (concurrent proposals allowed). - Proposals reaching majority consensus `VALIDATOR_LIMIT` come into effect immediately. - Invalid proposals are not to be penalized for client implementation simplicity. -- A proposal coming into effect entails discarding all pending votes for that proposal (both for and against) and starts with a clean slate. +- A proposal coming into effect entails discarding all pending votes for that proposal (both for and against). #### Future message and backlog @@ -118,7 +118,7 @@ Istanbul BFT define the following constants - `ISTANBUL_DIGEST`: Fixed magic number `0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365` of `mixDigest` in block header for Istanbul block identification. - `DEFAULT_DIFFICULTY`: Default block difficulty, which is set to `0x0000000000000001`. - `EXTRA_VANITY`: Fixed number of extra-data prefix bytes reserved for proposer vanity. - - Suggested `32` bytes to retain the current extra-data allowance and/or use. + - Suggested `32` bytes to retain the current extra-data allowance. - `NONCE_AUTH`: Magic nonce number `0xffffffffffffffff` to vote on adding a validator. - `NONCE_DROP`: Magic nonce number `0x0000000000000000` to vote on removing a validator. - `UNCLE_HASH`: Always `Keccak256(RLP([]))` as uncles are meaningless outside of PoW. diff --git a/docs/Concepts/Consensus/Raft.md b/docs/Concepts/Consensus/Raft.md index 7958fd6c..8935c375 100644 --- a/docs/Concepts/Consensus/Raft.md +++ b/docs/Concepts/Consensus/Raft.md @@ -17,7 +17,14 @@ When the `geth` binary is passed the `--raft` flag, the node will operate in "ra Both Raft and Ethereum have their own notion of a "node": -In Raft, a node in normal operation can be a "leader", "follower" or "learner." There is a single leader for the entire cluster, through which all log entries must flow through. There's also the concept of a "candidate", but only during leader election. We won't go into more detail about Raft here, because by design these details are opaque to applications built on it. A Raft network can be started with a set of verifiers and one of them would get elected as a leader when the network starts. If the leader node dies, re-election is triggered and new leader is elected by the network. Once the network is up additional verifier nodes(peers) or learner nodes can be added to this network. Brief summary of each type of nodes is given below: +In Raft, a node in normal operation can be a "leader", "follower" or "learner". +There is a single leader for the entire cluster, through which all log entries must flow through. +There's also the concept of a "candidate", but only during leader election. +We won't go into more detail about Raft here, because by design these details are opaque to applications built on it. +A Raft network can be started with a set of verifiers and one of them would get elected as a leader when the network starts. +If the leader node dies, re-election is triggered and new leader is elected by the network. +Once the network is up additional verifier nodes(peers) or learner nodes can be added to this network. +A summary of each type of nodes is given as the following: ### Leader @@ -88,7 +95,7 @@ Let's follow the lifecycle of a typical transaction: 1. Having crossed the network through Raft, the block reaches the `eventLoop` (which processes new Raft log entries.) It has arrived from the leader through `pm.transport`, an instance of `rafthttp.Transport`. -1. The block is now handled by `applyNewChainHead`. This method checks whether the block extends the chain (i.e. it's parent is the current head of the chain; see below). If it does not extend the chain, it is simply ignored as a no-op. If it does extend chain, the block is validated and then written as the new head of the chain by [`InsertChain`](https://godoc.org/github.com/jpmorganchase/quorum/core#BlockChain.InsertChain). +1. The block is now handled by `applyNewChainHead`. This method checks whether the block extends the chain (it's parent is the current head of the chain). If it does not extend the chain, it is simply ignored as a no-op. If it does extend chain, the block is validated and then written as the new head of the chain by [`InsertChain`](https://godoc.org/github.com/jpmorganchase/quorum/core#BlockChain.InsertChain). 1. A [`ChainHeadEvent`](https://godoc.org/github.com/jpmorganchase/quorum/core#ChainHeadEvent) is posted to notify listeners that a new block has been accepted. This is relevant to us because: - It removes the relevant transaction from the transaction pool. @@ -184,7 +191,7 @@ Default number of peers is set to be 25. Max number of peers is configurable wit ## Initial configuration, and enacting membership changes -Currently Raft-based consensus requires that all _initial_ nodes in the cluster are configured to list the others up-front as [static peers](https://github.com/ethereum/go-ethereum/wiki/Connecting-to-the-network#static-nodes). These enode ID URIs _must_ include a `raftport` querystring parameter specifying the raft port for each peer: e.g. `enode://abcd@127.0.0.1:30400?raftport=50400`. Note that the order of the enodes in the `static-nodes.json` file needs to be the same across all peers. +Currently Raft-based consensus requires that all _initial_ nodes in the cluster are configured to list the others up-front as [static peers](https://github.com/ethereum/go-ethereum/wiki/Connecting-to-the-network#static-nodes). These enode ID URIs _must_ include a `raftport` querystring parameter specifying the raft port for each peer: for example, `enode://abcd@127.0.0.1:30400?raftport=50400`. Note that the order of the enodes in the `static-nodes.json` file needs to be the same across all peers. To remove a node from the cluster, attach to a JS console and issue `raft.removePeer(raftId)`, where `raftId` is the number of the node you wish to remove. For initial nodes in the cluster, this number is the 1-indexed position of the node's enode ID in the static peers list. Once a node has been removed from the cluster, it is permanent; this raft ID can not ever re-connect to the cluster in the future, and the party must re-join the cluster with a new raft ID. diff --git a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md index 7e8938ae..b20273eb 100644 --- a/docs/Concepts/Permissioning/Enhanced/ContractDesign.md +++ b/docs/Concepts/Permissioning/Enhanced/ContractDesign.md @@ -33,7 +33,7 @@ the implementation logic to change without changing the storage or interface lay If a role is revoked all accounts which are linked to the role lose all access rights * `VoterManager.sol`: This contract receives requests from a valid implementation contract as defined in `PermissionsUpgradable.sol`. - It stores the data of valid voters at network level which can approve identified activities e.g. adding a new organization to the network. + It stores the data of valid voters at network level which can approve identified activities, for example adding a new organization to the network. Any account which is linked to a predefined network admin role will be marked as a voter. Whenever a network level activity which requires voting is performed, a voting item is added to this contract and each voter account can vote for the activity. The activity is marked as `Approved` upon majority voting. diff --git a/docs/Concepts/Plugins/PluginsArchitecture.md b/docs/Concepts/Plugins/PluginsArchitecture.md index 7d52bb15..22510e81 100644 --- a/docs/Concepts/Plugins/PluginsArchitecture.md +++ b/docs/Concepts/Plugins/PluginsArchitecture.md @@ -15,8 +15,6 @@ and it has been proven in many plugin-based production systems. ## Benefits -There are number of benefits: - - Dynamically-linked binaries (which you get when using plugins) are much smaller than statically compiled binaries. - We value the ability to isolate failures. E.g.: GoQuorum client would continue mining/validating even if security plugin has crashed. - Easily enables support for open source plugins written in languages other than Go. diff --git a/docs/Concepts/Privacy/ContractExtension.md b/docs/Concepts/Privacy/ContractExtension.md index 9c1c7a77..9f07c13b 100644 --- a/docs/Concepts/Privacy/ContractExtension.md +++ b/docs/Concepts/Privacy/ContractExtension.md @@ -7,8 +7,8 @@ to set of initial participant nodes, need to be extended to a new node which has flow. Contract state extension feature addresses this requirement. It should be noted that as a part of contract state extension only the state of the contract as of the -time of extension is shared. This means that there is no past history of the contract, and attempting -to view past history will not yield any result, as the new recipient was not party at that time. This +time of extension is shared. This means that there is no history of the contract, and attempting +to view it will not yield any result, as the new recipient was not party at that time. This also means that events are not shared either, as the transactions are not shared and no state transitions are calculated. ## Flow @@ -32,7 +32,7 @@ In this example, private contract is being extended from Nodes A to Node B. - **2c & 2d** - Private transaction payload is shared with Tessera node B. Public state is propagated across all nodes 1. Since the state sharing does not execute the transactions that generate the state - (in order to keep past history private), there is no proof that can be provided by the proposer + (in order to keep history private), there is no proof that can be provided by the proposer that the state is correct. In order to remedy this, the receiver must accept the proposal for the contract as the proof. In this step, the user owning the ethereum public key of node B which was marked as receiving address, approves the contract extension using GoQuorum apis diff --git a/docs/Concepts/Privacy/Privacy.md b/docs/Concepts/Privacy/Privacy.md index 4c2dbb42..9ef97d6b 100644 --- a/docs/Concepts/Privacy/Privacy.md +++ b/docs/Concepts/Privacy/Privacy.md @@ -20,7 +20,7 @@ Tessera is restful/stateless and can be load balanced easily. Distributed ledger protocols leverage cryptographic techniques for transaction authenticity, participant authentication, and historical data preservation (that is, through a chain of cryptographically hashed data). -To achieve a separation of concerns, as well as to provide performance improvements through parallelization +To achieve a separation of concerns and to provide performance improvements through parallelization of certain crypto-operations, much of the cryptographic work including symmetric key generation and data encryption/decryption is delegated to the enclave. diff --git a/docs/Concepts/Privacy/PrivateAndPublic.md b/docs/Concepts/Privacy/PrivateAndPublic.md index 85b23686..ff3e73cd 100644 --- a/docs/Concepts/Privacy/PrivateAndPublic.md +++ b/docs/Concepts/Privacy/PrivateAndPublic.md @@ -38,6 +38,6 @@ who are not party to the Transaction will simply end up skipping the Transaction However those participants that are party to the Transaction will replace the hash with the original Payload before calling the EVM for execution, and their StateDB will be updated accordingly. In absence of making corresponding changes to the geth client, these two sets of participants would therefore end up with different StateDBs and -not be able to reach consensus. So in order to support this bifurcation of contract state, Quorum stores the state of +not be able to reach consensus. In order to support this bifurcation of contract state, Quorum stores the state of Public contracts in a Public State Trie that is globally synchronised, and it stores the state of Private contracts in a Private State Trie that is not synchronised globally. diff --git a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md index db4686a3..bcab5d9c 100644 --- a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md +++ b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md @@ -5,7 +5,7 @@ Below is a description of how Private Transactions are processed in GoQuorum: In this example, Party A and Party B are party to Transaction AB, whilst Party C is not. 1. Party A sends a Transaction to their GoQuorum Node, specifying the Transaction payload and setting `privateFor` to be the public keys for Parties A and B (Party A is optional) -1. Party A's GoQuorum Node passes the Transaction on to its paired Transaction Manager, requesting that it encrypt and store the Transaction payload before forwarding it on to the recipients of the transaction (i.e. Party B) +1. Party A's GoQuorum Node passes the Transaction on to its paired Transaction Manager, requesting that it encrypt and store the Transaction payload before forwarding it on to the recipients of the transaction (that is Party B) 1. Party A's Transaction Manager makes a call to its associated Enclave to encrypt the payload for the given recipients 1. Party A's Enclave encrypts the private transaction payload by: @@ -15,22 +15,22 @@ In this example, Party A and Party B are party to Transaction AB, whilst Party C 1. deriving the ECDH (elliptic-curve Diffie-Hellman) shared symmetric key (*shared-key*) from the sender's (A's) private key and the recipient's (B's) public key 1. encrypting the tx-key with the shared-key and the other nonce - 1. repeating this for all recipients (i.e. for *n* recipients there will be *n* unique encrypted tx-keys) (the nonce is unchanged for each recipient as the shared-key being used changes) + 1. repeating this for all recipients (for *n* recipients there will be *n* unique encrypted tx-keys - the nonce is unchanged for each recipient as the shared-key being used changes) 1. returning to the Transaction Manager: the encrypted transaction payload, all encrypted tx-keys, both nonces, and the public keys of the sender and all recipients 1. Party A's Transaction Manager stores the response from the Enclave and forwards to the private transaction recipients by: 1. calculating the SHA3-512 hash of the encrypted payload (this acts as the unique identifier/primary key in the database) 1. storing the hash, encrypted payload, all encrypted tx-keys, both nonces, and the public keys of the sender and all recipients in the database 1. sending the response from the Enclave to each recipient by: - 1. sanitising the response for each recipient (i.e. removing all encrypted tx-keys except for the one intended for that recipient) + 1. sanitising the response for each recipient (removing all encrypted tx-keys except for the one intended for that recipient) 1. serialising the data 1. pushing the serialised data to the recipient (in this case Party B's Transaction Manager) - 1. ensuring the push was successful (if a single recipient fails to respond or returns an error then the process will stop here - i.e. it is a requirement that all recipients have stored the encrypted payload before the transaction can be propagated at the GoQuorum level and written to the blockchain) + 1. ensuring the push was successful (if a single recipient fails to respond or returns an error then the process will stop here. It is a requirement that all recipients have stored the encrypted payload before the transaction can be propagated at the GoQuorum level and written to the blockchain) 1. repeating this for all recipients 1. Party A's Transaction Manager returns the hash of the encrypted payload to the GoQuorum Node. GoQuorum replaces the `data` field of the Transaction with that hash, and changes the transaction's `v` value to `37` or `38`, thus marking the transaction as private and indicating that the transaction's `data` field represents the hash of an encrypted payload as opposed to executable EVM bytecode 1. The Transaction is then propagated to the rest of the network using the standard geth P2P Protocol 1. A block containing Transaction AB is created and distributed to each GoQuorum node in the network -1. In processing the block, all GoQuorum nodes attempt to process the Transaction. Recognising that the transaction `data` is a hash due to the `v` value of `37` or `38`, each node will make a call to its Transaction Manager to determine if it is party to the transaction (i.e. there is an entry for the given hash in its database). In this example, Party A & B's Transaction Managers will determine that they are party to the transaction whereas Party C's Transaction Manager will determine that it is not party +1. In processing the block, all GoQuorum nodes attempt to process the Transaction. Recognising that the transaction `data` is a hash due to the `v` value of `37` or `38`, each node will make a call to its Transaction Manager to determine if it is party to the transaction (there is an entry for the given hash in its database). In this example, Party A & B's Transaction Managers will determine that they are party to the transaction whereas Party C's Transaction Manager will determine that it is not party 1. Party A & B's Transaction Managers make a call to their associated Enclaves to decrypt the payload 1. Party A & B's Enclaves decrypt the private transaction by: 1. deriving the shared-key used in the encryption: diff --git a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md index e52c0f0e..2c5c8649 100644 --- a/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md +++ b/docs/Concepts/Security/Framework/DecentralizedApplication/SmartContractsSecurity.md @@ -101,7 +101,7 @@ Short address attacks are a side effect of the EVM accepting incorrectly padded - [X] Ownership related events must be broadcasted to all the network participants. -- [X] In a Consortium based ownership structure, changing activities that are bound to approval from consortium members before they are committed (e.g. editing Consortium structure) must have approval pending expiration date. +- [X] In a Consortium based ownership structure, changing activities that are bound to approval from consortium members before they are committed (for example, editing Consortium structure) must have approval pending expiration date. - [X] Consortium based voting must involve real-time notification through EVM event emission. @@ -161,4 +161,4 @@ Short address attacks are a side effect of the EVM accepting incorrectly padded - [X] Multiparty contract logic action should not be dependent on a single party. -- [X] Prevent token transfers to 0x0 address. +- [X] Prevent token transfers to `0x0` address. diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md index 3c7417fb..cf3ebdb2 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Consortium.md @@ -22,9 +22,9 @@ Most network operational activities are benign, but this is not true in all case and even in otherwise low-risk Consortium, where the membership constitutes “market power” under the antitrust laws, a significant percentage of the competitors in a given product or service space might be members. -The potential for inadvertent mistakes, as well as the level of potential scrutiny by government regulators, is higher. +The potential for inadvertent mistakes and the level of potential scrutiny by government regulators, is higher. -In such a situation, individual members may wish to maintain tighter control over what can – and more importantly, what cannot – be done +In such a situation, individual members may wish to maintain tighter control over what can (and more importantly, what cannot) be done by the organization, and its members without proper prior consensus in order to reduce the risk and liability. ## Activities diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md index 08739994..1eb2fa0d 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/Node.md @@ -47,7 +47,7 @@ Users password should never be saved across the ecosystem or stored in ledger ho ### Host -- [x] Harden GoQuorum Host Operating System (e.g remove irrelevant services, root access...etc). +- [x] Harden GoQuorum Host Operating System (e.g remove irrelevant services, root access, …). - [x] Disable direct remote network access to GoQuorum host management interface in production. @@ -65,7 +65,7 @@ Users password should never be saved across the ecosystem or stored in ledger ho - [x] Enable Secure Transport Security (TLS) to encrypt all communications from/to JSON-RPC interface to prevent data leakage and man in the middle attacks (MITM). -- [x] Enable GoQuorum Enterprise JSON-RPC authorization model to enforce atomic access controls to ledger modules functionalities (for example personal.OpenWallet). +- [x] Enable GoQuorum Enterprise JSON-RPC authorization model to enforce atomic access controls to ledger modules functionalities (for example `personal.OpenWallet`). - [x] Implement a robust Patch Management Program, and always keep the client updated to latest stable version. diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md index 02424851..13f873e0 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md @@ -15,7 +15,7 @@ The following parameters are of interest to be collected and analyzed: - Public and Private transaction rates per account in the network. - Number of public Smart contracts in the network. - Network connections to ledger nodes and metadata. -- Consensus protocol metadata (E.g Block creation rate, and source ...etc) +- Consensus protocol metadata (Block creation rate, and source, …) ## Security Checklist @@ -27,7 +27,7 @@ The following parameters are of interest to be collected and analyzed: - Public and Private transaction rates per account in the network. - Number of public Smart contracts in the network. - Network connections to ledger nodes and metadata. - - Consensus protocol metadata (E.g Block creation rate, and source ...etc) + - Consensus protocol metadata (E.g Block creation rate, and source, …) - [x] Logs must be backed-up and integrity verified. diff --git a/docs/HowTo/Configure/Plugins.md b/docs/HowTo/Configure/Plugins.md index 36e0bede..38706b68 100644 --- a/docs/HowTo/Configure/Plugins.md +++ b/docs/HowTo/Configure/Plugins.md @@ -35,7 +35,7 @@ |:------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `baseDir` | A string indicating the local directory from where plugins are read. If empty, defaults to `/plugins`.
To read from arbitrary enviroment variable (e.g: `MY_BASE_DIR`), provide value `env://MY_BASE_DIR` | | `central` | A configuration of the remote plugin central. See [PluginCentralConfiguration](#plugincentralconfiguration) | -| `providers` | A map of the supported plugin interfaces being used (e.g. `helloworld`), mapped to their respective plugin provider definitions (see [PluginDefinition](#plugindefinition)) | +| `providers` | A map of the supported plugin interfaces being used (for example, `helloworld`), mapped to their respective plugin provider definitions (see [PluginDefinition](#plugindefinition)) | | `` | A string constant indicates the plugin interface. E.g: `helloworld`. | ## `PluginCentralConfiguration` diff --git a/docs/HowTo/Configure/dns.md b/docs/HowTo/Configure/dns.md index 7a9153f7..cfbd9f19 100644 --- a/docs/HowTo/Configure/dns.md +++ b/docs/HowTo/Configure/dns.md @@ -8,7 +8,7 @@ requires. Static nodes are nodes we keep reference to even if the node is not alive, so that is the nodes comes alive, then we can connect to it. Hostnames are permitted here, and are resolved once at startup. If a static peer goes offline -and its IP address changes, then it is expected that that peer would re-establish the connection in a fully static +and its IP address changes, then it is expected that this peer would re-establish the connection in a fully static network, or have discovery enabled. ## Discovery diff --git a/docs/HowTo/DevelopPlugins.md b/docs/HowTo/DevelopPlugins.md index b840d680..0dd32d89 100644 --- a/docs/HowTo/DevelopPlugins.md +++ b/docs/HowTo/DevelopPlugins.md @@ -86,7 +86,7 @@ Some additional advanced topics are described here. ### Magic Cookie -Magic Cookie key and value are used as a very basic verification that a plugin is intended to be launched. +Magic Cookie key and value are used as a basic verification that a plugin is intended to be launched. This is not a security measure, just a UX feature. Magic Cookie key and value are injected as an environment variable while executing the plugin process. @@ -95,7 +95,9 @@ Magic Cookie key and value are injected as an environment variable while executi QUORUM_PLUGIN_MAGIC_COOKIE="CB9F51969613126D93468868990F77A8470EB9177503C5A38D437FEFF7786E0941152E05C06A9A3313391059132A7F9CED86C0783FE63A8B38F01623C8257664" ``` -The plugin and the GoQuorum client's magic cookies are compared. If they are equal then the plugin is loaded. If they are not equal, the plugin should show human-friendly output. +The plugin and the GoQuorum client's magic cookies are compared. +If they are equal then the plugin is loaded. +If they are not equal, the plugin should show human-friendly output. ### Mutual TLS Authentication diff --git a/docs/HowTo/GetStarted/Cakeshop.md b/docs/HowTo/GetStarted/Cakeshop.md index 050ca2f5..9fefcc7c 100644 --- a/docs/HowTo/GetStarted/Cakeshop.md +++ b/docs/HowTo/GetStarted/Cakeshop.md @@ -27,7 +27,7 @@ ## Running modes -There are a few ways in which you can run Cakeshop (see the sections below for details on each, as well as [configuration](https://github.com/ConsenSys/cakeshop/blob/master/docs/configuration.md#geth) page): +Cakeshop can start in multiple modes (see the sections below for details on each and [configuration](https://github.com/ConsenSys/cakeshop/blob/master/docs/configuration.md#geth) page): 1. **Default mode**: _Used when you want Cakeshop to start up an Ethereum node._ Running Cakeshop in the Default mode will start up Cakeshop and also start running a regular geth node (on a private/test network). @@ -42,7 +42,7 @@ There are a few ways in which you can run Cakeshop (see the sections below for d Cakeshop is currently designed such that a given instance of Cakeshop works directly with a single Ethereum-like node, however you can set up multiple instances of Cakeshop on the same machine (each which could either have been started in 'Default' mode or 'Attach' mode) such that each can talk to a different node. !!!note - You can use the Attach mode and/or Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. + You can use the Attach mode and Multi-Instance setup configuration to run Cakeshop on [GoQuorum](https://github.com/ConsenSys/quorum) nodes. See below for connecting Cakeshop to the [7nodes](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes) network from the quorum-examples repo. !!!warning The following commands assume you have renamed the WAR file to cakeshop.war @@ -87,7 +87,7 @@ There are a few ways in which you can run Cakeshop (see the sections below for d 1. The dropdown menu on the top right of the page should show "Manage Nodes" if you haven't attached to any yet. Click on that to go to the Manage Nodes page. -1. Click Add Node and input the RPC url of your GoQuorum node (i.e. http://localhost:22000) and the path to the Tessera P2P Party Info endpoint (i.e. http://localhost:9001/partyinfo). +1. Click Add Node and input the RPC url of your GoQuorum node (http://localhost:22000) and the path to the Tessera P2P Party Info endpoint (http://localhost:9001/partyinfo). 1. Once added, click on View to attach to the node and return to the main Cakeshop page diff --git a/docs/HowTo/GetStarted/GettingStartedOverview.md b/docs/HowTo/GetStarted/GettingStartedOverview.md index fb60fcb8..250b2076 100644 --- a/docs/HowTo/GetStarted/GettingStartedOverview.md +++ b/docs/HowTo/GetStarted/GettingStartedOverview.md @@ -4,8 +4,8 @@ description: Getting started with GoQuorum overview # Getting started overview -There are several ways to get started with GoQuorum. They range from using our wizard to generate a -local network, to configuring and creating a full network from scratch. +You can get started with GoQuorum in multiple ways. +They range from using our wizard to generate a local network, to configuring and creating a full network from scratch. ## GoQuorum Wizard @@ -30,12 +30,12 @@ To explore the features of GoQuorum and deploy a private contract, follow the in network that can be run either in a virtual-machine environment using Vagrant, in containers using docker-compose, or locally through the use of bash scripts to automate creation of the network. -## GoQuorum on Kubernetes ![k8s-logo](../../images/qubernetes/k8s-logo.png){: style="height:20px;width:20px"} +## GoQuorum on Kubernetes Use [qubernetes](https://github.com/ConsenSys/qubernetes) to run configurable N node GoQuorum networks on Kubernetes. You can use [kind](https://github.com/ConsenSys/qubernetes#quickest-start) or [Minikube](https://github.com/ConsenSys/qubernetes/blob/master/docs/minikube-docs.md) -for local development. For long running networks, use a cloud service (e.g. Google Kubernetes Engine, Azure KS, AWS EKS) or a self-hosted kubernetes cluster. +for local development. For long running networks, use a cloud service (for ecample Google Kubernetes Engine, Azure KS, AWS EKS) or a self-hosted kubernetes cluster. Qubernetes supports Raft and Istanbul consensus algorithms, multiple versions, and networks with an arbitrary number of nodes. Also includes [examples](https://github.com/ConsenSys/qubernetes/blob/master/docs/7nodes-on-k8s.md) ready to run on Kubernetes. diff --git a/docs/HowTo/GetStarted/Install.md b/docs/HowTo/GetStarted/Install.md index f45e08c5..4deb6428 100644 --- a/docs/HowTo/GetStarted/Install.md +++ b/docs/HowTo/GetStarted/Install.md @@ -28,7 +28,7 @@ docker pull quorumengineering/tessera make all ``` - Binaries are placed in `$REPO_ROOT/build/bin`. Add that folder to `PATH` to make `geth` and `bootnode` easily invokable, or copy those binaries to a folder already in `PATH`, e.g. `/usr/local/bin`. + Binaries are placed in `$REPO_ROOT/build/bin`. Add that folder to `PATH` to make `geth` and `bootnode` easily invokable, or copy those binaries to a folder already in `PATH`, for example `/usr/local/bin`. An easy way to supplement `PATH` is to add `PATH=$PATH:/path/to/repository/build/bin` to your `~/.bashrc` or `~/.bash_aliases` file. diff --git a/docs/HowTo/GetStarted/Wizard/GettingStarted.md b/docs/HowTo/GetStarted/Wizard/GettingStarted.md index cc5cf1c5..a1b2147b 100644 --- a/docs/HowTo/GetStarted/Wizard/GettingStarted.md +++ b/docs/HowTo/GetStarted/Wizard/GettingStarted.md @@ -11,7 +11,7 @@ users to set up a development GoQuorum network on their local machine in less th ## Installation -`quorum-wizard` is written in Javascript and designed to be installed as a global NPM module and run +`quorum-wizard` is written in JavaScript and designed to be installed as a global NPM module and run from the command line. Make sure you have [Node.js/NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed. Using npm: diff --git a/docs/HowTo/GetStarted/Wizard/Interacting.md b/docs/HowTo/GetStarted/Wizard/Interacting.md index 99787f24..3a7d55d4 100644 --- a/docs/HowTo/GetStarted/Wizard/Interacting.md +++ b/docs/HowTo/GetStarted/Wizard/Interacting.md @@ -20,7 +20,7 @@ cd network/3-nodes-raft-tessera-bash ## Demonstrating Privacy -The network comes with some simple contracts to demonstrate the privacy features of GoQuorum. In this demo we: +The network comes with some simple contracts to demonstrate the privacy features of GoQuorum. In this demo you: - Send a private transaction between nodes 1 and 2 - Show that only nodes 1 and 2 are able to view the initial state of the contract @@ -40,9 +40,9 @@ Take note of the `TransactionHash` printed to the terminal. ### Inspecting the GoQuorum nodes -We can inspect any of the GoQuorum nodes by using `./attach.sh` to open the Geth JavaScript console. For this demo, we will be inspecting Node 1, Node 2, and Node 3. +You can inspect any of the GoQuorum nodes by using `./attach.sh` to open the Geth JavaScript console. For this demo, you will be inspecting Node 1, Node 2, and Node 3. -It is recommended to use separate terminal windows for each node we are inspecting. In each terminal, ensure you are in your network's directory, then: +It is recommended to use separate terminal windows for each node you are inspecting. In each terminal, ensure you are in your network's directory, then: - In terminal 1 run `./attach.sh 1` to attach to node 1 - In terminal 2 run `./attach.sh 2` to attach to node 2 @@ -79,7 +79,7 @@ Take note of the `v` field value of `"0x25"` or `"0x26"` (37 or 38 in decimal) w #### Checking the state of the contract -For each of the 3 nodes we'll use the Geth JavaScript console to create a variable called `address` which we will assign to the address of the contract created by Node 1. The contract address can be found in two ways: +For each of the 3 nodes you'll use the Geth JavaScript console to create a variable called `address` which you will assign to the address of the contract created by Node 1. The contract address can be found in two ways: - In Node 1's log file: `qdata/logs/1.log` - By reading the `contractAddress` param after calling `eth.getTransactionReceipt(txHash)` ([Ethereum API documentation](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgettransactionreceipt)) where `txHash` is the hash printed to the terminal after sending the transaction. @@ -90,7 +90,7 @@ Once you've identified the contract address, run the following command in each t > var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"; //replace with your contract address ``` -Next we'll use ```eth.contract``` to define a contract class with the simpleStorage ABI definition in each terminal: +Next you'll use ```eth.contract``` to define a contract class with the simpleStorage ABI definition in each terminal: ```js > var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}]; @@ -120,7 +120,7 @@ The function calls are now available on the contract instance and you can call t 0 ``` -So we can see nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. +Notice that nodes 1 and 2 are able to read the state of the private contract and its initial value is 42. If you look in `private-contract.js` you will see that this was the value set when the contract was created. @@ -128,7 +128,7 @@ Node 3 is unable to read the state. ### Updating the state of the contract -Next we'll have Node 1 set the state to the value `4` and verify only nodes 1 and 2 are able to view the new state. +Next you'll have Node 1 set the state to the value `4` and verify only nodes 1 and 2 are able to view the new state. In terminal window 1 (Node 1): @@ -137,7 +137,7 @@ In terminal window 1 (Node 1): "0xacf293b491cccd1b99d0cfb08464a68791cc7b5bc14a9b6e4ff44b46889a8f70" ``` -You can check the log files in `qdata/logs/` to see each node validating the block with this new private transaction. Once the block containing the transaction has been validated we can once again check the state from each node 1, 4, and 2. +You can check the log files in `qdata/logs/` to see each node validating the block with this new private transaction. Once the block containing the transaction has been validated you can once again check the state from each node 1, 4, and 2. - In terminal window 1 (Node 1): diff --git a/docs/HowTo/GetStarted/migration.md b/docs/HowTo/GetStarted/migration.md index d44aa947..93eca310 100644 --- a/docs/HowTo/GetStarted/migration.md +++ b/docs/HowTo/GetStarted/migration.md @@ -17,7 +17,7 @@ A node running on GoQuorum 2.6.0 can coexist on a network where other nodes are * GoQuorum 2.6.0 has deprecated genesis attributes `maxCodeSize` and `maxCodeSizeChangeBlock`. To allow tracking of multiple `maxCodeSize` value changes, a new attribute `maxCodeSizeConfig` is added to genesis. - If the `maxCodeSize` was changed multiple times, it could possibly result in `Bad block` error for any new node joining the network. + If the `maxCodeSize` was changed multiple times, it could result in `Bad block` error for any new node joining the network. The changes in GoQuorum 2.6.0 address this and enable tracking of historical changes of `maxCodeSize` in genesis and thus allow it to be changed multiple times in network life. With this change when `init` is executed in GoQuorum 2.6.0, `geth` will force usage of `maxCodeSizeConfig`. diff --git a/docs/HowTo/Logging and Errors.md b/docs/HowTo/Logging and Errors.md index cf8fc57e..a609c849 100644 --- a/docs/HowTo/Logging and Errors.md +++ b/docs/HowTo/Logging and Errors.md @@ -19,7 +19,7 @@ This is our take on cataloguing of error messages along with possible cause and | `"Bootstrap URL invalid", "enode", url, "err", err` | One or more enode values specified on the command line for a bootstrap node, is not a valid url. | You need to provide a correct url | | `"Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()` | This message is generated if the socket file specified for the smartcard daemon (pcscd) is not actually a socket file | Ensure that the daemon is running and the correct socket file is specified on the command line | | `"Failed to get signer address", "err", err` | This indicates that the public address could not be obtained for the signature on a message in an IBFT network. This is potentially an internal error or an issue with the crypto package. | Depends on the root cause in the log message - an issue ticket may need to be raised | -| `"Failed to serialize JavaScript exception", "exception", msg, "err", err` | This is an internal error, occurring if the given message could not be serialized into a javascript message by the [Otto](https://github.com/robertkrimen/otto) JS parser. | Raise an issue ticket | +| `"Failed to serialize JavaScript exception", "exception", msg, "err", err` | This is an internal error, occurring if the given message could not be serialized into a JavaScript message by the [Otto](https://github.com/robertkrimen/otto) JS parser. | Raise an issue ticket | | `"Non contiguous block insert", "number", block.Number(), "hash", block.Hash()` | Message is generated if an 'out of sequence' block is received for insertion into the chain. This usually occurs if node is out of sync or holds a corrupt chain. | See instructions under the section on [Resolution of database corruption issues](#resolution-of-database-corruption-issues) | | `"Non contiguous receipt insert", "number", blockChain[i].Number(), "hash", blockChain[i].Hash(), "parent", blockChain[i].ParentHash()` | Message is generated if an 'out of sequence' receipt is received for insertion. This usually occurs if node is out of sync or holds corrupt data. | See instructions under the section on [Resolution of database corruption issues](#resolution-of-database-corruption-issues) | | `"Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash` | Message is generated on startup if a block is found in the database with one of a set 'bad hash' values predefined in [core/blocks.go](https://github.com/ethereum/go-ethereum/blob/461291882edce0ac4a28f64c4e8725b7f57cbeae/core/blocks.go#L22). The node will rewind the chain to prior to the bad hash and resync from that point | No action should be necessary as node will rewind and recover | diff --git a/docs/HowTo/ManageKeys/AccountPlugins.md b/docs/HowTo/ManageKeys/AccountPlugins.md index 24023a04..0e4f2d0f 100644 --- a/docs/HowTo/ManageKeys/AccountPlugins.md +++ b/docs/HowTo/ManageKeys/AccountPlugins.md @@ -94,7 +94,7 @@ Create a plugin-managed account with a new key: Create a plugin-managed account from an existing private key: !!! note - Although this API can be used to move plugin-managed accounts between nodes, the plugin may provide a more preferable alternative. See the plugin's documentation for more info. + Although this API can be used to move plugin-managed accounts between nodes, the plugin may provide a preferable alternative. See the plugin's documentation for more info. | Parameter | Description | | --- | --- | @@ -139,7 +139,7 @@ geth account plugin --help ``` !!! info - Use the `--verbosity` flag to hide log output, e.g. `geth --verbosity 1 account plugin new ...` + Use the `--verbosity` flag to hide log output, for example `geth --verbosity 1 account plugin new ...` ### geth account plugin new @@ -172,7 +172,7 @@ Create a plugin-managed account from an existing private key: | Parameter | Description | | --- | --- | | `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required -| `rawkey` | Path to file containing hex-encoded account private key (without 0x prefix) (e.g. `/path/to/raw.key`) +| `rawkey` | Path to file containing hex-encoded account private key (without 0x prefix) (for example `/path/to/raw.key`) === "json file" diff --git a/docs/HowTo/ManageKeys/clef.md b/docs/HowTo/ManageKeys/clef.md index 311dcb78..24ec5030 100644 --- a/docs/HowTo/ManageKeys/clef.md +++ b/docs/HowTo/ManageKeys/clef.md @@ -33,7 +33,7 @@ Using `clef` instead of `geth` for account management has several benefits: ## Installing -`geth` and all included tools (i.e. `clef`, `bootnode`, ...) can be installed to `PATH` by +`geth` and all included tools (`clef`, `bootnode`, …) can be installed to `PATH` by [building GoQuorum from source with `make all`](../GetStarted/Install.md). Verify the installation with: @@ -45,7 +45,7 @@ clef help ## Getting Started See [cmd/clef/tutorial.md](https://github.com/ConsenSys/quorum/blob/master/cmd/clef/tutorial.md) -for an overview and step-by-step guide on initialising and starting `clef`, as well as configuring automation rules. +for an overview and step-by-step guide on `clef` initialisation, startup and automation rules configuration. ## Using diff --git a/docs/HowTo/Use/AddingIBFTValidators.md b/docs/HowTo/Use/AddingIBFTValidators.md index 7093f817..05bf23f0 100644 --- a/docs/HowTo/Use/AddingIBFTValidators.md +++ b/docs/HowTo/Use/AddingIBFTValidators.md @@ -1,7 +1,7 @@ # Adding and removing IBFT validators Over the lifetime of an IBFT network, validators will need to be added and removed as authorities change. -Here we will showcase adding a new validator to an IBFT network, as well as removing an existing one. +Here we will showcase adding a new validator to an IBFT network and removing an existing one. ## Adding a node to the validator set @@ -96,7 +96,7 @@ repository. Secondly, we fetched the current snapshot, which gives us an insight into the current running state of the voting. We can see that the new address has 1 vote under the `tally` section, and that one vote is described under the - `votes` section. So we know our vote was registered! + `votes` section. Your vote was registered! 1. Let's run this from node 2 and see similar results: @@ -132,7 +132,7 @@ repository. } ``` - True to form, we have the second vote registered! + True to form, you have the second vote registered! 1. Ok, let's finally vote on nodes 3 and 4. @@ -144,7 +144,7 @@ repository. null ``` -1. Now we have a majority of votes, let's check the snapshot again: +1. Now you have a majority of votes, let's check the snapshot again: ```bash docker exec -it addnode_node1_1 geth --exec 'istanbul.getSnapshot();' attach /qdata/dd/geth.ipc @@ -159,19 +159,19 @@ repository. } ``` - We can see that the votes have now been wiped clean, ready for a new round. Additionally, the address we were adding, + You can see that the votes have now been wiped clean, ready for a new round. Additionally, the address you were adding, `0xb131288f355bc27090e542ae0be213c20350b767` now exists within the `validators` list! Lastly, the `unauthorized` messages that node 7 was giving before has stopped, as it now has the authority to mint blocks. ## Removing a node from the validator set -Removing a validator is very similar to adding a node, but this time we want to propose nodes with the value `false`, -to indicate we are deauthorising them. It does not matter whether the node is still online or not, as it doesn't +Removing a validator is similar to adding a node, but this time you want to propose nodes with the value `false`, +to indicate you are deauthorising them. It does not matter whether the node is still online or not, as it doesn't require any input from the node being removed. !!! warning - Be aware when removing nodes that cross the BFT boundary, e.g. going from 10 validators to 9, as this may impact the chains ability to progress if other nodes are offline + Be aware when removing nodes that cross the BFT boundary, that is, going from 10 validators to 9, as this may impact the chains ability to progress if other nodes are offline Removing a new validator requires that a majority of existing validators propose the new node to be removed. This is achieved by calling the `propose` RPC method with the value `false` and replacing the address to your required one: @@ -210,10 +210,10 @@ repository. docker-compose -f ibft-6-validators.yml up ``` -1. Now we need to propose node 6 as the node to remove. +1. Now you need to propose node 6 as the node to remove. !!! note - We need a majority of existing validators to propose the new node before the changes will take effect. + You need a majority of existing validators to propose the new node before the changes will take effect. Lets start with node 1 and see what happens: @@ -246,15 +246,15 @@ repository. ``` Let's break this down. - Firstly, we proposed the address `0x8157d4437104e3b8df4451a85f7b2438ef6699ff` to be removed; that is what the + Firstly, you proposed the address `0x8157d4437104e3b8df4451a85f7b2438ef6699ff` to be removed; that is what the `false` parameter is for. - Secondly, we fetched the current snapshot, which gives us an insight into the current running state of the voting. - We can see that the proposed address has 1 vote under the `tally` section, and that one vote is described under the + Secondly, you fetched the current snapshot, which gives us an insight into the current running state of the voting. + You can see that the proposed address has 1 vote under the `tally` section, and that one vote is described under the `votes` section. Here, the `authorize` section is set to `false`, which is inline with our proposal to *remove* the validator. -1. We need to get a majority, so let's run the proposal on 3 more nodes: +1. You need to get a majority, so let's run the proposal on 3 more nodes: ```bash docker exec -it addnode_node2_1 geth --exec 'istanbul.propose("0x8157d4437104e3b8df4451a85f7b2438ef6699ff", false);' attach /qdata/dd/geth.ipc @@ -282,7 +282,7 @@ repository. } ``` - The validator has been removed from the `validators` list, and we are left with the other 5 still present. You will + The validator has been removed from the `validators` list, and you are left with the other 5 still present. You will also see in the logs of node 6 a message like `node6_1 | WARN [01-20|11:35:52.044] Block sealing failed err=unauthorized`. This is because it is still minting blocks, but realises it does not have the authority to push them to any of the other nodes on the network (you will diff --git a/docs/HowTo/Use/DevelopingSmartContracts.md b/docs/HowTo/Use/DevelopingSmartContracts.md index 592f8f6a..24badcae 100644 --- a/docs/HowTo/Use/DevelopingSmartContracts.md +++ b/docs/HowTo/Use/DevelopingSmartContracts.md @@ -2,7 +2,7 @@ GoQuorum uses standard [Solidity](https://solidity.readthedocs.io/en/develop/) for writing Smart Contracts, and generally, these can be designed as you would design Smart Contracts for Ethereum. Smart Contracts can -either be public (i.e. visible and executable by all participants on a given GoQuorum network) or private to +either be public (that is, visible and executable by all participants on a given GoQuorum network) or private to one or more network participants. Note that GoQuorum does not introduce new contract types. ## Creating public transactions/contracts diff --git a/docs/HowTo/Use/JSON-RPC-API-Security.md b/docs/HowTo/Use/JSON-RPC-API-Security.md index 6d1ae957..fa39bd18 100644 --- a/docs/HowTo/Use/JSON-RPC-API-Security.md +++ b/docs/HowTo/Use/JSON-RPC-API-Security.md @@ -21,7 +21,7 @@ Enterprise authorization protocol integration introduces an access control layer that authorizes each JSON RPC invocation to an atomic module function level (E.g `personal_OpenWallet`) using industry standard [OAuth 2.0](https://tools.ietf.org/html/rfc6749) -protocol and/or [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) method. +protocol and [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) method. This feature allows managing distributed application (dApps), and Quorum Clients access control in an efficient approach. diff --git a/docs/HowTo/Use/add_node_examples.md b/docs/HowTo/Use/add_node_examples.md index a81752f4..1648736f 100644 --- a/docs/HowTo/Use/add_node_examples.md +++ b/docs/HowTo/Use/add_node_examples.md @@ -28,7 +28,7 @@ export COMPOSE_PROJECT_NAME=addnode An example using IBFT, no permissioning and discover enabled via a bootnode. -There are no static peers in this network; instead, every node is set to talk to node 1 via the CLI flag +This network has no static peers; instead, every node is set to talk to node 1 via the CLI flag `--bootnodes enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@172.16.239.11:21000`. Node 1 will forward the details of all the nodes it knows about (in this case, everyone) and they will then initiate their @@ -94,7 +94,7 @@ own connections. 1. Let's check to see if the nodes are in sync. If they are, they will have similar block numbers, which is enough for - this example; there are other ways to tell if nodes are on the same chain, for example matching block hashes. + this example; Other options exists to tell if nodes are on the same chain, for example matching block hashes. !!! note Depending on timing, the second may have an extra block or two. @@ -187,7 +187,7 @@ own connections. ``` And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to -read existing public data, as well as deploy its own transactions and contracts for others to see! +read existing public data and deploy its own transactions and contracts for others to see! ## Non-permissioned RAFT with discovery disabled @@ -336,7 +336,7 @@ solely based on who is listed in the nodes `static-nodes.json` file. ``` And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to -read existing public data, as well as deploy its own transactions and contracts for others to see! +read existing public data and deploy its own transactions and contracts for others to see! ## Permissioned RAFT with discovery disabled @@ -518,7 +518,7 @@ the node must appear is others nodes' `permissioned-nodes.json` file. ``` And that's it. You deployed a working 6 node network, and then added a 7th node afterwards; this 7th node was able to -read existing public data, as well as deploy its own transactions and contracts for others to see! +read existing public data and deploy its own transactions and contracts for others to see! ## Adding a Private Transaction Manager @@ -600,7 +600,7 @@ IP Whitelist isn't used, nor is key discovery disabled. and you have a single peer to start off with, which is node 1. This is all that is needed to connect to an existing network. Shortly after starting up, Tessera - will ask node 1 about all it's peers, and then will keep a record of them for it's own use. + will request about all node 1 peers, and then will keep a record of them for it's own use. From then on, all the nodes will know about node 7 and can send private transactions to it. 1. Let's try it! Let's send a private transaction from node 1 to the newly added node 7. diff --git a/docs/HowTo/Use/adding_nodes.md b/docs/HowTo/Use/adding_nodes.md index 64bd1d77..675335d4 100644 --- a/docs/HowTo/Use/adding_nodes.md +++ b/docs/HowTo/Use/adding_nodes.md @@ -33,11 +33,11 @@ In some cases, they may have their own options to achieve similar tasks, but mus 7 ``` - So in this example, our new node has a Raft ID of `7`. + In this example, your new node has a Raft ID of `7`. 1. If you are using permissioning, or discovery for Ethereum p2p, please refer [here](#extra-options). -1. We now need to initialise the new node with the network's genesis configuration. +1. You now need to initialise the new node with the network's genesis configuration. Initialising the new node is exactly the same an the original nodes. @@ -48,7 +48,7 @@ In some cases, they may have their own options to achieve similar tasks, but mus !!! note Where you obtain this from will be dependent on the network. You may get it from an existing peer, or a network operator, or elsewhere entirely. -1. Now we can start up the new node and let it sync with the network. +1. Now you can start up the new node and let it sync with the network. The main difference now is the use of the `--raftjoinexisting` flag, which lets the node know that it is joining an existing network, which is handled differently internally. @@ -173,7 +173,7 @@ In order to make sure the new node is accepted into the network: ``` 1. The new peer can be started, setting the `peers` configuration to mirror the existing network. - e.g. if there are 3 existing nodes in the network, then the new nodes configuration will look like this: + If there are 3 existing nodes in the network, then the new nodes configuration will look like this: ```json { @@ -196,15 +196,15 @@ In order to make sure the new node is accepted into the network: ### Discovery -Tessera discovery is very similar to the IP whitelist. The difference being that the IP whitelist blocks -communications between nodes, whereas disabling discovery only affects which public keys we keep track of. +Tessera discovery is similar to the IP whitelist. The difference being that the IP whitelist blocks +communications between nodes, whereas disabling discovery only affects which public keys you keep track of. See the [Tessera configuration page](https://docs.tessera.consensys.net) for details on setting it up. When discovery is disabled, Tessera will only allow keys that are owned by a node in its peer list to be available to the users. -This means that if any keys are found that are owned by a node NOT in our peer list, they are discarded and +This means that if any keys are found that are owned by a node NOT in your peer list, they are discarded and private transactions cannot be sent to that public key. !!! note diff --git a/docs/Reference/APIs/PrivacyAPI.md b/docs/Reference/APIs/PrivacyAPI.md index ff2131e8..7b44be48 100644 --- a/docs/Reference/APIs/PrivacyAPI.md +++ b/docs/Reference/APIs/PrivacyAPI.md @@ -173,12 +173,10 @@ To support offline signing of transaction. This api fills and defaults `RLP` plu "0xcd8ab3f6dbdb8535a44d47df9c7d8a3862fe9fb4257a2d377bdd8bface016928" ``` - ## JSON RPC Privacy API Reference __In addition to the JSON-RPC provided by Ethereum, GoQuorum exposes below two API calls.__ - ### eth_storageRoot Returns the storage root of given address (Contract/Account etc) @@ -186,7 +184,7 @@ Returns the storage root of given address (Contract/Account etc) #### Parameters 1. `address`: `String` - The address to fetch the storage root for in hex -1. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. +1. `block`: `String` - (optional) The block number to look at in hex (for example `0x15` for block 21). Uses the latest block if not specified. #### Returns @@ -297,26 +295,26 @@ Returns the unencrypted payload from Tessera/constellation #### Parameters - 1. `Object` - The transaction object to send: - - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. - - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. - - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - - `input`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. `input` cannot coexist with `data` if they are set to different value. - - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. - - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction +1. `Object` - The transaction object to send: + - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. + - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. + - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. + - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). + - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. + - `input`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. `input` cannot coexist with `data` if they are set to different value. + - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. + - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. + - `callbackUrl`: `String` - (optional) the URL to perform a POST request to post the result of submitted the transaction #### Returns - 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` +1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` - The callback URL receives the following object: +The callback URL receives the following object: - 1. `Object` - The result object: +1. `Object` - The result object: - `id`: `String` - the identifier in the original RPC call, used to match this result to the request - `txHash`: `String` - the transaction hash that was generated, if successful - `error`: `String` - the error that occurred whilst submitting the transaction. diff --git a/docs/Reference/FAQ.md b/docs/Reference/FAQ.md index 4af5392d..6c8e149b 100644 --- a/docs/Reference/FAQ.md +++ b/docs/Reference/FAQ.md @@ -22,7 +22,12 @@ Please see the [GoQuorum Consensus](../Consensus/Consensus) and [Transaction and Contract Privacy Overview](../Privacy/Overview) pages for more info. ??? question "Are there any restrictions on the transaction size for private transactions (since they are encrypted)?" - The only restriction is the gas limit on the transaction. Constellation/Tessera does not have a size limit (although maybe it should be possible to set one). If anything, performing large transactions as private transactions will improve performance because most of the network only sees hash digests. In terms of performance of transferring large data blobs between geographically distributed nodes, it would be equivalent performance to PGP encrypting the file and transferring it over http/https..so very fast. If you are doing sequential transactions then of course you will have to wait for those transfers, but there is no special overhead by the payload being large if you are doing separate/concurrent transactions, subject to network bandwidth limits. Constellation/Tessera does everything in parallel. + The only restriction is the gas limit on the transaction. + Constellation/Tessera does not have a size limit (although maybe it should be possible to set one). + If anything, performing large transactions as private transactions will improve performance because most of the network only sees hash digests. + In terms of performance of transferring large data blobs between geographically distributed nodes, it would be equivalent performance to PGP encrypting the file and as fast as transferring it over http/https. + If you are doing sequential transactions then of course you will have to wait for those transfers, but there is no special overhead by the payload being large if you are doing separate/concurrent transactions, subject to network bandwidth limits. + Constellation/Tessera does everything in parallel. ??? question "Should I include originating node in private transaction?" No. In GoQuorum, including originating node's `privateFor` results in an error. To create a private @@ -60,12 +65,12 @@ It means the node will only communicate with the nodes defined in the configuration file. Upto version 0.10.2, the nodes still accepts transactions from undiscovered nodes. From version 0.10.3 the node blocks all communication with undiscovered nodes. ??? info "Upgrading to Tessera version 0.10.+ from verion 0.9.+ and below" - Due to 'database file unable to open' issue with H2 DB upgrade from version 1.4.196 direct to version 1.4.200 as explained [here](https://github.com/h2database/h2database/issues/2263), our recommended mitigation strategy is to upgrade to version 1.4.199 first before upgrading to version 1.4.200 i.e., first upgrade to Tessera 0.10.0 before upgrading to higher versions. + Due to 'database file unable to open' issue with H2 DB upgrade from version 1.4.196 direct to version 1.4.200 as explained [here](https://github.com/h2database/h2database/issues/2263), our recommended mitigation strategy is to upgrade to version 1.4.199 first before upgrading to version 1.4.200, first upgrade to Tessera 0.10.0 before upgrading to higher versions. ### Raft FAQ ??? question "Could you have a single- or two-node cluster? More generally, could you have an even number of nodes?" - A cluster can tolerate failures that leave a GoQuorum (majority) available. So a cluster of two nodes can't tolerate any failures, three nodes can tolerate one, and five nodes can tolerate two. Typically Raft clusters have an odd number of nodes, since an even number provides no failure tolerance benefit. + A cluster can tolerate failures that leave a GoQuorum (majority) available. A cluster of two nodes can't tolerate any failures, three nodes can tolerate one, and five nodes can tolerate two. Typically Raft clusters have an odd number of nodes, since an even number provides no failure tolerance benefit. ??? question "What happens if you don't assume minter and leader are the same node?" There's no hard reason they couldn't be different. We just co-locate the minter and leader as an optimization. @@ -85,7 +90,7 @@ With raft-based consensus we can produce far more than one block per second, which vanilla Ethereum implicitly disallows (as the default timestamp resolution is in seconds and every block must have a timestamp greater than its parent). For Raft, we store the timestamp in nanoseconds and ensure it is incremented by at least 1 nanosecond per block. ??? question "Why do I see "Error: Number can only safely store up to 53 bits" when using web3js with Raft?" - As mentioned above, Raft stores the timestamp in nanoseconds, so it is too large to be held as a number in javascript. + As mentioned above, Raft stores the timestamp in nanoseconds, so it is too large to be held as a number in JavaScript. You need to modify your code to take account of this. An example can be seen [here](https://github.com/ConsenSys/quorum.js/blob/master/lib/index.js#L35). A future GoQuorum release will address this issue. diff --git a/docs/Reference/GoQuorum-Projects.md b/docs/Reference/GoQuorum-Projects.md index e065dfde..b2408bb4 100644 --- a/docs/Reference/GoQuorum-Projects.md +++ b/docs/Reference/GoQuorum-Projects.md @@ -10,7 +10,6 @@ Current examples include: * Pons [backend](https://github.com/M-Bowe/pons) | [frontend](https://github.com/M-Bowe/pons-frontend): A sample Cross-Chain Trading Bridge written to run over 2 GoQuorum Chains to safely exchange ERC-20 and ERC-721 assets. * [Marketplace](https://github.com/lyotam/techmarketplace): Marketplace is an example application running on top of a GoQuorum network which allows users to bid for and offer virtual hackathon gear for sale in an interactive marketplace. This app is based on what was originally developed for the MLH Localhost GoQuorum workshop, which demonstrates how to run a simple Ethereum application and how to write a simple Smart Contract that interacts with the Ethereum-based network. - !!! Info Most of the links link out to externally maintained repos. We thank all of the authors. Please contact us for any modifications or questions about the content. diff --git a/docs/Reference/Plugins/account/For-Developers.md b/docs/Reference/Plugins/account/For-Developers.md index 2a0f6c60..b1cbee85 100644 --- a/docs/Reference/Plugins/account/For-Developers.md +++ b/docs/Reference/Plugins/account/For-Developers.md @@ -5,7 +5,7 @@ New `account` plugins can be developed to extend the supported account managemen `account` plugins must satisfy the [documented gRPC API](interface.md). !!! note - This documentation is auto-generated from the [GoQuorum Plugin Definitions](https://github.com/ConsenSys/quorum-plugin-definitions) `account.proto` file + This documentation is auto generated from the [GoQuorum Plugin Definitions](https://github.com/ConsenSys/quorum-plugin-definitions) `account.proto` file To simplify the development of new `account` plugins the following `account` plugin SDKs are available: diff --git a/docs/Reference/Plugins/security/For-Developers.md b/docs/Reference/Plugins/security/For-Developers.md index 5338c6c4..ab2e65db 100644 --- a/docs/Reference/Plugins/security/For-Developers.md +++ b/docs/Reference/Plugins/security/For-Developers.md @@ -5,7 +5,7 @@ New `security` plugins can be developed to customize protection of JSON API serv `security` plugins must satisfy the [documented gRPC API](interface.md). !!! note - This documentation is auto-generated from the [Quorum Plugin Definitions](https://www.github.com/ConsenSys/quorum-plugin-definitions) `security.proto` file + This documentation is auto generated from the [Quorum Plugin Definitions](https://www.github.com/ConsenSys/quorum-plugin-definitions) `security.proto` file To simplify the development of new `security` plugins the following `security` plugin SDKs are available: diff --git a/docs/Reference/Plugins/security/For-Users.md b/docs/Reference/Plugins/security/For-Users.md index cb1afbd3..80111da0 100644 --- a/docs/Reference/Plugins/security/For-Users.md +++ b/docs/Reference/Plugins/security/For-Users.md @@ -211,6 +211,7 @@ from a token endpoint of an OAuth2 Provider. The access token issued to the client will be limited to the scopes granted. The scope syntax is as follow: + ```text scope := "rpc://"rpc-string diff --git a/docs/Reference/quorum.js/RawTransactionManager.md b/docs/Reference/quorum.js/RawTransactionManager.md index bffbf894..0c445381 100644 --- a/docs/Reference/quorum.js/RawTransactionManager.md +++ b/docs/Reference/quorum.js/RawTransactionManager.md @@ -54,7 +54,7 @@ txnMngr.sendRawTransaction(args); ```js txnMngr.sendRawTransaction(txnParams); ``` -Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnParams` with the response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, RLP encodes the transaction in hex format, and submits the signed transaction to the blockchain with `eth_sendRawPrivateTransaction`. +Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnParams` with the response (encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, RLP encodes the transaction in hex format, and submits the signed transaction to the blockchain with `eth_sendRawPrivateTransaction`. #### Parameters 1. `txnParams` - The transaction to sign and send @@ -82,7 +82,7 @@ A promise that resolves to the transaction receipt if the transaction was sent s txnMngr.sendRawTransactionViaSendAPI(txnParams); ``` -Calls Privacy Manager's `/send` API to encrypt txn data and send to all participant Privacy Manager nodes, replaces `data` field in `txnParams` with response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, and submits the signed transaction to the blockchain with `eth_sendRawTransaction`. +Calls Privacy Manager's `/send` API to encrypt txn data and send to all participant Privacy Manager nodes, replaces `data` field in `txnParams` with response (encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, and submits the signed transaction to the blockchain with `eth_sendRawTransaction`. #### Parameters 1. `txnParams` - The transaction to sign and send @@ -118,7 +118,7 @@ txnMngr.storeRawRequest(data, privateFrom); Calls Tessera's `ThirdParty` `/storeraw` API to encrypt the provided `data` and store in preparation for a `eth_sendRawPrivateTransaction`. #### Parameters -1. `data`: `String` - Hex encoded private transaction data (i.e. value of `data`/`input` field in the transaction) +1. `data`: `String` - Hex encoded private transaction data (value of `data`/`input` field in the transaction) 1. `privateFrom`: `String` - Sending party's base64-encoded public key #### Returns diff --git a/docs/Reference/quorum.js/extend.md b/docs/Reference/quorum.js/extend.md index 6db75529..634448a3 100644 --- a/docs/Reference/quorum.js/extend.md +++ b/docs/Reference/quorum.js/extend.md @@ -15,7 +15,7 @@ web3.quorum.eth.sendRawPrivateTransaction(signedTx, args); | param | type | required | description | | :---: | :---: | :---: | --- | | `web3` | `Object` | yes | web3 instance | -| `apis` | `String` | no | comma-separated list of APIs to extend `web3` with. Default is to add all APIs, i.e. `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` | +| `apis` | `String` | no | comma-separated list of APIs to extend `web3` with. Default is to add all APIs, that is `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` | ## Methods See the [Raft](../Consensus/Raft-RPC-API.md), [Istanbul](../Consensus/IBFT-RPC-API.md), [Privacy](../APIs/PrivacyAPI.md), and [Permissioning](../APIs/PermissioningAPIs.md) API documentation for API details. diff --git a/docs/Tutorials/Creating-A-Network-From-Scratch.md b/docs/Tutorials/Creating-A-Network-From-Scratch.md index 0edb1cc7..3a734958 100644 --- a/docs/Tutorials/Creating-A-Network-From-Scratch.md +++ b/docs/Tutorials/Creating-A-Network-From-Scratch.md @@ -170,15 +170,15 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Edit `static-nodes.json` and add new entry for the new node you are configuring (should be last) - ``` + ``` vim new-node-2/static-nodes.json - .... append new-node-2's enode generated in step 1, port 21001;IP 127.0.0.1 and raft port set as 50001 + .... append new-node-2's enode generated in step 1, port 21001;IP 127.0.0.1 and raft port set as 50001 - [ + [ "enode://70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8@127.0.0.1:21000?discport=0&raftport=50000", "enode://56e81550db3ccbfb5eb69c0cfe3f4a7135c931a1bae79ea69a1a1c6092cdcbea4c76a556c3af977756f95d8bf9d7b38ab50ae070da390d3abb3d7e773099c1a9@127.0.0.1:21001?discport=0&raftport=50001" - ] - ``` + ] + ``` 1. Initialize new node as given below: @@ -324,7 +324,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` mkdir node0 node1 node2 node3 node4 ``` -1. Change into the lead (whichever one you consider first) node's working directory and generate the setup files for X initial validator nodes by executing `istanbul setup --num X --nodes --quorum --save --verbose` **only execute this instruction once, i.e. not X times**. This command will generate several items of interest: `static-nodes.json`, `genesis.json`, and nodekeys for all the initial validator nodes which will sit in numbered directories from 0 to X-1 +1. Change into the lead (whichever one you consider first) node's working directory and generate the setup files for X initial validator nodes by executing `istanbul setup --num X --nodes --quorum --save --verbose` **only execute this instruction once, that is not X times**. This command will generate several items of interest: `static-nodes.json`, `genesis.json`, and nodekeys for all the initial validator nodes which will sit in numbered directories from 0 to X-1 ``` cd node0 ../istanbul-tools/build/bin/istanbul setup --num 5 --nodes --quorum --save --verbose diff --git a/docs/Tutorials/permissioned-nodes.md b/docs/Tutorials/permissioned-nodes.md index 5f6fe87e..3388f281 100644 --- a/docs/Tutorials/permissioned-nodes.md +++ b/docs/Tutorials/permissioned-nodes.md @@ -1,4 +1,6 @@ -``` +# Permissioned nodes example + +```json [ "enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@127.0.0.1:21000?discport=0&raftport=50401", "enode://0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416@127.0.0.1:21001?discport=0&raftport=50402", From 5d3af597c3fca5cbdd1574734767fb71eb8a4479 Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Tue, 22 Sep 2020 13:00:48 +0200 Subject: [PATCH 5/9] fix md --- docs/Reference/CakeshopFAQ.md | 7 +- docs/Reference/Consensus/IBFT-RPC-API.md | 82 +++-- docs/Reference/Consensus/IBFTParameters.md | 3 +- docs/Reference/Consensus/Raft-RPC-API.md | 326 +++++++++--------- docs/Reference/FAQ.md | 13 +- .../Plugins/helloworld/implementation.md | 6 +- docs/Reference/Plugins/security/For-Users.md | 83 ++--- docs/Reference/RemixPlugin/GettingStarted.md | 8 +- docs/Reference/RemixPlugin/Overview.md | 1 + docs/Reference/quorum.js/Overview.md | 6 + .../quorum.js/RawTransactionManager.md | 68 +++- docs/Reference/quorum.js/extend.md | 10 + docs/Tutorials/CreatePermissionedNetwork.md | 24 +- .../Creating-A-Network-From-Scratch.md | 296 ++++++++++------ 14 files changed, 567 insertions(+), 366 deletions(-) diff --git a/docs/Reference/CakeshopFAQ.md b/docs/Reference/CakeshopFAQ.md index 375cab4c..20b5f635 100644 --- a/docs/Reference/CakeshopFAQ.md +++ b/docs/Reference/CakeshopFAQ.md @@ -1,8 +1,13 @@ +--- +description: CakeShop FAQ +--- + +# CakeShop FAQ + ??? question "How do I call contracts or send Transactions to existing contracts?" The "Sandbox" tab provides the ability to load up a contract that has been deployed using Cakeshop or the Cakeshop APIs and to make Read calls or submit Transactions to those contracts. - ??? question "How do I find existing contracts?" The "Contracts" explorer tab lists all contracts that have been deployed using Cakeshop sandbox. diff --git a/docs/Reference/Consensus/IBFT-RPC-API.md b/docs/Reference/Consensus/IBFT-RPC-API.md index 8a309113..11103fbe 100644 --- a/docs/Reference/Consensus/IBFT-RPC-API.md +++ b/docs/Reference/Consensus/IBFT-RPC-API.md @@ -1,129 +1,171 @@ +--- +description: Istanbul RPC API +--- + # Istanbul RPC API ## Getting Started + 1. Run Istanbul geth with `--rpcapi "istanbul"` 1. `geth attach` ## API Reference ### istanbul.candidates + Candidates returns the current candidates which the node tries to vote in or out. -``` + +```js istanbul.candidates ``` #### Returns + `map[string] boolean` - returns the current candidates map. ### istanbul.discard + Discard drops a currently running candidate, stopping the validator from casting further votes (either for or against). -``` + +```js istanbul.discard(address) ``` #### Parameters + `string` - the address of the candidate ### istanbul.getSnapshot + GetSnapshot retrieves the state snapshot at a given block. -``` + +```js istanbul.getSnapshot(blockHashOrBlockNumber) ``` #### Parameters + `String|Number` - The block number, the string "latest" or nil. nil is the same with string "latest" and means the latest block #### Returns + `Object` - The snapshot object ### istanbul.getSnapshotAtHash + GetSnapshotAtHash retrieves the state snapshot at a given block. -``` + +```js istanbul.getSnapshotAtHash(blockHash) ``` #### Parameters + `String` - The block hash #### Returns + `Object` - The snapshot object ### istanbul.getValidators + GetValidators retrieves the list of authorized validators at the specified block. -``` + +```js istanbul.getValidators(blockHashOrBlockNumber) ``` #### Parameters + `String|Number` - The block number, the string "latest" or nil. nil is the same with string "latest" and means the latest block #### Returns + `[]string` - The validator address array ### istanbul.getValidatorsAtHash + GetValidatorsAtHash retrieves the list of authorized validators at the specified block. -``` + +```js istanbul.getValidatorsAtHash(blockHash) ``` #### Parameters + `String` - The block hash #### Returns + `[]string` - The validator address array ### istanbul.propose + Propose injects a new authorization candidate that the validator will attempt to push through. If the number of vote is larger than 1/2 of validators to vote in/out, the candidate will be added/removed in validator set. -``` +```js istanbul.propose(address, auth) ``` #### Parameters + `String` - The address of candidate `bool` - `true` votes in and `false` votes out ### istanbul.nodeAddress + Retrieves the public address that is used to sign proposals, which is derived from the nodes `nodekey`. -``` + +```js istanbul.nodeAddress() ``` #### Returns + `string` - The nodes public signing address ### istanbul.getSignersFromBlock + Retrieves the public addresses for whose seals are included in the block. This means that they participated in the consensus for this block and attested to its validity. A block number may be optionally given, or else the current block is assumed. -``` + +```js istanbul.getSignersFromBlock(blockNumber) ``` #### Parameters + `Number` - The block number to retrieve #### Returns -`Object` - - - `number`: `Number` - The retrieved block's number - - `hash`: `String` - The retrieved block's hash - - `author`: `String` - The address of the block proposer - - `committers`: `[]String` - The list of all addresses whose seal appears in this block + +`Object` + +- `number`: `Number` - The retrieved block's number +- `hash`: `String` - The retrieved block's hash +- `author`: `String` - The address of the block proposer +- `committers`: `[]String` - The list of all addresses whose seal appears in this block ### istanbul.getSignersFromBlockByHash + Retrieves the public addresses for whose seals are included in the block. This means that they participated in the consensus for this block and attested to its validity. A block hash must be given, and does NOT default to the current latest block. -``` + +```js istanbul.getSignersFromBlockByHash(blockHash) ``` #### Parameters + `String` - The hash of the block to retrieve #### Returns -`Object` - - - `number`: `Number` - The retrieved block's number - - `hash`: `String` - The retrieved block's hash - - `author`: `String` - The address of the block proposer - - `committers`: `[]String` - The list of all addresses whose seal appears in this block + +`Object` + +- `number`: `Number` - The retrieved block's number +- `hash`: `String` - The retrieved block's hash +- `author`: `String` - The address of the block proposer +- `committers`: `[]String` - The list of all addresses whose seal appears in this block diff --git a/docs/Reference/Consensus/IBFTParameters.md b/docs/Reference/Consensus/IBFTParameters.md index 10d55942..da4c420e 100644 --- a/docs/Reference/Consensus/IBFTParameters.md +++ b/docs/Reference/Consensus/IBFTParameters.md @@ -29,7 +29,8 @@ Within the `genesis.json` file, there is an area for IBFT specific configuration configuration. The options are as follows: -``` + +```json { "config": { "istanbul": { diff --git a/docs/Reference/Consensus/Raft-RPC-API.md b/docs/Reference/Consensus/Raft-RPC-API.md index cc83ee15..7501cf80 100644 --- a/docs/Reference/Consensus/Raft-RPC-API.md +++ b/docs/Reference/Consensus/Raft-RPC-API.md @@ -1,14 +1,18 @@ +--- +description: Raft RPC API +--- + # Raft RPC API -### raft_cluster +## raft_cluster Returns the details of all nodes part of the raft cluster -#### Parameters +### Parameters None -#### Returns +### Returns * `hostName`: DNS name or the host IP address * `nodeActive`: true if the node is active in raft cluster else false @@ -18,257 +22,257 @@ None * `raftPort`: raft port * `role`: role of the node in raft GoQuorum. Can be minter/ verifier/ learner. In case there is no leader at network level it will be returned as `""` -#### Examples - -=== "JSON RPC" - - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_cluster", "id":10}' --header "Content-Type: application/json" - - // Response - {"jsonrpc":"2.0","id":10,"result":[{"raftId":1,"nodeId":"ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef","p2pPort":21000,"raftPort":50401,"hostname":"127.0.0.1","role":"minter","nodeActive":true},{"raftId":3,"nodeId":"579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778","p2pPort":21002,"raftPort":50403,"hostname":"127.0.0.1","role":"verifier","nodeActive":true},{"raftId":2,"nodeId":"0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416","p2pPort":21001,"raftPort":50402,"hostname":"127.0.0.1","role":"verifier","nodeActive":true}]} - ``` - -=== "geth console" - - ```javascript - > raft.cluster - [{ - hostname: "127.0.0.1", - nodeActive: true, - nodeId: "0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416", - p2pPort: 21001, - raftId: 2, - raftPort: 50402, - role: "verifier" - }, { - hostname: "127.0.0.1", - nodeActive: true, - nodeId: "579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778", - p2pPort: 21002, - raftId: 3, - raftPort: 50403, - role: "verifier" - }, { - hostname: "127.0.0.1", - nodeActive: true, - nodeId: "ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef", - p2pPort: 21000, - raftId: 1, - raftPort: 50401, - role: "minter" - }] - ``` - -### raft_role +!!! example + + === "JSON RPC" + + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_cluster", "id":10}' --header "Content-Type: application/json" + + // Response + {"jsonrpc":"2.0","id":10,"result":[{"raftId":1,"nodeId":"ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef","p2pPort":21000,"raftPort":50401,"hostname":"127.0.0.1","role":"minter","nodeActive":true},{"raftId":3,"nodeId":"579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778","p2pPort":21002,"raftPort":50403,"hostname":"127.0.0.1","role":"verifier","nodeActive":true},{"raftId":2,"nodeId":"0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416","p2pPort":21001,"raftPort":50402,"hostname":"127.0.0.1","role":"verifier","nodeActive":true}]} + ``` + + === "geth console" + + ```javascript + > raft.cluster + [{ + hostname: "127.0.0.1", + nodeActive: true, + nodeId: "0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416", + p2pPort: 21001, + raftId: 2, + raftPort: 50402, + role: "verifier" + }, { + hostname: "127.0.0.1", + nodeActive: true, + nodeId: "579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778", + p2pPort: 21002, + raftId: 3, + raftPort: 50403, + role: "verifier" + }, { + hostname: "127.0.0.1", + nodeActive: true, + nodeId: "ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef", + p2pPort: 21000, + raftId: 1, + raftPort: 50401, + role: "minter" + }] + ``` + +## raft_role Returns the role of the current node in raft cluster -#### Parameters +### Parameters None -#### Returns +### Returns * `result`: role of the node in raft cluster. Can be minter/ verifier/ learner. In case there is no leader at network level it will be returned as `""` -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_role", "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_role", "id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":"verifier"} - ``` + // Response + {"jsonrpc":"2.0","id":10,"result":"verifier"} + ``` -=== "geth console" + === "geth console" - ```javascript - > raft.role - "minter" - ``` + ```javascript + > raft.role + "minter" + ``` -### raft_leader +## raft_leader Returns enode id of the leader node -#### Parameters +### Parameters None -#### Returns +### Returns * `result`: enode id of the leader -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_leader", "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_leader", "id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":"ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef"} - ``` + // Response + {"jsonrpc":"2.0","id":10,"result":"ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef"} + ``` + + === "geth console" -=== "geth console" + ```javascript + > raft.leader + "ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef" + ``` + + If there is no leader at the network level, the call to the api will result in the following error: ```javascript > raft.leader - "ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef" + Error: no leader is currently elected + at web3.js:3143:20 + at web3.js:6347:15 + at get (web3.js:6247:38) + at ``` -If there is no leader at the network level, the call to the api will result in the following error: - -```javascript -> raft.leader -Error: no leader is currently elected - at web3.js:3143:20 - at web3.js:6347:15 - at get (web3.js:6247:38) - at -``` - -### raft_addPeer +## raft_addPeer API for adding a new peer to the network. -#### Parameters +### Parameters * `enodeId`: enode id of the node to be added to the network -#### Returns +### Returns * `result`: raft id for the node being added -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_addPeer","params": ["enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405"], "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_addPeer","params": ["enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405"], "id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":5} - ``` + // Response + {"jsonrpc":"2.0","id":10,"result":5} + ``` -=== "geth console" + === "geth console" - ```javascript - > raft.addPeer("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") - 5 - ``` + ```javascript + > raft.addPeer("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") + 5 + ``` -The new node can join the network with `geth` option of `--raftjoinexisting <>` + The new node can join the network with `geth` option of `--raftjoinexisting <>` -If the node being added is already part of the network the of the network, the following error is thrown: + If the node being added is already part of the network the of the network, the following error is thrown: -```javascript -> raft.addPeer("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") -Error: node with this enode has already been added to the cluster: f06c06f1e958cb2edf90d8bfb912de287f9b047b4228436e94b5b78e3ee16171 - at web3.js:3143:20 - at web3.js:6347:15 - at web3.js:5081:36 - at :1:1 -``` + ```javascript + > raft.addPeer("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") + Error: node with this enode has already been added to the cluster: f06c06f1e958cb2edf90d8bfb912de287f9b047b4228436e94b5b78e3ee16171 + at web3.js:3143:20 + at web3.js:6347:15 + at web3.js:5081:36 + at :1:1 + ``` -### raft_removePeer +## raft_removePeer API to remove a node from raft cluster -#### Parameters +### Parameters * `raftId` : raft id of the node to be removed from the cluster -#### Returns +### Returns * `result`: null -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_removePeer","params": [4], "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_removePeer","params": [4], "id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":null} - ``` + // Response + {"jsonrpc":"2.0","id":10,"result":null} + ``` -=== "geth console" + === "geth console" - ```javascript - > raft.removePeer(4) - null - ``` + ```javascript + > raft.removePeer(4) + null + ``` -### raft_addLearner +## raft_addLearner API to add a new node to the network as a learner node. The learner node syncs with network and can transact but will not be part of raft GoQuorum and hence will not provide block confirmation to minter node. -#### Parameters +### Parameters * `enodeId` -#### Returns +### Returns * `result`: raft id for the node being added -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_addLearner","params": ["enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405"], "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_addLearner","params": ["enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405"], "id":10}' --header "Content-Type: application/json" - // Response - {"jsonrpc":"2.0","id":10,"result":5} + // Response + {"jsonrpc":"2.0","id":10,"result":5} - ``` + ``` -=== "geth console" + === "geth console" - ```javascript - > raft.addLearner("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") - 5 - ``` + ```javascript + > raft.addLearner("enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405") + 5 + ``` -### raft_promoteToPeer +## raft_promoteToPeer API for promoting a learner node to peer and thus be part of the raft GoQuorum. -#### Parameters +### Parameters * `raftId`: raft id of the node to be promoted -#### Returns +### Returns * `result`: true or false -#### Examples +!!! example -=== "JSON RPC" + === "JSON RPC" - ```jshelllanguage - // Request - curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_promoteToPeer","params": [4], "id":10}' --header "Content-Type: application/json" + ```jshelllanguage + // Request + curl -X POST http://127.0.0.1:22001 --data '{"jsonrpc":"2.0","method":"raft_promoteToPeer","params": [4], "id":10}' --header "Content-Type: application/json" - // Response - {// Response - {"jsonrpc":"2.0","id":10,"result":true} - ``` + // Response + {// Response + {"jsonrpc":"2.0","id":10,"result":true} + ``` -=== "geth console" + === "geth console" - ```javascript - > raft.promoteToPeer(4) - true - ``` + ```javascript + > raft.promoteToPeer(4) + true + ``` diff --git a/docs/Reference/FAQ.md b/docs/Reference/FAQ.md index 6c8e149b..6890fc23 100644 --- a/docs/Reference/FAQ.md +++ b/docs/Reference/FAQ.md @@ -1,4 +1,10 @@ -### GoQuorum FAQ +--- +description: FAQ +--- + +# FAQ + +## GoQuorum FAQ ??? question "I've run into an issue with GoQuorum, where do I get support?" The [GoQuorum Slack channels](https://93ecjxb0d3.execute-api.us-east-1.amazonaws.com/Express/) are the best place to query the community and get immediate help. @@ -58,8 +64,7 @@ | ---------------------- | ---------------------- | ---------------------- | | Geth v1.7.2 | Geth v1.8.12 | Geth v1.8.18 | - -### Tessera FAQ +## Tessera FAQ ??? question "What does enabling 'disablePeerDiscovery' mean?" It means the node will only communicate with the nodes defined in the configuration file. Upto version 0.10.2, the nodes still accepts transactions from undiscovered nodes. From version 0.10.3 the node blocks all communication with undiscovered nodes. @@ -67,7 +72,7 @@ ??? info "Upgrading to Tessera version 0.10.+ from verion 0.9.+ and below" Due to 'database file unable to open' issue with H2 DB upgrade from version 1.4.196 direct to version 1.4.200 as explained [here](https://github.com/h2database/h2database/issues/2263), our recommended mitigation strategy is to upgrade to version 1.4.199 first before upgrading to version 1.4.200, first upgrade to Tessera 0.10.0 before upgrading to higher versions. -### Raft FAQ +## Raft FAQ ??? question "Could you have a single- or two-node cluster? More generally, could you have an even number of nodes?" A cluster can tolerate failures that leave a GoQuorum (majority) available. A cluster of two nodes can't tolerate any failures, three nodes can tolerate one, and five nodes can tolerate two. Typically Raft clusters have an odd number of nodes, since an even number provides no failure tolerance benefit. diff --git a/docs/Reference/Plugins/helloworld/implementation.md b/docs/Reference/Plugins/helloworld/implementation.md index 21aa00c1..8d0d8bd4 100644 --- a/docs/Reference/Plugins/helloworld/implementation.md +++ b/docs/Reference/Plugins/helloworld/implementation.md @@ -1,6 +1,8 @@ -title: helloworld - Plugin Implementation - Quorum +--- +description: helloworld - Plugin Implementation +--- -# `helloworld` Plugin +# helloworld - Plugin Implementation | Version | Language | |:--------|:---------| diff --git a/docs/Reference/Plugins/security/For-Users.md b/docs/Reference/Plugins/security/For-Users.md index 80111da0..e3666b49 100644 --- a/docs/Reference/Plugins/security/For-Users.md +++ b/docs/Reference/Plugins/security/For-Users.md @@ -10,12 +10,12 @@ providing the following enterprise features to `geth` JSON RPC server: One of the below blocks must be configured: -
+```json
 {
-    "tls": object(TLSConfiguration),
-    "tokenValidation": object(TokenValidationConfiguration)
+    "tls": object(TLSConfiguration),
+    "tokenValidation": object(TokenValidationConfiguration)
 }
-
+``` | Fields | Description | |:--------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -24,14 +24,14 @@ One of the below blocks must be configured: ### `TLSConfiguration` -
+```json
 {
     "auto": bool,
-    "certFile": EnvironmentAwaredValue,
-    "keyFile": EnvironmentAwaredValue,
-    "advanced": object(TLSAdvancedConfiguration)
+    "certFile": EnvironmentAwaredValue,
+    "keyFile": EnvironmentAwaredValue,
+    "advanced": object(TLSAdvancedConfiguration)
 }
-
+``` | Fields | Description | |:-----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -42,11 +42,11 @@ One of the below blocks must be configured: ### `TLSAdvancedConfiguration` -
+```json
 {
     "cipherSuites": array,
 }
-
+``` | Fields | Description | |:---------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -54,15 +54,16 @@ One of the below blocks must be configured: ### `TokenValidationConfiguration` -
+```json
 {
     "issuers": array,
-    "cache": object(CacheConfiguration),
-    "introspect": object(IntrospectionConfiguration),
-    "jws": object(JWSConfiguration),
-    "jwt": object(JWTConfiguration),
+    "cache": object(CacheConfiguration),
+    "introspect": object(IntrospectionConfiguration),
+    "jws": object(JWSConfiguration),
+    "jwt": object(JWTConfiguration),
 }
-
+``` + | Fields | Description | |:-------------|:---------------------------------------------------------------------------------------| | `issuers` | Array of strings specifying approved entities who issue tokens | @@ -76,12 +77,12 @@ One of the below blocks must be configured: An LRU cache which also checks for expiration before returning the value. Below is the default configuration if not specified -
+```json
 {
     "limit": 80,
     "expirationInSeconds": 3600
 }
-
+``` | Fields | Description | |:----------------------|:-----------------------------------| @@ -90,13 +91,13 @@ Below is the default configuration if not specified ### `IntrospectionConfiguration` -
+```json
 {
     "endpoint": string,
-    "authentication": object(AuthenticationConfiguration),
-    "tlsConnection": object(TLSConnectionConfiguration)
+    "authentication": object(AuthenticationConfiguration),
+    "tlsConnection": object(TLSConnectionConfiguration)
 }
-
+``` | Fields | Description | |:-----------------|:--------------------------------------------------------------| @@ -106,12 +107,12 @@ Below is the default configuration if not specified ### `AuthenticationConfiguration` -
+```json
 {
     "method": string,
-    "credentials": map(string->EnvironmentAwaredValue)
+    "credentials": map(string->EnvironmentAwaredValue)
 }
-
+``` | Fields | Description | |:--------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -126,13 +127,13 @@ Below is the default configuration if not specified ### `TLSConnectionConfiguration` -
+```json
 {
     "insecureSkipVerify": bool,
-    "certFile": EnvironmentAwaredValue,
-    "caFile": EnvironmentAwaredValue
+    "certFile": EnvironmentAwaredValue,
+    "caFile": EnvironmentAwaredValue
 }
-
+``` | Fields | Description | |:---------------------|:--------------------------------------------------------------------------------------------| @@ -142,12 +143,12 @@ Below is the default configuration if not specified ### `JWSConfiguration` -
+```json
 {
     "endpoint": string,
-    "tlsConnection": object(TLSConnectionConfiguration)
+    "tlsConnection": object(TLSConnectionConfiguration)
 }
-
+``` | Fields | Description | |:----------------|:---------------------------------------------------| @@ -156,12 +157,12 @@ Below is the default configuration if not specified ### `JWTConfiguration` -
+```json
 {
     "authorizationField": string,
     "preferIntrospection": bool
 }
-
+``` | Fields | Description | |:----------------------|:--------------------------------------------------------------------------------------| @@ -226,10 +227,10 @@ The scope syntax is as follow: ### Examples -#### Protecting APIs +!!! example "Protecting APIs" -| Scope | Description | -|:-------------------------------|:--------------------------------------------------------------------------------------------| -| `rpc://web3.clientVersion` | Allow access to `web3_clientVersion` API | -| `rpc://eth_*`
or `rpc://eth_` | Allow access to all APIs under `eth` namespace | -| `rpc://*_version`
or `rpc://_version` | Allow access to `version` method of all namespaces.
E.g.: `net_version`, `ssh_version` | + | Scope | Description | + |:-------------------------------|:--------------------------------------------------------------------------------------------| + | `rpc://web3.clientVersion` | Allow access to `web3_clientVersion` API | + | `rpc://eth_*`
or `rpc://eth_` | Allow access to all APIs under `eth` namespace | + | `rpc://*_version`
or `rpc://_version` | Allow access to `version` method of all namespaces.
E.g.: `net_version`, `ssh_version` | diff --git a/docs/Reference/RemixPlugin/GettingStarted.md b/docs/Reference/RemixPlugin/GettingStarted.md index 6e9d79d3..5a7febc8 100644 --- a/docs/Reference/RemixPlugin/GettingStarted.md +++ b/docs/Reference/RemixPlugin/GettingStarted.md @@ -34,16 +34,16 @@ ![method_call](images/method_call.png) -10. To create a private contract, add your Tessera public keys one at a time to the Private For multi-select box. Press enter after inputting each one to save and select. +1. To create a private contract, add your Tessera public keys one at a time to the Private For multi-select box. Press enter after inputting each one to save and select. ![private_add](images/private_add.png) -11. Add as many peers as you want, then deploy the contract again like you did in step 7. +1. Add as many peers as you want, then deploy the contract again like you did in step 7. ![private_multiple](images/private_multiple.png) -12. After deploying and expanding the new contract, you should see the public keys that you selected in the widget. Every method call will include the selected keys automatically. +1. After deploying and expanding the new contract, you should see the public keys that you selected in the widget. Every method call will include the selected keys automatically. ![deployed_private](images/deployed_private.png) -13. Please open a github issue or reach out to us on our [Slack](https://www.goquorum.com/slack-inviter) with any feedback or questions! +1. Please open a github issue or reach out to us on our [Slack](https://www.goquorum.com/slack-inviter) with any feedback or questions! diff --git a/docs/Reference/RemixPlugin/Overview.md b/docs/Reference/RemixPlugin/Overview.md index f29e7cad..086c6cdc 100644 --- a/docs/Reference/RemixPlugin/Overview.md +++ b/docs/Reference/RemixPlugin/Overview.md @@ -9,6 +9,7 @@ The GoQuorum plugin for Ethereum's Remix IDE adds support for creating and inter Just go to the [Remix IDE](https://remix.ethereum.org) and activate the **GoQuorum Network** plugin on the plugins page. For step-by-step instructions, go to the [Getting Started](GettingStarted.md) doc. ## Contributing + GoQuorum Plugin for Remix is built on open source and we invite you to contribute enhancements. Upon review you will be required to complete a Contributor License Agreement (CLA) before we are able to merge. If you have any questions about the contribution process, please feel free to send an email to [quorum@consensys.net](mailto:quorum@consensys.net). diff --git a/docs/Reference/quorum.js/Overview.md b/docs/Reference/quorum.js/Overview.md index 50b59143..72fb635b 100644 --- a/docs/Reference/quorum.js/Overview.md +++ b/docs/Reference/quorum.js/Overview.md @@ -1,9 +1,15 @@ +--- +description: quorum.js +--- + # quorum.js ## Overview, Installation, Quickstart & Examples + See the [project page README](https://github.com/ConsenSys/quorum.js). ## API + This documentation provides additional usage and API information not included in the README. quorum.js exports two modules: diff --git a/docs/Reference/quorum.js/RawTransactionManager.md b/docs/Reference/quorum.js/RawTransactionManager.md index 0c445381..28580d41 100644 --- a/docs/Reference/quorum.js/RawTransactionManager.md +++ b/docs/Reference/quorum.js/RawTransactionManager.md @@ -1,6 +1,13 @@ +--- +description: RawTransactionManager module +--- + +# RawTransactionManager module + The `RawTransactionManager` module of quorum.js provides access to private transaction APIs that require a connection to a [Privacy Manager](../../Concepts/Privacy/PrivateTransactionManager.md). ## Example + ```js const Web3 = require("web3"); const quorumjs = require("quorum-js"); @@ -24,39 +31,44 @@ txnMngr.sendRawTransaction(args); ``` ## Parameters -| param | type | required | description | -| :---: | :---: | :---: | --- | -| `web3` | `Object` | yes | web3 instance | -| `enclaveOptions` | `Object` | yes | Privacy Manager connection configuration - see [enclaveOptions](#enclaveoptions) | + +| param | type | required | description | +|-:-:--------------|-:-:------|-:-:------|----------------------------------------------------------------------------------| +| `web3` | `Object` | yes | web3 instance | +| `enclaveOptions` | `Object` | yes | Privacy Manager connection configuration - see [enclaveOptions](#enclaveoptions) | ### enclaveOptions -| param | type | required | description | -| :---: | :---: | :---: | --- | -| `privateUrl` | `String` | yes (unless `ipcPath` is provided) | Tessera `ThirdParty` server url (if using the Constellation Privacy Manager use `ipcPath` instead) | -| `ipcPath` | `String` | no | path to Privacy Manager `.ipc` socket file, `privateUrl` is preferred | -| `tlsSettings` | `Object` | no | TLS configuration for HTTPS Privacy Manager connections - see [tlsSettings](#tlssettings) | + +| param | type | required | description | +|-:-:-----------|-:-:------|-:-:--------------------------------|----------------------------------------------------------------------------------------------------| +| `privateUrl` | `String` | yes (unless `ipcPath` is provided) | Tessera `ThirdParty` server url (if using the Constellation Privacy Manager use `ipcPath` instead) | +| `ipcPath` | `String` | no | path to Privacy Manager `.ipc` socket file, `privateUrl` is preferred | +| `tlsSettings` | `Object` | no | TLS configuration for HTTPS Privacy Manager connections - see [tlsSettings](#tlssettings) | ### tlsSettings -| param | type | required | description | -| :---: | :---: | :---: | --- | -| `key` | `String` | no | client private key as byte string | -| `clcert` | `String` | no | client certificate (signed/unsigned) as byte string | -| `cacert` | `String` | no | CA certificate as byte string | -| `allowInsecure` | `boolean` | no | do not verify the Privacy Manager's certificate (can be used to allow self-signed certificates) | + +| param | type | required | description | +|-:-:-------------|-:-:-------|-:-:------|-------------------------------------------------------------------------------------------------| +| `key` | `String` | no | client private key as byte string | +| `clcert` | `String` | no | client certificate (signed/unsigned) as byte string | +| `cacert` | `String` | no | CA certificate as byte string | +| `allowInsecure` | `boolean` | no | do not verify the Privacy Manager's certificate (can be used to allow self-signed certificates) | ## Methods ### sendRawTransaction -!!! info "If using Constellation" +!!!info "If using Constellation" Constellation privacy managers do not support this method. Use [`sendRawTransactionViaSendAPI`](#sendrawtransactionviasendapi) instead. ```js txnMngr.sendRawTransaction(txnParams); ``` + Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnParams` with the response (encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, RLP encodes the transaction in hex format, and submits the signed transaction to the blockchain with `eth_sendRawPrivateTransaction`. #### Parameters + 1. `txnParams` - The transaction to sign and send - `gasPrice`: `Number` - Must always be 0 in Quorum networks - `gasLimit`: `Number` - The amount of gas to use for the transaction @@ -71,6 +83,7 @@ Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnP 1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. #### Returns + A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error. ### sendRawTransactionViaSendAPI @@ -85,6 +98,7 @@ txnMngr.sendRawTransactionViaSendAPI(txnParams); Calls Privacy Manager's `/send` API to encrypt txn data and send to all participant Privacy Manager nodes, replaces `data` field in `txnParams` with response (encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, and submits the signed transaction to the blockchain with `eth_sendRawTransaction`. #### Parameters + 1. `txnParams` - The transaction to sign and send - `gasPrice`: `Number` - Must always be 0 in Quorum networks - `gasLimit`: `Number` - The amount of gas to use for the transaction @@ -99,41 +113,57 @@ Calls Privacy Manager's `/send` API to encrypt txn data and send to all particip 1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. #### Returns + A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error. ### setPrivate + ```js txnMngr.setPrivate(rawTransaction); ``` + Marks a signed transaction as private by changing the value of `v` to `37` or `38`. + #### Parameters + 1. `rawTransaction`: `String` - RLP-encoded hex-format signed transaction + #### Returns + Updated RLP-encoded hex-format signed transaction ### storeRawRequest + ```js txnMngr.storeRawRequest(data, privateFrom); ``` + Calls Tessera's `ThirdParty` `/storeraw` API to encrypt the provided `data` and store in preparation for a `eth_sendRawPrivateTransaction`. #### Parameters + 1. `data`: `String` - Hex encoded private transaction data (value of `data`/`input` field in the transaction) 1. `privateFrom`: `String` - Sending party's base64-encoded public key #### Returns + A promise that resolves to the hex-encoded hash of the encrypted `data` (`key` field) that should be used to replace the `data` field of a transaction if externally signing. ### sendRawRequest + ```js txnMngr.sendRawRequest(rawTransaction, privateFor); ``` + Call `eth_sendRawPrivateTransaction`, sending the signed transaction to the recipients specified in `privateFor`. + #### Parameters + 1. `rawTransaction`: `String` - RLP-encoded hex-format signed transaction 1. `privateFor`: `List` - List of the recipients' base64-encoded public keys #### Returns + A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error. ## Examples @@ -146,19 +176,25 @@ A promise that resolves to the transaction receipt if the transaction was sent s [Code sample](https://github.com/ConsenSys/quorum.js/blob/master/7nodes-test/deployContractViaHttp-externalSigningTemplate.js). 1. `storeRawRequest` to encrypt the transaction `data` + ```js txnManager.storeRawRequest(data, from) ``` + 1. Replace `data` field of transaction with `key` field from `storeRawRequest` response 1. Sign the transaction 1. Mark the signed transaction as private with `setPrivate` + ```js txnManager.setPrivate(signedTx) ``` + 1. Send the signed transaction to Quorum with `sendRawRequest` + ```js txnManager.sendRawRequest(serializedTransaction, privateFor) ``` ### Other examples + The [7nodes-test](https://github.com/ConsenSys/quorum.js/tree/master/7nodes-test) directory in the quorum.js project repo contains examples of quorum.js usage. These scripts can be tested with a running [7nodes test network](https://github.com/ConsenSys/quorum-examples/tree/master/examples/7nodes). diff --git a/docs/Reference/quorum.js/extend.md b/docs/Reference/quorum.js/extend.md index 634448a3..ace3bfea 100644 --- a/docs/Reference/quorum.js/extend.md +++ b/docs/Reference/quorum.js/extend.md @@ -1,6 +1,13 @@ +--- +description: Extend module +--- + +# Extend module + The `extend` module of quorum.js allows Quorum-specific APIs to be added to an instance of `web3`. ## Example + ```js const Web3 = require("web3"); const quorumjs = require("quorum-js"); @@ -11,11 +18,14 @@ quorumjs.extend(web3); web3.quorum.eth.sendRawPrivateTransaction(signedTx, args); ``` + ## Parameters + | param | type | required | description | | :---: | :---: | :---: | --- | | `web3` | `Object` | yes | web3 instance | | `apis` | `String` | no | comma-separated list of APIs to extend `web3` with. Default is to add all APIs, that is `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` | ## Methods + See the [Raft](../Consensus/Raft-RPC-API.md), [Istanbul](../Consensus/IBFT-RPC-API.md), [Privacy](../APIs/PrivacyAPI.md), and [Permissioning](../APIs/PermissioningAPIs.md) API documentation for API details. diff --git a/docs/Tutorials/CreatePermissionedNetwork.md b/docs/Tutorials/CreatePermissionedNetwork.md index 681b119a..3cb2dfe7 100644 --- a/docs/Tutorials/CreatePermissionedNetwork.md +++ b/docs/Tutorials/CreatePermissionedNetwork.md @@ -1,3 +1,7 @@ +--- +description: Create a permissioned network +--- + # Create a permissioned network ## 1. Initialize chain @@ -7,7 +11,7 @@ The first step is to generate the genesis block. The `7nodes` directory in the `quorum-examples` repository contains several keys (using an empty password) that are used in the example genesis file: -``` +```text key1 vote key 1 key2 vote key 2 key3 vote key 3 @@ -16,6 +20,7 @@ key5 block maker 2 ``` Example genesis file (copy to `genesis.json`): + ``` json "config": { "homesteadBlock": 0, @@ -31,29 +36,30 @@ Example genesis file (copy to `genesis.json`): Initialize geth: -``` +```bash geth init genesis.json ``` ## 2. Setup Bootnode + Optionally you can set up a bootnode that all the other nodes will first connect to in order to find other peers in the network. You will first need to generate a bootnode key: 1. To generate the key for the first time: - ``` bash + ```bash bootnode -genkey tmp_file.txt // this will start a bootnode with an enode address and generate a key inside a “tmp_file.txt” file` ``` 1. To later restart the bootnode using the same key (and hence use the same enode url): - ``` bash + ```bash bootnode -nodekey tmp_file.txt ``` or - ``` bash + ```bash bootnode -nodekeyhex 77bd02ffa26e3fb8f324bda24ae588066f1873d95680104de5bc2db9e7b2e510 // Key from tmp_file.txt ``` @@ -62,7 +68,9 @@ other peers in the network. You will first need to generate a bootnode key: Starting a node is as simple as `geth`. This will start the node without any of the roles and makes the node a spectator. If you have setup a bootnode then be sure to add the `--bootnodes` param to your startup command: -`geth --bootnodes $BOOTNODE_ENODE` +```bash +geth --bootnodes $BOOTNODE_ENODE +``` ## Adding New Nodes @@ -72,5 +80,7 @@ subsequent incoming/outgoing requests are made. The node does not need to be res ## Removing existing nodes Removing existing connected nodes from the `permissioned-nodes.json` file does not immediately drop those -existing connected nodes. However, if the connection is dropped for any reason, and a subsequent connect +existing connected nodes. + +However, if the connection is dropped for any reason, and a subsequent connect request is made from the dropped node ids, it is rejected as part of that new request. diff --git a/docs/Tutorials/Creating-A-Network-From-Scratch.md b/docs/Tutorials/Creating-A-Network-From-Scratch.md index 3a734958..67d2bc1f 100644 --- a/docs/Tutorials/Creating-A-Network-From-Scratch.md +++ b/docs/Tutorials/Creating-A-Network-From-Scratch.md @@ -11,7 +11,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ## GoQuorum with Raft consensus 1. On each machine build GoQuorum as described in the [Installing](../HowTo/GetStarted/Install.md) section. Ensure that PATH contains geth and bootnode - ``` + + ```bash git clone https://github.com/ConsenSys/quorum.git cd quorum make all @@ -19,13 +20,16 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Create a working directory which will be the base for the new node(s) and change into it - ``` + + ```bash mkdir fromscratch cd fromscratch mkdir new-node-1 ``` + 1. Generate one or more accounts for this node and take down the account address. A funded account may be required depending what you are trying to accomplish - ``` + + ```bash geth --datadir new-node-1 account new INFO [06-07|14:52:18.742] Maximum peer count ETH=25 LES=0 total=25 @@ -44,7 +48,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co You could generate multiple accounts for a single node, or any number of accounts for additional nodes and pre-allocate them with funds in the genesis.json file (see below) 1. Create a `genesis.json` file see example [here](../Reference/genesis.md). The `alloc` field should be pre-populated with the account you generated at previous step - ``` + + ```bash vim genesis.json ... alloc holds 'optional' accounts with a pre-funded amounts. In this example we are funding the accounts 679fed8f4f3ea421689136b25073c6da7973418f (generated from the step above) and c5c7b431e1629fb992eb18a79559f667228cd055. { @@ -79,19 +84,25 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "timestamp": "0x00" } ``` + 1. Generate node key and copy it into datadir - ``` + + ```bash bootnode --genkey=nodekey cp nodekey new-node-1/ ``` + 1. Execute below command to display enode id of the new node - ``` + + ```bash bootnode --nodekey=new-node-1/nodekey --writeaddress > new-node-1/enode cat new-node-1/enode '70399c3d1654c959a02b73acbdd4770109e39573a27a9b52bd391e5f79b91a42d8f2b9e982959402a97d2cbcb5656d778ba8661ec97909abc72e7bb04392ebd8' ``` + 1. Create a file called `static-nodes.json` and edit it to match this [example](permissioned-nodes.md). Your file should contain a single line for your node with your enode's id and the ports you are going to use for devp2p and raft. Ensure that this file is in your nodes data directory - ``` + + ```bash vim static-nodes.json .... paste below lines with enode generated in previous step, port 21000;IP 127.0.0.1 and raft port set as 50000 [ @@ -99,8 +110,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ] cp static-nodes.json new-node-1 ``` + 1. Initialize new node with below command. - ``` + + ```bash geth --datadir new-node-1 init genesis.json INFO [06-07|15:45:17.508] Maximum peer count ETH=25 LES=0 total=25 @@ -113,8 +126,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co INFO [06-07|15:45:17.527] Persisted trie from memory database nodes=1 size=152.00B time=60.76µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-07|15:45:17.527] Successfully wrote genesis state database=lightchaindata hash=ec0542…9665bf ``` + 1. Start your node by first creating a script as below and then starting it: - ``` + + ```bash vim startnode1.sh ... paste below commands. It will start it in the background. #!/bin/bash @@ -128,7 +143,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co This configuration starts GoQuorum without privacy support as could be evidenced in prefix `PRIVATE_CONFIG=ignore`, please see below sections on [how to enable privacy with privacy transaction managers](#adding-privacy-transaction-manager). Your node is now operational and you may attach to it with below commands. - ``` + + ```bash geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! @@ -155,22 +171,26 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` ### Adding additional node + 1. Complete steps 1, 2, 5, and 6 from the previous guide - ``` + ```bash mkdir new-node-2 bootnode --genkey=nodekey2 cp nodekey2 new-node-2/nodekey bootnode --nodekey=new-node-2/nodekey --writeaddress 56e81550db3ccbfb5eb69c0cfe3f4a7135c931a1bae79ea69a1a1c6092cdcbea4c76a556c3af977756f95d8bf9d7b38ab50ae070da390d3abb3d7e773099c1a9 ``` + 1. Retrieve current chains `genesis.json` and `static-nodes.json`. `static-nodes.json` should be placed into new nodes data dir - ``` + + ```bash cp static-nodes.json new-node-2 ``` 1. Edit `static-nodes.json` and add new entry for the new node you are configuring (should be last) - ``` + + ```bash vim new-node-2/static-nodes.json .... append new-node-2's enode generated in step 1, port 21001;IP 127.0.0.1 and raft port set as 50001 @@ -182,7 +202,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. Initialize new node as given below: - ``` + ```bash geth --datadir new-node-2 init genesis.json INFO [06-07|16:34:39.805] Maximum peer count ETH=25 LES=0 total=25 @@ -197,7 +217,8 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Connect to an already running node of the chain and execute raft `addPeer` command. - ``` + + ```bash geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! @@ -225,8 +246,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co }] > exit ``` + 1. Start your node by first creating a script as previous step and changing the ports you are going to use for Devp2p and raft. - ``` + + ```bash cp startnode1.sh startnode2.sh vim startnode2.sh ..... paste below details @@ -237,18 +260,21 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Optional: share new `static-nodes.json` with all other chain participants - ``` + + ```bash cp new-node-2/static-nodes.json new-node-1 ``` Your additional node is now operational and is part of the same chain as the previously set up node. ### Removing node + 1. Connect to an already running node of the chain and execute `raft.cluster` and get the `RAFT_ID` corresponding to the node that needs to be removed 1. Run `raft.removePeer(RAFT_ID)` 1. Stop the `geth` process corresponding to the node that was removed. - ``` - geth attach new-node-1/geth.ipc + + ```bash + geth attach new-node-1/geth.ipc Welcome to the Geth JavaScript console! instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 @@ -301,72 +327,76 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 10695 ttys002 0:31.76 geth --datadir new-node-1 --nodiscover --verbosity 5 --networkid 31337 --raft --raftport 50000 --rpc --rpcaddr 0.0.0.0 --rpcport 22000 --rpcapi admin,db,eth,debug,miner,net,shh,txpoo ``` - - ## GoQuorum with Istanbul BFT consensus 1. On each machine build GoQuorum as described in the [Installing](../HowTo/GetStarted/Install.md) section. Ensure that PATH contains geth and boot node - ``` + + ```bash git clone https://github.com/ConsenSys/quorum.git cd quorum make all export PATH=$(pwd)/build/bin:$PATH ``` + 1. Install [istanbul-tools](https://github.com/ConsenSys/istanbul-tools) - ``` + + ```bash mkdir fromscratchistanbul cd fromscratchistanbul git clone https://github.com/ConsenSys/istanbul-tools.git cd istanbul-tools make ``` + 1. Create a working directory for each of the X number of initial validator nodes - ``` + + ```bash mkdir node0 node1 node2 node3 node4 ``` + 1. Change into the lead (whichever one you consider first) node's working directory and generate the setup files for X initial validator nodes by executing `istanbul setup --num X --nodes --quorum --save --verbose` **only execute this instruction once, that is not X times**. This command will generate several items of interest: `static-nodes.json`, `genesis.json`, and nodekeys for all the initial validator nodes which will sit in numbered directories from 0 to X-1 - ``` + + ```bash cd node0 ../istanbul-tools/build/bin/istanbul setup --num 5 --nodes --quorum --save --verbose validators { - "Address": "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", - "Nodekey": "fe2725c4e8f7617764b845e8d939a65c664e7956eb47ed7d934573f16488efc1", - "NodeInfo": "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0" + "Address": "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", + "Nodekey": "fe2725c4e8f7617764b845e8d939a65c664e7956eb47ed7d934573f16488efc1", + "NodeInfo": "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0" } { - "Address": "0x189d23d201b03ae1cf9113672df29a5d672aefa3", - "Nodekey": "3434f9efd184f2255f8acc9f4408a5068bd5ae920548044087578ab97ef22f3a", - "NodeInfo": "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@0.0.0.0:30303?discport=0" + "Address": "0x189d23d201b03ae1cf9113672df29a5d672aefa3", + "Nodekey": "3434f9efd184f2255f8acc9f4408a5068bd5ae920548044087578ab97ef22f3a", + "NodeInfo": "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@0.0.0.0:30303?discport=0" } { - "Address": "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", - "Nodekey": "8183051c9976200d245c59a80ae004f20c3f66e1aa1b8f17458931de91576e05", - "NodeInfo": "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@0.0.0.0:30303?discport=0" + "Address": "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", + "Nodekey": "8183051c9976200d245c59a80ae004f20c3f66e1aa1b8f17458931de91576e05", + "NodeInfo": "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@0.0.0.0:30303?discport=0" } { - "Address": "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52", - "Nodekey": "de415c5dbbb9ff0a34dbd3bf871ee41b230f431925e1f4cc1dd225ef47cc066f", - "NodeInfo": "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@0.0.0.0:30303?discport=0" + "Address": "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52", + "Nodekey": "de415c5dbbb9ff0a34dbd3bf871ee41b230f431925e1f4cc1dd225ef47cc066f", + "NodeInfo": "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@0.0.0.0:30303?discport=0" } { - "Address": "0x7ae555d0f6faad7930434abdaac2274fd86ab516", - "Nodekey": "768b87473ba96fcfa272f958fc95a3cefdf9aa82110cde6f2f34aa5855eb39db", - "NodeInfo": "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0" + "Address": "0x7ae555d0f6faad7930434abdaac2274fd86ab516", + "Nodekey": "768b87473ba96fcfa272f958fc95a3cefdf9aa82110cde6f2f34aa5855eb39db", + "NodeInfo": "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0" } static-nodes.json [ - "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0", - "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@0.0.0.0:30303?discport=0", - "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@0.0.0.0:30303?discport=0", - "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@0.0.0.0:30303?discport=0", - "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0" + "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0", + "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@0.0.0.0:30303?discport=0", + "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@0.0.0.0:30303?discport=0", + "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@0.0.0.0:30303?discport=0", + "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@0.0.0.0:30303?discport=0" ] - genesis.json { "config": { @@ -425,19 +455,22 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Update `static-nodes.json` to include the intended IP and port numbers of all initial validator nodes. In `static-nodes.json`, you will see a different row for each node. For the rest of the installation guide, row Y refers to node Y and row 1 is assumed to correspond to the lead node - ``` + + ```bash cat static-nodes.json .... update the IP and port numbers as give below... [ - "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@127.0.0.1:30300?discport=0", - "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@127.0.0.1:30301?discport=0", - "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@127.0.0.1:30302?discport=0", - "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@127.0.0.1:30303?discport=0", - "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@127.0.0.1:30304?discport=0" + "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@127.0.0.1:30300?discport=0", + "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@127.0.0.1:30301?discport=0", + "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@127.0.0.1:30302?discport=0", + "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@127.0.0.1:30303?discport=0", + "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@127.0.0.1:30304?discport=0" ] ``` + 1. In each node's working directory, create a data directory called `data`, and inside `data` create the `geth` directory - ``` + + ```bash cd .. mkdir -p node0/data/geth mkdir -p node1/data/geth @@ -445,8 +478,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co mkdir -p node3/data/geth mkdir -p node4/data/geth ``` + 1. Now we will generate initial accounts for any of the nodes in the required node's working directory. The resulting public account address printed in the terminal should be recorded. Repeat as many times as necessary. A set of funded accounts may be required depending what you are trying to accomplish - ``` + + ```bash geth --datadir node0/data account new INFO [06-11|16:05:53.672] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. @@ -466,8 +501,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Repeat passphrase: Address: {65a3ab6d4cf23395f544833831fc5d42a0b2b43a} ``` + 1. To add accounts to the initial block, edit the `genesis.json` file in the lead node's working directory and update the `alloc` field with the account(s) that were generated at previous step - ``` + + ```bash vim node0/genesis.json .... update the accounts under 'alloc' { @@ -507,8 +544,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" } ``` + 1. Next we need to distribute the files created in part 4, which currently reside in the lead node's working directory, to all other nodes. To do so, place `genesis.json` in the working directory of all nodes, place `static-nodes.json` in the data folder of each node and place `X/nodekey` in node (X-1)'s `data/geth` directory - ``` + + ```bash cp node0/genesis.json node1 cp node0/genesis.json node2 cp node0/genesis.json node3 @@ -524,8 +563,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co cp node0/3/nodekey node3/data/geth cp node0/4/nodekey node4/data/geth ``` -10. Switch into working directory of lead node and initialize it. Repeat for every working directory X created in step 3. *The resulting hash given by executing `geth init` must match for every node* - ``` + +1. Switch into working directory of lead node and initialize it. Repeat for every working directory X created in step 3. *The resulting hash given by executing `geth init` must match for every node* + + ```bash cd node0 geth --datadir data init genesis.json INFO [06-11|16:14:11.883] Maximum peer count ETH=25 LES=0 total=25 @@ -588,8 +629,9 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ cd.. ``` -11. Start all nodes by first creating a script and running it. - ``` +1. Start all nodes by first creating a script and running it. + + ```bash $ vim startall.sh .... paste below. The port numbers should match the port number for each node decided on in step 5 #!/bin/bash @@ -636,19 +678,23 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Your node is now operational and you may attach to it with `geth attach node0/data/geth.ipc`. ### Adding additional validator + 1. Create a working directory for the new node that needs to be added + + ```bash + mkdir node5 ``` - $ mkdir node5 - ``` + 1. Change into the working directory for the new node and run `istanbul setup --num 1 --verbose --quorum --save`. This will generate the validator details including Address, NodeInfo and genesis.json - ``` - $ cd node5 - $ ../istanbul-tools/build/bin/istanbul setup --num 1 --verbose --quorum --save + + ```bash + cd node5 + ../istanbul-tools/build/bin/istanbul setup --num 1 --verbose --quorum --save validators { - "Address": "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", - "Nodekey": "25b47a49ef08f888c04f30417363e6c6bc33e739147b2f8b5377b3168f9f7435", - "NodeInfo": "enode://273eaf48591ce0e77c800b3e6465811d6d2f924c4dcaae016c2c7375256d17876c3e05f91839b741fe12350da0b5a741da4e30f39553fe8790f88503c64f6ef9@0.0.0.0:30303?discport=0" + "Address": "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", + "Nodekey": "25b47a49ef08f888c04f30417363e6c6bc33e739147b2f8b5377b3168f9f7435", + "NodeInfo": "enode://273eaf48591ce0e77c800b3e6465811d6d2f924c4dcaae016c2c7375256d17876c3e05f91839b741fe12350da0b5a741da4e30f39553fe8790f88503c64f6ef9@0.0.0.0:30303?discport=0" } @@ -687,10 +733,11 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Copy the address of the validator and run `istanbul.propose(
, true)` from more than half the number of current validators. - ``` - $ cd .. - $ geth attach node0/data/geth.ipc - $ geth attach node0/data/geth.ipc + + ```bash + cd .. + geth attach node0/data/geth.ipc + geth attach node0/data/geth.ipc Welcome to the Geth JavaScript console! instance: Geth/v1.8.18-stable-bb88608c(quorum-v2.2.3)/darwin-amd64/go1.10.2 @@ -744,38 +791,47 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` 1. Verify that the new validator has been added to the list of validators by running `istanbul.getValidators()` - ``` + + ```bash ... you can see below command now displays 6 node address as validators. > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` + 1. Copy `static-nodes.json` and genesis.json from the existing chain. `static-nodes.json` should be placed into new nodes data dir - ``` + + ```bash $ cd node5 $ mkdir -p data/geth $ cp ../node0/static-nodes.json data $ cp ../node0/genesis.json . ``` + 1. Edit `static-nodes.json` and add the new validators node info to the end of the file. New validators node info can be got from the output of `istanbul setup --num 1 --verbose --quorum --save` command that was run in step 2. Update the IP address and port of the node info to match the IP address of the validator and port you want to use. - ``` + + ```bash $ vim data/static-nodes.json ...add new validate nodes details with correct IP and port details [ - "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@127.0.0.1:30300?discport=0", - "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@127.0.0.1:30301?discport=0", - "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@127.0.0.1:30302?discport=0", - "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@127.0.0.1:30303?discport=0", - "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@127.0.0.1:30304?discport=0", + "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@127.0.0.1:30300?discport=0", + "enode://1bb6be462f27e56f901c3fcb2d53a9273565f48e5d354c08f0c044405b29291b405b9f5aa027f3a75f9b058cb43e2f54719f15316979a0e5a2b760fff4631998@127.0.0.1:30301?discport=0", + "enode://0df02e94a3befc0683780d898119d3b675e5942c1a2f9ad47d35b4e6ccaf395cd71ec089fcf1d616748bf9871f91e5e3d29c1cf6f8f81de1b279082a104f619d@127.0.0.1:30302?discport=0", + "enode://3fe0ff0dd2730eaac7b6b379bdb51215b5831f4f48fa54a24a0298ad5ba8c2a332442948d53f4cd4fd28f373089a35e806ef722eb045659910f96a1278120516@127.0.0.1:30303?discport=0", + "enode://e53e92e5a51ac2685b0406d0d3c62288b53831c3b0f492b9dc4bc40334783702cfa74c49b836efa2761edde33a3282704273b2453537b855e7a4aeadcccdb43e@127.0.0.1:30304?discport=0", "enode://273eaf48591ce0e77c800b3e6465811d6d2f924c4dcaae016c2c7375256d17876c3e05f91839b741fe12350da0b5a741da4e30f39553fe8790f88503c64f6ef9@127.0.0.1:30305?discport=0" ] ``` + 1. Copy the nodekey that was generated by `istanbul setup` command to the `geth` directory inside the working directory - ``` + + ```bash $ cp 0/nodekey data/geth ``` + 1. Generate one or more accounts for this node and take down the account address. - ``` + + ```bash $ geth --datadir data account new INFO [06-12|17:45:11.116] Maximum peer count ETH=25 LES=0 total=25 Your new account is locked with a password. Please give a password. Do not forget this password. @@ -783,8 +839,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co Repeat passphrase: Address: {37922bce824bca2f3206ea53dd50d173b368b572} ``` + 1. Initialize new node with below command - ``` + + ```bash $ geth --datadir data init genesis.json INFO [06-11|16:42:27.120] Maximum peer count ETH=25 LES=0 total=25 INFO [06-11|16:42:27.130] Allocated cache and file handles database=/Users/krish/fromscratchistanbul/node5/data/geth/chaindata cache=16 handles=16 @@ -798,8 +856,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co $ ``` -10. Start the node by first creating below script and executing it: - ``` + +1. Start the node by first creating below script and executing it: + + ```bash $ cd .. $ cp startall.sh start6.sh $ vim start6.sh @@ -826,8 +886,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co ``` ### Removing validator + 1. Attach to a running validator and run `istanbul.getValidators()` and identify the address of the validator that needs to be removed - ``` + + ```bash $ geth attach node0/data/geth.ipc Welcome to the Geth JavaScript console! @@ -839,8 +901,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` + 1. Run `istanbul.propose(
, false)` by passing the address of the validator that needs to be removed from more than half current validators - ``` + + ```bash > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) null $ @@ -877,13 +941,17 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co > istanbul.propose("0x2aabbc1bb9bacef60a09764d1a1f4f04a47885c1",false) null ``` + 1. Verify that the validator has been removed by running `istanbul.getValidators()` - ``` + + ```bash > istanbul.getValidators() ["0x189d23d201b03ae1cf9113672df29a5d672aefa3", "0x44b07d2c28b8ed8f02b45bd84ac7d9051b3349e6", "0x4c1ccd426833b9782729a212c857f2f03b7b4c0d", "0x7ae555d0f6faad7930434abdaac2274fd86ab516", "0xc1056df7c02b6f1a353052eaf0533cc7cb743b52"] ``` + 1. Stop the `geth` process corresponding to the validator that was removed. - ``` + + ```bash $ ps PID TTY TIME CMD 10554 ttys000 0:00.11 -bash @@ -908,13 +976,13 @@ Same instructions as adding validator node **excluding** step 3 which proposes t Just execute **step 4** instruction from removing a validator node. - ## Adding privacy transaction manager ### Tessera 1. Build GoQuorum and install [Tessera](https://github.com/ConsenSys/tessera/releases) as described in the [Installing](../HowTo/GetStarted/Install.md) section. Ensure that PATH contains geth and bootnode. Be aware of the location of the `tessera.jar` release file - ``` + + ```bash $ git clone https://github.com/ConsenSys/quorum.git $ cd quorum $ make all @@ -924,8 +992,10 @@ Just execute **step 4** instruction from removing a validator node. $ mv tessera-app-0.9.2-app.jar tessera.jar ``` + 1. Generate new keys using `java -jar /path-to-tessera/tessera.jar -keygen -filename new-node-1` - ``` + + ```bash $ mkdir new-node-1t $ cd new-node-1t $ java -jar ../tessera.jar -keygen -filename new-node-1 @@ -938,8 +1008,10 @@ Just execute **step 4** instruction from removing a validator node. 10:32:51.624 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved public key to /Users/krish/fromscratch/new-node-1t/new-node-1.pub 10:32:51.624 [main] INFO c.q.t.k.generation.FileKeyGenerator - Saved private key to /Users/krish/fromscratch/new-node-1t/new-node-1.key ``` + 1. Create new configuration file with newly generated keys referenced. Name it `config.json` as done in this example - ``` + + ```bash vim config.json { "useWhiteList": false, @@ -994,7 +1066,8 @@ Just execute **step 4** instruction from removing a validator node. ``` 1. If you want to start another Tessera node, please repeat step 2 & step 3 - ``` + + ```bash $ cd .. $ mkdir new-node-2t $ cd new-node-2t @@ -1063,8 +1136,10 @@ Just execute **step 4** instruction from removing a validator node. } ``` + 1. Start your Tessera nodes and send then into background - ``` + + ```bash $ java -jar ../tessera.jar -configfile config.json >> tessera.log 2>&1 & [1] 38064 $ cd ../new-node-1t @@ -1081,7 +1156,8 @@ Just execute **step 4** instruction from removing a validator node. ``` 1. Start GoQuorum nodes attached to running Tessera nodes from above and send it to background - ``` + + ```bash ... update the start scripts to include PRIVATE_CONFIG $cd .. $vim startnode1.sh @@ -1110,7 +1186,8 @@ Just execute **step 4** instruction from removing a validator node. Tessera IPC bridge will be over a file name defined in your `config.json`, usually named `tm.ipc` as evidenced in prefix `PRIVATE_CONFIG=tm.ipc`. Your node is now able to send and receive private transactions, advertised public node key will be in the `new-node-1.pub` file. Tessera offers a lot of configuration flexibility, please refer [Configuration](../../Privacy/Tessera/Configuration/Configuration%20Overview) section under Tessera for complete and up to date configuration options. Your node is now operational and you may attach to it with `geth attach new-node-1/geth.ipc` to send private transactions. - ``` + + ```bash $ vim private-contract.js ... create simple private contract to send transaction from new-node-1 private for new-node-2's tessera public key created in step 4 a = eth.accounts[0] @@ -1124,16 +1201,16 @@ Just execute **step 4** instruction from removing a validator node. var simpleContract = web3.eth.contract(abi); var simple = simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["AeggpVlVsi+rxD6h9tcq/8qL/MsjyipUnkj1nvNPgTU="]}, function(e, contract) { - if (e) { - console.log("err creating contract", e); - } else { - if (!contract.address) { - console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); - } else { - console.log("Contract mined! Address: " + contract.address); - console.log(contract); - } - } + if (e) { + console.log("err creating contract", e); + } else { + if (!contract.address) { + console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); + } else { + console.log("Contract mined! Address: " + contract.address); + console.log(contract); + } + } }); $ $ @@ -1142,7 +1219,7 @@ Just execute **step 4** instruction from removing a validator node. !!! note Account opened in geth by default are locked, so please unlock account first before sending transaction - ``` + ```bash $ $ geth attach new-node-1/geth.ipc > eth.accounts @@ -1161,7 +1238,8 @@ Just execute **step 4** instruction from removing a validator node. !!! note if you do not have an valid public key in the array in private-contract.js, you will see the following error when the script in loaded. - ``` + + ```bash > loadScript("private-contract.js") err creating contract Error: Non-200 status code: &{Status:400 Bad Request StatusCode:400 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Date:[Mon, 17 Jun 2019 15:23:53 GMT] Content-Type:[text/plain] Content-Length:[73] Server:[Jetty(9.4.z-SNAPSHOT)]] Body:0xc01997a580 ContentLength:73 TransferEncoding:[] Close:false Uncompressed:false Trailer:map[] Request:0xc019788200 TLS:} ``` From 85a7bc0930e87273757dba61128afe90a6f15f6d Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Wed, 23 Sep 2020 10:28:28 +0200 Subject: [PATCH 6/9] update CI and submodule for new linter and link checker --- .circleci/config.yml | 18 +++++++++++------- common | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e2497ad..9c66e279 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,9 +11,6 @@ executors: node_executor: docker: - image: circleci/node:12.9.0-stretch - ruby_executor: - docker: - - image: circleci/ruby:2-stretch commands: prepare: @@ -101,23 +98,30 @@ jobs: destination: ./linkchecker.out markdownlint: - executor: ruby_executor + executor: node_executor steps: - prepare + - restore_cache: + keys: + - deps-{{ checksum "./common/build_tools/package-lock.json" }} - run: name: Install dependencies command: | - gem install mdl + npm ci - run: shell: /bin/bash #this is a non breaking command so it will always return success name: Run Markdownlint info checks command: | - mdl --ignore-front-matter --style ./common/build_tools/markdownlint/info_style.rb . | tee ./markdownlint_info.out + npm run test:markdown:info - run: name: Run Markdownlint command: | - mdl --ignore-front-matter --style ./common/build_tools/markdownlint/style.rb . | tee ./markdownlint.out + npm run test:markdown - notify + - save_cache: + paths: + - ./node_modules + key: deps-{{ checksum "./common/build_tools/package-lock.json" }} - store_artifacts: path: ./markdownlint.out destination: ./markdownlint.out diff --git a/common b/common index 1b85aba1..fc6f5caf 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1b85aba1f69903f08af315505c7d8d7704a7b64f +Subproject commit fc6f5caf1864b9e4bee32da9e56e17569732248d From 59165340ec379e6d2922d6f7a13d6d854dfbd4d1 Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Wed, 23 Sep 2020 11:31:58 +0200 Subject: [PATCH 7/9] fix md update submodule exclude generated files --- .markdownlintignore | 1 + common | 2 +- docs/Concepts/Privacy/Privacy.md | 1 - docs/Concepts/Privacy/PrivateTransactionLifecycle.md | 2 -- .../OpertionalConsiderations.md | 1 - docs/HowTo/GetStarted/Wizard/GettingStarted.md | 2 +- docs/HowTo/Use/EnhancedPermissions.md | 5 ----- docs/HowTo/Use/add_node_examples.md | 10 +++++----- docs/Tutorials/Creating-A-Network-From-Scratch.md | 10 +++++----- 9 files changed, 13 insertions(+), 21 deletions(-) create mode 100644 .markdownlintignore diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 00000000..88030da8 --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1 @@ +docs/Reference/Plugins/**/*terface.md diff --git a/common b/common index fc6f5caf..fb8fd420 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit fc6f5caf1864b9e4bee32da9e56e17569732248d +Subproject commit fb8fd420442a87662444737496f760d0dde79080 diff --git a/docs/Concepts/Privacy/Privacy.md b/docs/Concepts/Privacy/Privacy.md index 9ef97d6b..6fc5c9bc 100644 --- a/docs/Concepts/Privacy/Privacy.md +++ b/docs/Concepts/Privacy/Privacy.md @@ -78,4 +78,3 @@ To overcome this issue the RPC method `eth_storageRoot(address[, blockNumber]) - It returns the storage root for the given address at an (optional) block number. If the optional block number is not given the latest block number is used. The storage root hash can be on or off chain compared by the parties involved. - diff --git a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md index bcab5d9c..112fd82b 100644 --- a/docs/Concepts/Privacy/PrivateTransactionLifecycle.md +++ b/docs/Concepts/Privacy/PrivateTransactionLifecycle.md @@ -42,5 +42,3 @@ In this example, Party A and Party B are party to Transaction AB, whilst Party C 1. The Transaction Manager's return their results to their GoQuorum nodes: 1. Party A & B's Transaction Managers return the decrypted private transaction data to their GoQuorum nodes which can now execute the transaction as normal, thus updating their respective Private StateDB. GoQuorum discards the decrypted private transaction data once used 1. Party C's Transaction Manager returns a 404 NOT FOUND to its GoQuorum node as it is not a recipient of the transaction. Recognising that it is not party to this private transaction, the GoQuorum node will skip the execution of the transaction, so that no changes to its Private StateDB are made - - diff --git a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md index 13f873e0..ae49c8b2 100644 --- a/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md +++ b/docs/Concepts/Security/Framework/GoQuorumNetworkSecurity/OpertionalConsiderations.md @@ -32,4 +32,3 @@ The following parameters are of interest to be collected and analyzed: - [x] Logs must be backed-up and integrity verified. - [x] An alerting system should be put in place in order to monitor consensus protocol anomalies - diff --git a/docs/HowTo/GetStarted/Wizard/GettingStarted.md b/docs/HowTo/GetStarted/Wizard/GettingStarted.md index a1b2147b..9e2a1907 100644 --- a/docs/HowTo/GetStarted/Wizard/GettingStarted.md +++ b/docs/HowTo/GetStarted/Wizard/GettingStarted.md @@ -7,7 +7,7 @@ description: GoQuorum network setup wizard command line tool [GoQuorum Wizard](https://github.com/ConsenSys/quorum-wizard) is a command line tool that allows users to set up a development GoQuorum network on their local machine in less than 2 minutes. -![](../../../images/quorum-wizard.gif) +![Quorum wizard terminal demo](../../../images/quorum-wizard.gif) ## Installation diff --git a/docs/HowTo/Use/EnhancedPermissions.md b/docs/HowTo/Use/EnhancedPermissions.md index a292680c..13c78ebd 100644 --- a/docs/HowTo/Use/EnhancedPermissions.md +++ b/docs/HowTo/Use/EnhancedPermissions.md @@ -606,8 +606,3 @@ To approve the assignment of network admin role invoke [approveAdminRole](../../ ``` The above account can now perform all activities allowable by a network admin account and can participate in the approval process for any actions at network level. - - - - - diff --git a/docs/HowTo/Use/add_node_examples.md b/docs/HowTo/Use/add_node_examples.md index 1648736f..2873f826 100644 --- a/docs/HowTo/Use/add_node_examples.md +++ b/docs/HowTo/Use/add_node_examples.md @@ -46,9 +46,9 @@ own connections. 1. Send in a public transaction and check it is minted. - !!! note - * The block creation period is set to 2 seconds, so you may have to wait upto that amount of time for the transaction to be minted. - * The transaction hashes will likely be different, but the contract addresses will be the same for your network. +!!! note + - The block creation period is set to 2 seconds, so you may have to wait upto that amount of time for the transaction to be minted. + - The transaction hashes will likely be different, but the contract addresses will be the same for your network. **Send in the transaction** @@ -209,7 +209,7 @@ solely based on who is listed in the nodes `static-nodes.json` file. 1. Send in a public transaction and check it is minted. !!! note - * The transaction hashes will likely be different, but the contract addresses will be the same for your network. + The transaction hashes will likely be different, but the contract addresses will be the same for your network. **Send in the transaction** @@ -359,7 +359,7 @@ the node must appear is others nodes' `permissioned-nodes.json` file. 1. Send in a public transaction and check it is minted. !!! note - * The transaction hashes will likely be different, but the contract addresses will be the same for your network. + The transaction hashes will likely be different, but the contract addresses will be the same for your network. **Send in the transaction** diff --git a/docs/Tutorials/Creating-A-Network-From-Scratch.md b/docs/Tutorials/Creating-A-Network-From-Scratch.md index 67d2bc1f..082b0bad 100644 --- a/docs/Tutorials/Creating-A-Network-From-Scratch.md +++ b/docs/Tutorials/Creating-A-Network-From-Scratch.md @@ -801,10 +801,10 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. Copy `static-nodes.json` and genesis.json from the existing chain. `static-nodes.json` should be placed into new nodes data dir ```bash - $ cd node5 - $ mkdir -p data/geth - $ cp ../node0/static-nodes.json data - $ cp ../node0/genesis.json . + cd node5 + mkdir -p data/geth + cp ../node0/static-nodes.json data + cp ../node0/genesis.json . ``` 1. Edit `static-nodes.json` and add the new validators node info to the end of the file. New validators node info can be got from the output of `istanbul setup --num 1 --verbose --quorum --save` command that was run in step 2. Update the IP address and port of the node info to match the IP address of the validator and port you want to use. @@ -826,7 +826,7 @@ Let's go through step by step instructions to setup a GoQuorum node with Raft co 1. Copy the nodekey that was generated by `istanbul setup` command to the `geth` directory inside the working directory ```bash - $ cp 0/nodekey data/geth + cp 0/nodekey data/geth ``` 1. Generate one or more accounts for this node and take down the account address. From 9fa9f29c9a9bc80c8364a140629b2fed2597d9be Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Wed, 23 Sep 2020 11:43:04 +0200 Subject: [PATCH 8/9] fix html exceptions --- docs/HowTo/DevelopPlugins.md | 2 -- docs/HowTo/ManageKeys/AccountPlugins.md | 4 ++-- docs/Reference/APIs/PrivacyAPI.md | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/HowTo/DevelopPlugins.md b/docs/HowTo/DevelopPlugins.md index 0dd32d89..9770621c 100644 --- a/docs/HowTo/DevelopPlugins.md +++ b/docs/HowTo/DevelopPlugins.md @@ -108,8 +108,6 @@ A plugin would need to include this certificate to its trusted certificate pool, generate a self-signed certificate and append the base64-encoded value of the certificate (in DER format) in the [handshake](https://github.com/hashicorp/go-plugin/blob/master/docs/internals.md#handshake) message. - - {!./PluggableArchitecture/Plugins/init_interface.md!} ## Examples diff --git a/docs/HowTo/ManageKeys/AccountPlugins.md b/docs/HowTo/ManageKeys/AccountPlugins.md index 0e4f2d0f..8a8ec0f2 100644 --- a/docs/HowTo/ManageKeys/AccountPlugins.md +++ b/docs/HowTo/ManageKeys/AccountPlugins.md @@ -147,7 +147,7 @@ Create a plugin-managed account from an existing key: | Parameter | Description | | --- | --- | -| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required. +| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required. === "json file" @@ -171,7 +171,7 @@ Create a plugin-managed account from an existing private key: | Parameter | Description | | --- | --- | -| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required +| `plugins.account.config` | Plugin-specific configuration for creating an account. Can be `file://` or inline-json. See the plugin's documentation for more info on the json config required | `rawkey` | Path to file containing hex-encoded account private key (without 0x prefix) (for example `/path/to/raw.key`) === "json file" diff --git a/docs/Reference/APIs/PrivacyAPI.md b/docs/Reference/APIs/PrivacyAPI.md index 7b44be48..5825c48d 100644 --- a/docs/Reference/APIs/PrivacyAPI.md +++ b/docs/Reference/APIs/PrivacyAPI.md @@ -20,7 +20,7 @@ Sends a transaction to the network. - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - ~~`gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.~~ - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - `input`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. `input` cannot coexist with `data` if they are set to different value. - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. @@ -300,7 +300,7 @@ Returns the unencrypted payload from Tessera/constellation - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - ~~`gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.~~ - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - `input`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. `input` cannot coexist with `data` if they are set to different value. - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. From 71bfc793252eb0ca816587c351c10376b488272c Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Wed, 23 Sep 2020 11:46:20 +0200 Subject: [PATCH 9/9] update submodule --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index fb8fd420..9244c70f 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit fb8fd420442a87662444737496f760d0dde79080 +Subproject commit 9244c70fcf97f2a10088f85acb9ecb604ff52806