permission: update start and initialize service methods

code clean up - remove unused code related to org key
This commit is contained in:
amalraj.manigmail.com 2019-05-08 22:55:03 +08:00
parent 468478be78
commit 6e7f3959e3
21 changed files with 132 additions and 2421 deletions

View File

@ -25,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/permission"
"io"
"os"
"path/filepath"
"reflect"
"time"
"unicode"
@ -171,14 +170,8 @@ func makeFullNode(ctx *cli.Context) *node.Node {
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
}
if ctx.GlobalBool(utils.EnableNodePermissionFlag.Name) {
fileName := "permission-config.json"
fullPath := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), fileName)
if _, err := os.Stat(fullPath); err != nil {
log.Warn("permission-config.json file is missing. permission service will be disabled", err)
} else {
RegisterPermissionService(ctx, stack)
}
if utils.IsPermissionEnabled(ctx) {
RegisterPermissionService(ctx, stack)
}
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
@ -212,9 +205,9 @@ func RegisterPermissionService(ctx *cli.Context, stack *node.Node) {
if permissionConfig, err = permission.ParsePermissionConifg(dataDir); err != nil {
utils.Fatalf("loading of permission-config.json failed", "error", err)
}
log.Info("AJ-permission ctrl new")
// start the permissions management service
pc, err := permission.NewQuorumPermissionCtrl(stack, ctx.GlobalBool(utils.EnableNodePermissionFlag.Name), ctx.GlobalBool(utils.RaftModeFlag.Name), &permissionConfig)
pc, err := permission.NewQuorumPermissionCtrl(stack, ctx.GlobalBool(utils.RaftModeFlag.Name), &permissionConfig)
if err != nil {
utils.Fatalf("Failed to load the permission contracts as given in permissions-config.json %v", err)
}

View File

@ -19,6 +19,7 @@ package main
import (
"fmt"
"github.com/ethereum/go-ethereum/permission"
"math"
"os"
godebug "runtime/debug"
@ -343,6 +344,18 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}()
//initialize permission as we can create eth client only after the node and RPC are started
if utils.IsPermissionEnabled(ctx) {
var permissionService *permission.PermissionCtrl
stack.Service(&permissionService)
if permissionService == nil {
utils.Fatalf("permission service missing")
}
//initialize the service to create eth client and get ethereum service
permissionService.InitializeService()
permissionService.Start(stack.Server())
}
// Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
// Mining only makes sense if a full Ethereum node is running

View File

@ -20,9 +20,11 @@ package utils
import (
"compress/gzip"
"fmt"
"gopkg.in/urfave/cli.v1"
"io"
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
@ -63,6 +65,19 @@ func Fatalf(format string, args ...interface{}) {
os.Exit(1)
}
func IsPermissionEnabled(ctx *cli.Context) bool {
if ctx.GlobalBool(EnableNodePermissionFlag.Name) {
fileName := "permission-config.json"
fullPath := filepath.Join(ctx.GlobalString(DataDirFlag.Name), fileName)
if _, err := os.Stat(fullPath); err != nil {
log.Warn("permission-config.json file is missing. permission service will be disabled", err)
return false
}
return true
}
return false
}
func StartNode(stack *node.Node) {
log.Info("AJ-start node2")

File diff suppressed because one or more lines are too long

View File

@ -3,19 +3,22 @@ package controls
import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
)
// Create an RPC client for the contract interface
func CreateEthClient(stack *node.Node) (*ethclient.Client, *eth.Ethereum, error) {
var e *eth.Ethereum
log.Info("AJ-CreateEthClient permission ethereum service..")
if err := stack.Service(&e); err != nil {
return nil, nil, err
}
log.Info("AJ-CreateEthClient permission stack attach..")
rpcClient, err := stack.Attach()
if err != nil {
return nil, nil, err
}
log.Info("AJ-permission CreateEthClient done")
return ethclient.NewClient(rpcClient), e, nil
}

View File

@ -1,407 +0,0 @@
pragma solidity ^0.5.3;
contract Clusterkeys {
// Struct for managing the org details
enum Operation {None, Add, Delete}
struct OrgKeyDetails {
string tmKey;
bool active;
}
struct OrgDetails {
string orgId;
string morgId;
string pendingKey;
Operation pendingOp;
uint keyCount;
OrgKeyDetails []orgKeys;
mapping (bytes32 => uint) orgKeyIndex;
}
OrgDetails [] private orgList;
mapping(bytes32 => uint) private OrgIndex;
// Struct for managing the voter accounst for the org
// voter struct which will be part of Master org
struct VoterDetails {
address vAccount;
bool active;
}
struct MasterOrgDetails {
string orgId;
uint voterCount;
uint validVoterCount;
VoterDetails []voterList;
mapping (address => uint) voterIndex;
}
MasterOrgDetails [] private masterOrgList;
mapping(bytes32 => uint) private MasterOrgIndex;
// Struct to monitor the key usage
struct KeyUsageDetails {
string tmKey;
string morgId;
uint count;
bool pending;
}
KeyUsageDetails [] private keyUsage;
mapping (bytes32 => uint) KeyIndex;
// mapping to monitor the voting status for each acount and
// overall voting count
mapping (uint => mapping (address => bool)) private voteStatus;
mapping (uint => uint) private voteCount;
uint private orgNum = 0;
uint private morgNum = 0;
uint private keyNum = 0;
// events related to Master Org add
event MasterOrgAdded(string _orgId);
event SubOrgAdded(string _orgId);
// events related to Org level key management
event OrgKeyAdded(string _orgId, string _tmKey);
event OrgKeyDeleted(string _orgId, string _tmKey);
// events related to org level approval process
event ItemForApproval(string _orgId, Operation _pendingOp, string _tmKey);
// events related to managing voting accounts for the org
event VoterAdded(string _orgId, address _address);
event VoterDeleted(string _orgId, address _address);
/* public and external functions */
// view functions
// dummy function called from geth interface to check of the contract is deployed
function checkOrgContractExists() external pure returns (bool){
return true;
}
// returns voter count for a given org
function getOrgVoteCount(string calldata _orgId) external view returns (uint) {
return voteCount[getOrgIndex(_orgId)];
}
// returns pending operation details
function getPendingOp(string calldata _orgId) external view returns (string memory, Operation) {
uint i = getOrgIndex(_orgId);
return (orgList[i].pendingKey, orgList[i].pendingOp);
}
// All internal functions
// returns the voter index
function getVoterIndex(string memory _morgId, address _vAccount) internal view returns (uint)
{
uint morgIndex = getMasterOrgIndex(_morgId);
return masterOrgList[morgIndex].voterIndex[_vAccount] - 1;
}
// returns the org index for the org list
function getOrgIndex(string memory _orgId) internal view returns (uint)
{
return OrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
}
// returns the master org index for the org from voter list
function getMasterOrgIndex(string memory _orgId) internal view returns (uint)
{
return MasterOrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
}
// returns the key index from org key list
function getOrgKeyIndex(uint _orgIndex, string memory _tmKey) internal view returns (uint)
{
return orgList[_orgIndex].orgKeyIndex[keccak256(abi.encodePacked(_tmKey))] - 1;
}
// returns the key index for the key usage list
function getKeyIndex(string memory _tmKey) internal view returns (uint)
{
return KeyIndex[keccak256(abi.encodePacked(_tmKey))] - 1;
}
// initialize the voter account votes to false. This will be called
// when a new item is initiated for approval
function voterInit(string memory _orgId) internal {
uint orgIndex = getOrgIndex(_orgId);
uint morgIndex = getMasterOrgIndex(orgList[orgIndex].morgId);
for (uint i = 0; i < masterOrgList[morgIndex].voterList.length; i++){
if (masterOrgList[morgIndex].voterList[i].active){
voteStatus[orgIndex][masterOrgList[morgIndex].voterList[i].vAccount] = false;
}
}
voteCount[orgIndex] = 0;
}
// processes the vote from the voter account.
function processVote (string memory _orgId) internal {
uint orgIndex = getOrgIndex(_orgId);
if (voteStatus[orgIndex][msg.sender] == false ){
voteStatus[orgIndex][msg.sender] = true;
voteCount[orgIndex]++;
}
}
// checks if enough votes have been cast for the pending operation.
// If yes returns true
function checkEnoughVotes (string memory _orgId, string memory _morgId) internal view returns (bool) {
uint orgIndex = getOrgIndex(_orgId);
uint morgIndex = getMasterOrgIndex(_morgId);
return (voteCount[orgIndex] > masterOrgList[morgIndex].validVoterCount / 2 );
}
// function to update key usage details at master org level for a key
function updateKeyUsage(string memory _tmKey, string memory _morgId, Operation op) internal {
uint keyIndex = getKeyIndex(_tmKey);
keyUsage[keyIndex].pending = false;
if (op == Operation.Add){
keyUsage[keyIndex].count++;
keyUsage[keyIndex].morgId = _morgId;
}
else {
keyUsage[keyIndex].count--;
}
}
// function to process the approavl for add or delete
function processApproval(uint _orgIndex) internal {
if(checkEnoughVotes(orgList[_orgIndex].orgId, orgList[_orgIndex].morgId)){
string storage locKey = orgList[_orgIndex].pendingKey;
if (orgList[_orgIndex].pendingOp == Operation.Add){
if (checkIfKeyExists(orgList[_orgIndex].orgId, locKey)){
uint keyIndex = getOrgKeyIndex(_orgIndex, locKey);
orgList[_orgIndex].orgKeys[keyIndex].active = true;
}
else {
orgList[_orgIndex].keyCount++;
orgList[_orgIndex].orgKeyIndex[keccak256(abi.encodePacked(locKey))] = orgList[_orgIndex].keyCount;
orgList[_orgIndex].orgKeys.push(OrgKeyDetails(locKey, true));
updateKeyUsage(orgList[_orgIndex].pendingKey, orgList[_orgIndex].morgId, orgList[_orgIndex].pendingOp);
}
emit OrgKeyAdded(orgList[_orgIndex].orgId, locKey);
}
else {
if (checkIfKeyExists (orgList[_orgIndex].orgId, locKey)){
uint keyIndex = getOrgKeyIndex(_orgIndex, locKey);
orgList[_orgIndex].orgKeys[keyIndex].active = false;
emit OrgKeyDeleted(orgList[_orgIndex].orgId, locKey);
}
}
orgList[_orgIndex].pendingOp = Operation.None;
orgList[_orgIndex].pendingKey = "";
}
}
// All public functions
// checks if the org has any voter accounts set up or not
function checkIfVoterExists(string memory _morgId, address _address) public view returns (bool){
uint morgIndex = getMasterOrgIndex(_morgId);
if (masterOrgList[morgIndex].voterIndex[_address] == 0){
return false;
}
uint voterIndex = getVoterIndex(_morgId, _address);
return masterOrgList[morgIndex].voterList[voterIndex].active;
}
// checks if there the key is already in the list of private keys for the org
function checkIfKeyExists(string memory _orgId, string memory _tmKey) public view returns (bool){
uint orgIndex = getOrgIndex(_orgId);
if (orgList[orgIndex].orgKeyIndex[keccak256(abi.encodePacked(_tmKey))] == 0){
return false;
}
uint keyIndex = getOrgKeyIndex(orgIndex, _tmKey);
return orgList[orgIndex].orgKeys[keyIndex].active;
}
// All extenal view functions
// Get number of voters
function getNumberOfVoters(string calldata _morgId) external view returns (uint)
{
return masterOrgList[getMasterOrgIndex(_morgId)].voterCount;
}
// Get voter details
function getVoter(string calldata _morgId, uint i) external view returns (address _addr, bool _active)
{
uint morgIndex = getMasterOrgIndex(_morgId);
return (masterOrgList[morgIndex].voterList[i].vAccount, masterOrgList[morgIndex].voterList[i].active);
}
// returns the number of orgs
function getNumberOfOrgs() external view returns (uint){
return orgNum;
}
// returns the total number of keys for a given org
function getOrgKeyCount(string calldata _orgId) external view returns (uint){
return orgList[getOrgIndex(_orgId)].orgKeys.length;
}
// returns org key details based on org id and key index
function getOrgKey(string calldata _orgId, uint _keyIndex) external view returns (string memory, bool){
uint orgIndex = getOrgIndex(_orgId);
return (orgList[orgIndex].orgKeys[_keyIndex].tmKey,orgList[orgIndex].orgKeys[_keyIndex].active);
}
// returns org and master org details based on org index
function getOrgInfo(uint _orgIndex) external view returns (string memory, string memory){
return (orgList[_orgIndex].orgId, orgList[_orgIndex].morgId);
}
// checks if the sender is one of the registered voter account for the org
function isVoter (string calldata _orgId, address account) external view returns (bool){
uint orgIndex = getOrgIndex(_orgId);
uint morgIndex = getMasterOrgIndex(orgList[orgIndex].morgId);
return (!(masterOrgList[morgIndex].voterIndex[account] == 0));
}
// checks if the voting accounts exists for the org
function checkVotingAccountExists(string calldata _orgId) external view returns (bool)
{
uint orgIndex = getOrgIndex(_orgId);
uint morgIndex = getMasterOrgIndex(orgList[orgIndex].morgId);
return (masterOrgList[morgIndex].validVoterCount > 0);
}
// function to check if morg exists
function checkMasterOrgExists (string calldata _morgId) external view returns (bool) {
return (!(MasterOrgIndex[keccak256(abi.encodePacked(_morgId))] == 0));
}
// function to check if morg exists
function checkOrgExists (string calldata _orgId) external view returns (bool) {
return(!(OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0));
}
// function for checking if org exists and if there are any pending ops
function checkOrgPendingOp (string calldata _orgId) external view returns (bool) {
uint orgIndex = getOrgIndex(_orgId);
return (orgList[orgIndex].pendingOp != Operation.None);
}
// function for checking if org exists and if there are any pending ops
function getOrgPendingOp (string calldata _orgId) external view returns (string memory, Operation) {
uint orgIndex = getOrgIndex(_orgId);
return (orgList[orgIndex].pendingKey, orgList[orgIndex].pendingOp);
}
// this function checks of the key proposed is in use in another master org
function checkKeyClash (string calldata _orgId, string calldata _key) external view returns (bool) {
uint orgIndex = getOrgIndex(_orgId);
uint keyIndex = getKeyIndex(_key);
if ((KeyIndex[keccak256(abi.encodePacked(_key))] != 0) &&
(keccak256(abi.encodePacked (keyUsage[keyIndex].morgId)) != keccak256(abi.encodePacked(orgList[orgIndex].morgId)))){
// check the count if count is greather than zero, key already in use
if ((keyUsage[keyIndex].count > 0) || (keyUsage[keyIndex].pending)){
return true;
}
}
return false;
}
// All extenal update functions
// function for adding a new master org
function addMasterOrg(string calldata _morgId) external
{
morgNum++;
MasterOrgIndex[keccak256(abi.encodePacked(_morgId))] = morgNum;
uint id = masterOrgList.length++;
masterOrgList[id].orgId = _morgId;
masterOrgList[id].voterCount = 0;
masterOrgList[id].validVoterCount = 0;
emit MasterOrgAdded(_morgId);
}
// function for adding a new master org
function addSubOrg(string calldata _orgId, string calldata _morgId) external
{
orgNum++;
OrgIndex[keccak256(abi.encodePacked(_orgId))] = orgNum;
uint id = orgList.length++;
orgList[id].orgId = _orgId;
orgList[id].morgId = _morgId;
orgList[id].keyCount = 0;
orgList[id].pendingKey = "";
orgList[id].pendingOp = Operation.None;
emit SubOrgAdded(_morgId);
}
// function for adding a voter account to a master org
function addVoter(string calldata _morgId, address _address) external
{
uint morgIndex = getMasterOrgIndex(_morgId);
masterOrgList[morgIndex].voterCount++;
masterOrgList[morgIndex].validVoterCount++;
masterOrgList[morgIndex].voterIndex[_address] = masterOrgList[morgIndex].voterCount;
masterOrgList[morgIndex].voterList.push(VoterDetails(_address, true));
emit VoterAdded(_morgId, _address);
}
// function for deleting a voter account to a master org
function deleteVoter(string calldata _morgId, address _address) external
{
uint morgIndex = getMasterOrgIndex(_morgId);
if(checkIfVoterExists(_morgId, _address)){
uint vIndex = getVoterIndex(_morgId, _address);
masterOrgList[morgIndex].validVoterCount --;
masterOrgList[morgIndex].voterList[vIndex].active = false;
emit VoterDeleted(_morgId, _address);
}
}
// function for adding a private key for the org. Thsi will be added once
// approval process is complete
function addOrgKey(string calldata _orgId, string calldata _tmKey) external
{
uint orgIndex = getOrgIndex(_orgId);
if (!checkIfKeyExists (_orgId, _tmKey)){
orgList[orgIndex].pendingKey = _tmKey;
orgList[orgIndex].pendingOp = Operation.Add;
voterInit(_orgId);
// add key to key usage list for tracking
uint keyIndex = getKeyIndex(_tmKey);
if (KeyIndex[keccak256(abi.encodePacked(_tmKey))] == 0){
keyNum ++;
KeyIndex[keccak256(abi.encodePacked(_tmKey))] = keyNum;
keyUsage.push(KeyUsageDetails(_tmKey, orgList[orgIndex].morgId, 0, true));
}
else {
keyUsage[keyIndex].pending = true;
}
emit ItemForApproval(_orgId,Operation.Add, _tmKey);
}
}
// function for deleting a private key for the org. Thsi will be deleted once
// approval process is complete
function deleteOrgKey(string calldata _orgId, string calldata _tmKey) external
{
uint orgIndex = getOrgIndex(_orgId);
if (checkIfKeyExists(_orgId, _tmKey)) {
orgList[orgIndex].pendingKey = _tmKey;
orgList[orgIndex].pendingOp = Operation.Delete;
voterInit(_orgId);
uint keyIndex = getKeyIndex(_tmKey);
keyUsage[keyIndex].pending = true;
emit ItemForApproval(_orgId, Operation.Delete, _tmKey);
}
}
// function for approving key add or delete operations
function approvePendingOp(string calldata _orgId) external
{
uint orgIndex = getOrgIndex(_orgId);
processVote(_orgId);
processApproval(orgIndex);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,188 +0,0 @@
package cluster
import (
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/controls"
pbind "github.com/ethereum/go-ethereum/controls/bind/cluster"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
)
type OrgKeyCtrl struct {
ethClient *ethclient.Client
key *ecdsa.PrivateKey
km *pbind.Cluster
}
// Creates the controls structure for org key management
func NewOrgKeyCtrl(node *node.Node) (*OrgKeyCtrl, error) {
stateReader, _, err := controls.CreateEthClient(node)
if err != nil {
log.Error("Unable to create ethereum client for cluster check", "err", err)
return nil, err
}
// check if permissioning contract is there at address. If not return from here
km, err := pbind.NewCluster(params.QuorumPrivateKeyManagementContract, stateReader)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
return &OrgKeyCtrl{stateReader, node.GetNodeKey(), km}, nil
}
// starts the org key management services
func (k *OrgKeyCtrl) Start() error {
_, err := pbind.NewClusterFilterer(params.QuorumPrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error("Cluster not enabled for the network", "err", err)
return nil
}
// check if permissioning contract is there at address. If not return from here
err = k.checkIfContractExists()
if err != nil {
return err
}
// start the service
k.manageClusterKeys()
return nil
}
// checks if the contract is deployed for org key management
func (k *OrgKeyCtrl) checkIfContractExists() error {
auth := bind.NewKeyedTransactor(k.key)
clusterSession := &pbind.ClusterSession{
Contract: k.km,
CallOpts: bind.CallOpts{
Pending: true,
},
TransactOpts: bind.TransactOpts{
From: auth.From,
Signer: auth.Signer,
GasLimit: 4700000,
GasPrice: big.NewInt(0),
},
}
// dummy call to contrat to check if the contract is deployed
_, err := clusterSession.CheckOrgContractExists()
if err != nil {
return err
}
return nil
}
// in case of geth restart firts checks for historical key update events and
// populates the cache, then starts the key change monitoring service
func (k *OrgKeyCtrl) manageClusterKeys() {
//call populate nodes to populate the nodes into contract
if err := k.populatePrivateKeys(); err != nil {
return
}
//monitor for nodes deletiin via smart contract
k.monitorKeyChanges()
}
// populates cache based on the historical key change events.
func (k *OrgKeyCtrl) populatePrivateKeys() error {
cluster, err := pbind.NewClusterFilterer(params.QuorumPrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error("Failed to monitor node delete", "err", err)
return err
}
opts := &bind.FilterOpts{}
pastAddEvents, err := cluster.FilterOrgKeyAdded(opts)
if err != nil && err.Error() == "no contract code at given address" {
return err
}
recExists := true
for recExists {
recExists = pastAddEvents.Next()
if recExists {
types.AddOrgKey(pastAddEvents.Event.OrgId, pastAddEvents.Event.TmKey)
}
}
opts = &bind.FilterOpts{}
pastDeleteEvents, _ := cluster.FilterOrgKeyDeleted(opts)
recExists = true
for recExists {
recExists = pastDeleteEvents.Next()
if recExists {
types.DeleteOrgKey(pastDeleteEvents.Event.OrgId, pastDeleteEvents.Event.TmKey)
}
}
return nil
}
// service to monitor key change events
func (k *OrgKeyCtrl) monitorKeyChanges() {
go k.monitorKeyAdd()
go k.monitorKeyDelete()
}
// monitors for new key added event and updates caches based on the same
func (k *OrgKeyCtrl) monitorKeyAdd() {
cluster, err := pbind.NewClusterFilterer(params.QuorumPrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error("Failed to monitor key action", "err", err)
}
ch := make(chan *pbind.ClusterOrgKeyAdded)
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
var newEvent *pbind.ClusterOrgKeyAdded
_, err = cluster.WatchOrgKeyAdded(opts, ch)
if err != nil {
log.Info("Failed WatchOrgKeyDeleted: %v", err)
}
for {
select {
case newEvent = <-ch:
types.AddOrgKey(newEvent.OrgId, newEvent.TmKey)
}
}
}
// monitors for new key delete event and updates caches based on the same
func (k *OrgKeyCtrl) monitorKeyDelete() {
cluster, err := pbind.NewClusterFilterer(params.QuorumPrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error("Failed to monitor key action", "err", err)
}
ch := make(chan *pbind.ClusterOrgKeyDeleted)
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
var newEvent *pbind.ClusterOrgKeyDeleted
_, err = cluster.WatchOrgKeyDeleted(opts, ch)
if err != nil {
log.Info("Failed WatchOrgKeyDeleted: %v", err)
}
for {
select {
case newEvent = <-ch:
types.DeleteOrgKey(newEvent.OrgId, newEvent.TmKey)
}
}
}

View File

@ -87,11 +87,6 @@ type OrgDetailInfo struct {
SubOrgList []string `json:"subOrgList"`
}
type OrgStruct struct {
OrgId string
Keys []string
}
// permission config for bootstrapping
type PermissionConfig struct {
UpgrdAddress common.Address
@ -407,49 +402,3 @@ func ValidateNodeForTxn(enodeId string, from common.Address) bool {
}
return false
}
// Adds org key details to cache
func AddOrgKey(orgId string, key string) {
if OrgKeyMap.Len() != 0 {
if val, ok := OrgKeyMap.Get(orgId); ok {
orgKeyLock.Lock()
defer orgKeyLock.Unlock()
// Org record exists. Append the key only
vo := val.(*OrgStruct)
vo.Keys = append(vo.Keys, key)
return
}
}
OrgKeyMap.Add(orgId, &OrgStruct{OrgId: orgId, Keys: []string{key}})
}
// deletes org key details from cache
func DeleteOrgKey(orgId string, key string) {
if val, ok := OrgKeyMap.Get(orgId); ok {
orgKeyLock.Lock()
defer orgKeyLock.Unlock()
vo := val.(*OrgStruct)
for i, keyVal := range vo.Keys {
if keyVal == key {
vo.Keys = append(vo.Keys[:i], vo.Keys[i+1:]...)
break
}
}
}
}
// Givens a orgid returns the linked keys for the org
func ResolvePrivateForKeys(orgId string) []string {
var keys []string
if val, ok := OrgKeyMap.Get(orgId); ok {
vo := val.(*OrgStruct)
if len(vo.Keys) > 0 {
keys = vo.Keys
} else {
keys = append(keys, orgId)
}
return keys
}
keys = append(keys, orgId)
return keys
}

View File

@ -1805,10 +1805,8 @@ func (s *PublicBlockChainAPI) GetQuorumPayload(digestHex string) (string, error)
func resolvePrivateFor(privateFor []string) []string {
var newPrivateFor []string
for _, value := range privateFor {
keys := types.ResolvePrivateForKeys(value)
newPrivateFor = append(newPrivateFor, keys...)
newPrivateFor = append(newPrivateFor, value)
}
return newPrivateFor
}

View File

@ -6,12 +6,11 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
pbind "github.com/ethereum/go-ethereum/controls/bind/permission"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
pbind "github.com/ethereum/go-ethereum/permission/bind"
"math/big"
"regexp"
)
@ -61,16 +60,9 @@ const (
Inactive
)
type PermissionContracts struct {
PermInterf *pbind.PermInterface
}
// QuorumControlsAPI provides an API to access Quorum's node permission and org key management related services
type QuorumControlsAPI struct {
txPool *core.TxPool
acctMgr *accounts.Manager
permConfig *types.PermissionConfig
permInterf *pbind.PermInterface
permCtrl *PermissionCtrl
}
// txArgs holds arguments required for execute functions
@ -138,26 +130,10 @@ var (
)
// NewQuorumControlsAPI creates a new QuorumControlsAPI to access quorum services
func NewQuorumControlsAPI(tp *core.TxPool, am *accounts.Manager, pcfg *types.PermissionConfig, pc *pbind.PermInterface) *QuorumControlsAPI {
return &QuorumControlsAPI{tp, am, pcfg, pc}
func NewQuorumControlsAPI(p *PermissionCtrl) *QuorumControlsAPI {
return &QuorumControlsAPI{p}
}
/*//Init initializes QuorumControlsAPI with eth client, permission contract and org key management control
func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey, pc *pbind.PermInterface) error {
// check if the interface contract is deployed or not. if not
// permissions apis will not work. return error
p.ethClnt = ethClnt
if _, err := pbind.NewPermInterface(p.permConfig.InterfAddress, p.ethClnt); err != nil {
return err
}
p.permEnabled = true
p.key = key
p.permInterf = pc
return nil
}*/
func (s *QuorumControlsAPI) OrgList() []types.OrgInfo {
return types.OrgInfoMap.GetOrgList()
}
@ -254,7 +230,7 @@ func (s *QuorumControlsAPI) UpdateAccountStatus(orgId string, acct common.Addres
// check if the account is network admin
func (s *QuorumControlsAPI) isNetworkAdmin(account common.Address) bool {
ac := types.AcctInfoMap.GetAccount(account)
return ac != nil && ac.RoleId == s.permConfig.NwAdminRole
return ac != nil && ac.RoleId == s.permCtrl.permConfig.NwAdminRole
}
func (s *QuorumControlsAPI) isOrgAdmin(account common.Address, orgId string) (ExecStatus, error) {
@ -371,7 +347,7 @@ func (s *QuorumControlsAPI) valAccountStatusChange(orgId string, account common.
return ErrAccountNotThere, errors.New("account not there")
}
if ac.IsOrgAdmin && (ac.RoleId == s.permConfig.NwAdminRole || ac.RoleId == s.permConfig.OrgAdminRole) && (op == 1 || op == 3) {
if ac.IsOrgAdmin && (ac.RoleId == s.permCtrl.permConfig.NwAdminRole || ac.RoleId == s.permCtrl.permConfig.OrgAdminRole) && (op == 1 || op == 3) {
return ErrOpNotAllowed, errors.New("operation not allowed on org admin account")
}
@ -401,7 +377,7 @@ func (s *QuorumControlsAPI) checkOrgAdminExists(orgId, roleId string, account co
if ac.OrgId != orgId {
return ErrAccountInUse, errors.New("account part of another org")
}
if roleId != "" && roleId == s.permConfig.OrgAdminRole && ac.IsOrgAdmin {
if roleId != "" && roleId == s.permCtrl.permConfig.OrgAdminRole && ac.IsOrgAdmin {
return ErrAccountOrgAdmin, errors.New("account already org admin for the org")
}
}
@ -411,11 +387,11 @@ func (s *QuorumControlsAPI) checkOrgAdminExists(orgId, roleId string, account co
func (s *QuorumControlsAPI) valSubOrgBreadthDepth(porgId string) (ExecStatus, error) {
org := types.OrgInfoMap.GetOrg(porgId)
if s.permConfig.SubOrgDepth.Cmp(org.Level) == 0 {
if s.permCtrl.permConfig.SubOrgDepth.Cmp(org.Level) == 0 {
return ErrMaxDepth, errors.New("max depth for suborgs reached")
}
if s.permConfig.SubOrgBreadth.Cmp(big.NewInt(int64(len(org.SubOrgList)))) == 0 {
if s.permCtrl.permConfig.SubOrgBreadth.Cmp(big.NewInt(int64(len(org.SubOrgList)))) == 0 {
return ErrMaxBreadth, errors.New("max breadth for suborgs reached")
}
@ -484,7 +460,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
}
// check if any previous op is pending approval for network admin
if s.checkPendingOp(s.permConfig.NwAdminOrg, pinterf) {
if s.checkPendingOp(s.permCtrl.permConfig.NwAdminOrg, pinterf) {
return ErrPendingApprovals
}
// check if org already exists
@ -510,7 +486,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
return ErrNotNetworkAdmin
}
if !s.validatePendingOp(s.permConfig.NwAdminOrg, args.orgId, args.url, args.acctId, 1, pinterf) {
if !s.validatePendingOp(s.permCtrl.permConfig.NwAdminOrg, args.orgId, args.url, args.acctId, 1, pinterf) {
return ErrNothingToApprove
}
@ -583,7 +559,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
} else {
return ErrOpNotAllowed
}
if !s.validatePendingOp(s.permConfig.NwAdminOrg, args.orgId, "", common.Address{}, pendingOp, pinterf) {
if !s.validatePendingOp(s.permCtrl.permConfig.NwAdminOrg, args.orgId, "", common.Address{}, pendingOp, pinterf) {
return ErrNothingToApprove
}
@ -625,7 +601,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
return ErrInvalidInput
}
// check if caller is network admin
if args.roleId != s.permConfig.OrgAdminRole && args.roleId != s.permConfig.NwAdminRole {
if args.roleId != s.permCtrl.permConfig.OrgAdminRole && args.roleId != s.permCtrl.permConfig.NwAdminRole {
return ErrOpNotAllowed
}
@ -652,7 +628,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
return ErrInvalidAccount
}
// validate pending op
if !s.validatePendingOp(s.permConfig.NwAdminOrg, ac.OrgId, "", args.acctId, 4, pinterf) {
if !s.validatePendingOp(s.permCtrl.permConfig.NwAdminOrg, ac.OrgId, "", args.acctId, 4, pinterf) {
return ErrNothingToApprove
}
@ -682,7 +658,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
}
// admin roles cannot be removed
if args.roleId == s.permConfig.OrgAdminRole || args.roleId == s.permConfig.NwAdminRole {
if args.roleId == s.permCtrl.permConfig.OrgAdminRole || args.roleId == s.permCtrl.permConfig.NwAdminRole {
return ErrAdminRoles
}
@ -705,7 +681,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
if args.acctId == (common.Address{0}) {
return ErrInvalidInput
}
if args.roleId == s.permConfig.OrgAdminRole || args.roleId == s.permConfig.NwAdminRole {
if args.roleId == s.permCtrl.permConfig.OrgAdminRole || args.roleId == s.permCtrl.permConfig.NwAdminRole {
return ErrInvalidRole
}
// check if caller is network admin
@ -748,7 +724,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
// validateAccount validates the account and returns the wallet associated with that for signing the transaction
func (s *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Wallet, error) {
acct := accounts.Account{Address: from}
w, err := s.acctMgr.Find(acct)
w, err := s.permCtrl.eth.AccountManager().Find(acct)
if err != nil {
return nil, err
}
@ -758,7 +734,7 @@ func (s *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Walle
func (s *QuorumControlsAPI) newPermInterfaceSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermInterfaceSession {
frmAcct, transactOpts, gasLimit, gasPrice, nonce := s.getTxParams(txa, w)
ps := &pbind.PermInterfaceSession{
Contract: s.permInterf,
Contract: s.permCtrl.permInterf,
CallOpts: bind.CallOpts{
Pending: true,
},
@ -789,7 +765,7 @@ func (s *QuorumControlsAPI) getTxParams(txa ethapi.SendTxArgs, w accounts.Wallet
if txa.Nonce != nil {
nonce = new(big.Int).SetUint64(uint64(*txa.Nonce))
} else {
nonce = new(big.Int).SetUint64(s.txPool.Nonce(frmAcct.Address))
nonce = new(big.Int).SetUint64(s.permCtrl.eth.TxPool().Nonce(frmAcct.Address))
}
return frmAcct, transactOpts, gasLimit, gasPrice, nonce
}

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -1,7 +1,7 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package permission
package bind
import (
"math/big"

View File

@ -7,7 +7,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/controls"
pbind "github.com/ethereum/go-ethereum/controls/bind/permission"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
@ -16,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
pbind "github.com/ethereum/go-ethereum/permission/bind"
"github.com/ethereum/go-ethereum/raft"
"github.com/ethereum/go-ethereum/rpc"
"io/ioutil"
@ -53,28 +53,23 @@ type PermissionLocalConfig struct {
}
type PermissionCtrl struct {
node *node.Node
ethClnt *ethclient.Client
eth *eth.Ethereum
isRaft bool
permissionedMode bool
key *ecdsa.PrivateKey
dataDir string
permUpgr *pbind.PermUpgr
permInterf *pbind.PermInterface
permNode *pbind.NodeManager
permAcct *pbind.AcctManager
permRole *pbind.RoleManager
permOrg *pbind.OrgManager
permConfig *types.PermissionConfig
orgChan chan struct{}
nodeChan chan struct{}
roleChan chan struct{}
acctChan chan struct{}
}
func (p *PermissionCtrl) Interface() *pbind.PermInterface {
return p.permInterf
node *node.Node
ethClnt *ethclient.Client
eth *eth.Ethereum
isRaft bool
key *ecdsa.PrivateKey
dataDir string
permUpgr *pbind.PermUpgr
permInterf *pbind.PermInterface
permNode *pbind.NodeManager
permAcct *pbind.AcctManager
permRole *pbind.RoleManager
permOrg *pbind.OrgManager
permConfig *types.PermissionConfig
orgChan chan struct{}
nodeChan chan struct{}
roleChan chan struct{}
acctChan chan struct{}
}
// This function takes the local config data where all the information is in string
@ -136,70 +131,95 @@ func ParsePermissionConifg(dir string) (types.PermissionConfig, error) {
}
func waitForSync(e *eth.Ethereum) {
log.Info("AJ-wait for sync")
for !types.GetSyncStatus() {
time.Sleep(10 * time.Millisecond)
}
for e.Downloader().Synchronising() {
time.Sleep(10 * time.Millisecond)
}
log.Info("AJ-wait for sync over")
}
// Creates the controls structure for permissions
func NewQuorumPermissionCtrl(stack *node.Node, permissionedMode, isRaft bool, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
func NewQuorumPermissionCtrl(stack *node.Node, isRaft bool, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
// Create a new ethclient to for interfacing with the contract
clnt, e, err := controls.CreateEthClient(stack)
//waitForSync(e)
log.Info("AJ-permission eth client create")
return &PermissionCtrl{stack, nil, nil, isRaft, stack.GetNodeKey(), stack.DataDir(), nil, nil, nil, nil, nil, nil, pconfig, make(chan struct{}), make(chan struct{}), make(chan struct{}), make(chan struct{})}, nil
}
func (p *PermissionCtrl) InitializeService() error {
clnt, ethereum, err := controls.CreateEthClient(p.node)
if err != nil {
log.Error("creating eth client failed")
return err
}
waitForSync(ethereum)
if err != nil {
log.Error("Unable to create ethereum client for permissions check", "err", err)
return nil, err
return err
}
if pconfig.IsEmpty() && permissionedMode {
if p.permConfig.IsEmpty() {
log.Error("permission-config.json is missing contract address")
return nil, errors.New("permission-config.json is missing contract address")
return errors.New("permission-config.json is missing contract address")
}
pu, err := pbind.NewPermUpgr(pconfig.UpgrdAddress, clnt)
pu, err := pbind.NewPermUpgr(p.permConfig.UpgrdAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
// check if permissioning contract is there at address. If not return from here
pm, err := pbind.NewPermInterface(pconfig.InterfAddress, clnt)
pm, err := pbind.NewPermInterface(p.permConfig.InterfAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
pmAcct, err := pbind.NewAcctManager(pconfig.AccountAddress, clnt)
pmAcct, err := pbind.NewAcctManager(p.permConfig.AccountAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
pmNode, err := pbind.NewNodeManager(pconfig.NodeAddress, clnt)
pmNode, err := pbind.NewNodeManager(p.permConfig.NodeAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
pmRole, err := pbind.NewRoleManager(pconfig.RoleAddress, clnt)
pmRole, err := pbind.NewRoleManager(p.permConfig.RoleAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
pmOrg, err := pbind.NewOrgManager(pconfig.OrgAddress, clnt)
pmOrg, err := pbind.NewOrgManager(p.permConfig.OrgAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
return err
}
return &PermissionCtrl{stack, clnt, e, isRaft, permissionedMode, stack.GetNodeKey(), stack.DataDir(), pu, pm, pmNode, pmAcct, pmRole, pmOrg, pconfig, make(chan struct{}), make(chan struct{}), make(chan struct{}), make(chan struct{})}, nil
p.permUpgr = pu
p.permInterf = pm
p.permAcct = pmAcct
p.permNode = pmNode
p.permRole = pmRole
p.permOrg = pmOrg
p.ethClnt = clnt
p.eth = ethereum
log.Info("permission service initalized")
return nil
}
// Starts the node permissioning and event monitoring for permissions
// smart contracts
func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
log.Info("permission service started...")
if p.ethClnt == nil || p.eth == nil {
log.Info("permission service not initialized")
return nil
}
log.Info("permission service start...")
// Permissions initialization
if err := p.init(); err != nil {
log.Error("Permissions init failed", "err", err)
@ -217,7 +237,7 @@ func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
// monitor org level account management events
go p.manageAccountPermissions()
log.Info("permission service started")
return nil
}
@ -227,7 +247,7 @@ func (s *PermissionCtrl) APIs() []rpc.API {
{
Namespace: "quorumPermission",
Version: "1.0",
Service: NewQuorumControlsAPI(s.eth.TxPool(), s.eth.AccountManager(), s.permConfig, s.permInterf),
Service: NewQuorumControlsAPI(s),
Public: true,
},
}
@ -238,6 +258,9 @@ func (s *PermissionCtrl) Protocols() []p2p.Protocol {
}
func (p *PermissionCtrl) Stop() error {
if p.eth == nil || p.ethClnt == nil {
return nil
}
log.Info("stopping permission service...")
p.roleChan <- struct{}{}
p.orgChan <- struct{}{}