add api implementation for permission node - propose node

This commit is contained in:
amalraj.manigmail.com 2018-10-30 10:41:01 +08:00
parent 299c17598a
commit 64d8db5678
11 changed files with 325 additions and 162 deletions

View File

@ -39,9 +39,10 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/controls/permissions"
"github.com/ethereum/go-ethereum/controls/permission"
"github.com/ethereum/go-ethereum/controls/cluster"
"gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/core/quorum"
)
const (
@ -291,18 +292,6 @@ func startNode(ctx *cli.Context, stack *node.Node) {
events := make(chan accounts.WalletEvent, 16)
stack.AccountManager().Subscribe(events)
//START - QUORUM Permissioning
if permissioned := ctx.GlobalBool(utils.EnableNodePermissionFlag.Name); permissioned {
if err := permissions.QuorumPermissioning(ctx, stack); err != nil {
utils.Fatalf("Failed to start Quorum Permissioning: %v", err)
}
}
// Changes for managing org level cluster keys for privateFor txns
if err := cluster.ManageOrgKeys(ctx, stack); err != nil {
log.Warn("Org key management failed", "err", err)
}
//END - QUORUM Permissioning
go func() {
// Create a chain state reader for self-derivation
rpcClient, err := stack.Attach()
@ -340,6 +329,10 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}
}()
//START - QUORUM Permissioning
startQuorumPermissionOrgKeyService(ctx, stack)
// 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
@ -366,3 +359,34 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}
}
func startQuorumPermissionOrgKeyService(ctx *cli.Context, stack *node.Node) {
if permEnabled := ctx.GlobalBool(utils.EnableNodePermissionFlag.Name); permEnabled {
v := stack.GetRPC("permnode")
if v == nil {
utils.Fatalf("Failed to start Quorum Permission API")
}
papi := v.(*quorum.PermissionAPI)
rpcClient, err := stack.Attach()
if err != nil {
utils.Fatalf("Failed to attach to self: %v", err)
}
stateReader := ethclient.NewClient(rpcClient)
papi.Init(stateReader, stack.InstanceDir())
log.Info("Permission API initialized")
pctrl, err := permission.NewQuorumPermissionCtrl(ctx, stack)
if err != nil {
utils.Fatalf("Failed to start Quorum Permission contract service: %v", err)
}
pctrl.Start()
log.Info("Node Permission service started")
}
// Changes for managing org level cluster keys for privateFor txns
kc, err := cluster.NewOrgKeyCtrl(stack)
if err != nil {
log.Warn("Failed to start quorum Org key management service", "err", err)
} else {
kc.Start()
log.Info("Org key management service started")
}
}

View File

@ -1,7 +1,6 @@
package cluster
import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/params"
@ -9,43 +8,50 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/controls"
"gopkg.in/urfave/cli.v1"
)
type OrgKeyCtrl struct {
ethClient *ethclient.Client
}
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
}
return &OrgKeyCtrl{stateReader}, nil
}
// This function first adds the node list from permissioned-nodes.json to
// the permissiones contract deployed as a precompile via genesis.json
func ManageOrgKeys(ctx *cli.Context, stack *node.Node ) error {
// Create a new ethclient to for interfacing with the contract
stateReader, _, err := controls.CreateEthClient(stack)
if err != nil {
log.Error ("Unable to create ethereum client for cluster check : ", "err" , err)
return err
}
func (k *OrgKeyCtrl) Start() error {
_, err := NewClusterFilterer(params.PrivateKeyManagementContract, k.ethClient)
// check if permissioning contract is there at address. If not return from here
if _ , err = NewClusterFilterer(params.PrivateKeyManagementContract, stateReader); err != nil {
log.Error ("Cluster not enabled for the network : ", "err" , err)
if err != nil {
log.Error("Cluster not enabled for the network : ", "err", err)
return nil
}
manageClusterKeys(stack, stateReader);
k.manageClusterKeys()
return err
}
func manageClusterKeys (stack *node.Node, stateReader *ethclient.Client ) error {
func (k *OrgKeyCtrl) manageClusterKeys() error {
//call populate nodes to populate the nodes into contract
if err := populatePrivateKeys (stack, stateReader); err != nil {
if err := k.populatePrivateKeys(); err != nil {
return err
}
//monitor for nodes deletiin via smart contract
monitorKeyChanges(stack, stateReader)
k.monitorKeyChanges()
return nil
}
func populatePrivateKeys(stack *node.Node, stateReader *ethclient.Client) error{
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, stateReader)
func (k *OrgKeyCtrl) populatePrivateKeys() error {
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error ("Failed to monitor node delete: ", "err" , err)
log.Error("Failed to monitor node delete: ", "err", err)
return err
}
@ -56,7 +62,7 @@ func populatePrivateKeys(stack *node.Node, stateReader *ethclient.Client) error{
for recExists {
recExists = pastAddEvents.Next()
if recExists {
types.AddOrgKey(pastAddEvents.Event.OrgId, pastAddEvents.Event.PrivateKey )
types.AddOrgKey(pastAddEvents.Event.OrgId, pastAddEvents.Event.PrivateKey)
}
}
@ -67,22 +73,22 @@ func populatePrivateKeys(stack *node.Node, stateReader *ethclient.Client) error{
for recExists {
recExists = pastDeleteEvents.Next()
if recExists {
types.DeleteOrgKey(pastDeleteEvents.Event.OrgId, pastDeleteEvents.Event.PrivateKey )
types.DeleteOrgKey(pastDeleteEvents.Event.OrgId, pastDeleteEvents.Event.PrivateKey)
}
}
return nil
}
func monitorKeyChanges(stack *node.Node, stateReader *ethclient.Client) {
go monitorKeyAdd(stack, stateReader)
func (k *OrgKeyCtrl) monitorKeyChanges() {
go k.monitorKeyAdd()
go monitorKeyDelete(stack, stateReader)
go k.monitorKeyDelete()
}
func monitorKeyAdd(stack *node.Node, stateReader *ethclient.Client){
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, stateReader)
func (k *OrgKeyCtrl) monitorKeyAdd() {
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error ("Failed to monitor Account cluster : ", "err" , err)
log.Error("Failed to monitor Account cluster : ", "err", err)
}
ch := make(chan *ClusterOrgKeyAdded)
@ -101,13 +107,13 @@ func monitorKeyAdd(stack *node.Node, stateReader *ethclient.Client){
case newEvent = <-ch:
types.AddOrgKey(newEvent.OrgId, newEvent.PrivateKey)
}
}
}
}
func monitorKeyDelete(stack *node.Node, stateReader *ethclient.Client){
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, stateReader)
func (k *OrgKeyCtrl) monitorKeyDelete() {
cluster, err := NewClusterFilterer(params.PrivateKeyManagementContract, k.ethClient)
if err != nil {
log.Error ("Failed to monitor Account cluster : ", "err" , err)
log.Error("Failed to monitor Account cluster : ", "err", err)
}
ch := make(chan *ClusterOrgKeyDeleted)
@ -126,5 +132,5 @@ func monitorKeyDelete(stack *node.Node, stateReader *ethclient.Client){
case newEvent = <-ch:
types.DeleteOrgKey(newEvent.OrgId, newEvent.PrivateKey)
}
}
}
}

View File

@ -1,4 +1,4 @@
package permissions
package permission
import (
"fmt"
@ -25,70 +25,80 @@ import (
"gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/controls/permbind"
)
const (
PERMISSIONED_CONFIG = "permissioned-nodes.json"
BLACKLIST_CONFIG = "disallowed-nodes.json"
BLACKLIST_CONFIG = "disallowed-nodes.json"
)
type NodeOperation uint8
const (
NodeAdd NodeOperation = iota
NodeDelete
)
func SayHello(n string) string{
return "Hello " + n + "!"
type PermissionCtrl struct {
node *node.Node
ethClnt *ethclient.Client
eth *eth.Ethereum
isRaft bool
key string
}
// This function first adds the node list from permissioned-nodes.json to
// the permissiones contract deployed as a precompile via genesis.json
func QuorumPermissioning(ctx *cli.Context, stack *node.Node ) error {
func NewQuorumPermissionCtrl(ctx *cli.Context, stack *node.Node) (*PermissionCtrl, error) {
// Create a new ethclient to for interfacing with the contract
stateReader, e, err := controls.CreateEthClient(stack)
if err != nil {
log.Error ("Unable to create ethereum client for permissions check : ", "err" , err)
return err
}
// check if permissioning contract is there at address. If not return from here
if _ , err = permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader); err != nil {
log.Error ("Permissions not enabled for the network : ", "err" , err)
return nil
log.Error("Unable to create ethereum client for permissions check : ", "err", err)
return nil, err
}
isRaft := false
if ctx.GlobalBool(utils.RaftModeFlag.Name) {
isRaft = true
}
//Read the key file from key store. SHOULD WE MAKE IT CONFIG value
key := getKeyFromKeyStore(ctx)
return &PermissionCtrl{stack, stateReader, e, isRaft, key}, nil
}
// This function first adds the node list from permissioned-nodes.json to
// the permissiones contract deployed as a precompile via genesis.json
func (p *PermissionCtrl) Start() error {
// check if permissioning contract is there at address. If not return from here
if _, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt); err != nil {
log.Error("Permissions not enabled for the network : ", "err", err)
return nil
}
// Permissions initialization
err = permissionsInit(ctx, stack, e, stateReader, isRaft)
p.init()
// Monitors node addition and decativation from network
manageNodePermissions(ctx, stack, e, stateReader, isRaft);
p.manageNodePermissions()
// Monitors account level persmissions update from smart contarct
manageAccountPermissions(stack, stateReader);
p.manageAccountPermissions()
return nil
}
// This functions updates the initial values for the network
func permissionsInit(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateReader *ethclient.Client, isRaft bool) error {
func (p *PermissionCtrl) init() error {
// populate the initial list of nodes into the smart contract
// from permissioned-nodes.json
populateStaticNodesToContract(ctx, stack, e, stateReader)
p.populateStaticNodesToContract()
// populate the account access for the genesis.json accounts. these
// accounts will have full access
// populateInitAccountAccess()
// call populates the node details from contract to KnownNodes
if err := populatePermissionedNodes (stack, stateReader, isRaft); err != nil {
if err := p.populatePermissionedNodes(); err != nil {
return err
}
// call populates the account permissions based on past history
if err := populateAcctPermissions (stack, stateReader); err != nil {
if err := p.populateAcctPermissions(); err != nil {
return err
}
@ -96,24 +106,24 @@ func permissionsInit(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateR
}
// Manages node addition and decavtivation from network
func manageNodePermissions(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateReader *ethclient.Client, isRaft bool) {
func (p *PermissionCtrl) manageNodePermissions() {
//monitor for new nodes addition via smart contract
go monitorNewNodeAdd(stack, stateReader, isRaft)
go p.monitorNewNodeAdd()
//monitor for nodes deletiin via smart contract
go monitorNodeDeactivation(stack, stateReader, isRaft)
go p.monitorNodeDeactivation()
//monitor for nodes blacklisting via smart contract
go monitorNodeBlacklisting(stack, stateReader, isRaft)
go p.monitorNodeBlacklisting()
}
// This functions listens on the channel for new node approval via smart contract and
// adds the same into permissioned-nodes.json
func monitorNewNodeAdd(stack *node.Node, stateReader *ethclient.Client, isRaft bool) {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) monitorNewNodeAdd() {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("failed to monitor new node add : ", "err" , err)
log.Error("failed to monitor new node add : ", "err", err)
}
ch := make(chan *permbind.PermissionsNodeApproved, 1)
@ -131,17 +141,17 @@ func monitorNewNodeAdd(stack *node.Node, stateReader *ethclient.Client, isRaft b
for {
select {
case nodeAddEvent = <-ch:
updatePermissionedNodes(stack, nodeAddEvent.EnodeId, nodeAddEvent.IpAddrPort, nodeAddEvent.DiscPort, nodeAddEvent.RaftPort, isRaft, NodeAdd)
p.updatePermissionedNodes(nodeAddEvent.EnodeId, nodeAddEvent.IpAddrPort, nodeAddEvent.DiscPort, nodeAddEvent.RaftPort, NodeAdd)
}
}
}
}
// This functions listens on the channel for new node approval via smart contract and
// adds the same into permissioned-nodes.json
func monitorNodeDeactivation(stack *node.Node, stateReader *ethclient.Client, isRaft bool) {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) monitorNodeDeactivation() {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("Failed to monitor node delete: ", "err" , err)
log.Error("Failed to monitor node delete: ", "err", err)
}
ch := make(chan *permbind.PermissionsNodeDeactivated)
@ -159,18 +169,18 @@ func monitorNodeDeactivation(stack *node.Node, stateReader *ethclient.Client, is
for {
select {
case newNodeDeleteEvent = <-ch:
updatePermissionedNodes(stack, newNodeDeleteEvent.EnodeId, newNodeDeleteEvent.IpAddrPort, newNodeDeleteEvent.DiscPort, newNodeDeleteEvent.RaftPort, isRaft, NodeDelete)
}
p.updatePermissionedNodes(newNodeDeleteEvent.EnodeId, newNodeDeleteEvent.IpAddrPort, newNodeDeleteEvent.DiscPort, newNodeDeleteEvent.RaftPort, NodeDelete)
}
}
}
// This function listnes on the channel for any node blacklisting event via smart contract
// and adds the same disallowed-nodes.json
func monitorNodeBlacklisting(stack *node.Node, stateReader *ethclient.Client, isRaft bool) {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) monitorNodeBlacklisting() {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("failed to monitor new node add : ", "err" , err)
log.Error("failed to monitor new node add : ", "err", err)
}
ch := make(chan *permbind.PermissionsNodeBlacklisted, 1)
@ -187,52 +197,52 @@ func monitorNodeBlacklisting(stack *node.Node, stateReader *ethclient.Client, is
for {
select {
case nodeBlacklistEvent = <-ch:
updateDisallowedNodes(nodeBlacklistEvent, stack, isRaft)
p.updateDisallowedNodes(nodeBlacklistEvent)
}
}
}
}
//this function populates the new node information into the permissioned-nodes.json file
func updatePermissionedNodes(stack *node.Node, enodeId , ipAddrPort, discPort, raftPort string, isRaft bool, operation NodeOperation){
newEnodeId := formatEnodeId(enodeId, ipAddrPort, discPort, raftPort, isRaft)
func (p *PermissionCtrl) updatePermissionedNodes(enodeId, ipAddrPort, discPort, raftPort string, operation NodeOperation) {
newEnodeId := formatEnodeId(enodeId, ipAddrPort, discPort, raftPort, p.isRaft)
//new logic to update the server KnownNodes variable for permissioning
server := stack.Server();
server := p.node.Server();
newNode, err := discover.ParseNode(newEnodeId)
if err != nil {
log.Error("updatePermissionedNodes: Node URL", "url", newEnodeId, "err", err)
}
if (operation == NodeAdd){
if (operation == NodeAdd) {
// Add the new enode id to server.KnownNodes
server.KnownNodes = append(server.KnownNodes, newNode)
} else {
// delete the new enode id from server.KnownNodes
index := 0
for i, node := range server.KnownNodes {
if (node.ID == newNode.ID){
if (node.ID == newNode.ID) {
index = i
}
}
server.KnownNodes = append (server.KnownNodes[:index], server.KnownNodes[index+1:]...)
server.KnownNodes = append(server.KnownNodes[:index], server.KnownNodes[index+1:]...)
}
}
//this function populates the new node information into the permissioned-nodes.json file
func updateDisallowedNodes(nodeBlacklistEvent *permbind.PermissionsNodeBlacklisted, stack *node.Node, isRaft bool){
dataDir := stack.DataDir()
func (p *PermissionCtrl) updateDisallowedNodes(nodeBlacklistEvent *permbind.PermissionsNodeBlacklisted) {
dataDir := p.node.InstanceDir()
log.Debug("updateDisallowedNodes", "DataDir", dataDir, "file", BLACKLIST_CONFIG)
fileExisted := true
path := filepath.Join(dataDir, BLACKLIST_CONFIG)
// Check if the file is existing. If the file is not existing create the file
if _, err := os.Stat(path); err != nil {
log.Error("Read Error for disallowed-nodes.json file." , "err", err)
log.Error("Read Error for disallowed-nodes.json file.", "err", err)
if _, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644); err != nil {
log.Error("Failed to create disallowed-nodes.json file ", "err", err)
return
return
}
fileExisted = false
}
@ -248,37 +258,38 @@ func updateDisallowedNodes(nodeBlacklistEvent *permbind.PermissionsNodeBlacklist
if (blob != nil) {
if err := json.Unmarshal(blob, &nodelist); err != nil {
log.Error("updateDisallowedNodes: Failed to load nodes list", "err", err)
return
return
}
}
}
newEnodeId := formatEnodeId (nodeBlacklistEvent.EnodeId, nodeBlacklistEvent.IpAddrPort, nodeBlacklistEvent.DiscPort, nodeBlacklistEvent.RaftPort, isRaft )
newEnodeId := formatEnodeId(nodeBlacklistEvent.EnodeId, nodeBlacklistEvent.IpAddrPort, nodeBlacklistEvent.DiscPort, nodeBlacklistEvent.RaftPort, p.isRaft)
nodelist = append(nodelist, newEnodeId)
mu := sync.RWMutex{}
blob, _ := json.Marshal(nodelist)
mu.Lock()
if err:= ioutil.WriteFile(path, blob, 0644); err!= nil{
if err := ioutil.WriteFile(path, blob, 0644); err != nil {
log.Error("updateDisallowedNodes: Error writing new node info to file", "err", err)
}
mu.Unlock()
// Disconnect the peer if it is already connected
disconnectNode(stack, newEnodeId, isRaft)
p.disconnectNode(newEnodeId)
}
// Manages account level permissions update
func manageAccountPermissions(stack *node.Node, stateReader *ethclient.Client) error {
func (p *PermissionCtrl) manageAccountPermissions() error {
//monitor for nodes deletiin via smart contract
go monitorAccountPermissions(stack, stateReader)
go p.monitorAccountPermissions()
return nil
}
// populates the nodes list from permissioned-nodes.json into the permissions
// smart contract
func populatePermissionedNodes (stack *node.Node, stateReader *ethclient.Client, isRaft bool) error{
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) populatePermissionedNodes() error {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("Failed to monitor node delete: ", "err" , err)
log.Error("Failed to monitor node delete: ", "err", err)
return err
}
@ -289,7 +300,7 @@ func populatePermissionedNodes (stack *node.Node, stateReader *ethclient.Client,
for recExists {
recExists = pastAddEvent.Next()
if recExists {
updatePermissionedNodes(stack, pastAddEvent.Event.EnodeId, pastAddEvent.Event.IpAddrPort, pastAddEvent.Event.DiscPort, pastAddEvent.Event.RaftPort, isRaft, NodeAdd)
p.updatePermissionedNodes(pastAddEvent.Event.EnodeId, pastAddEvent.Event.IpAddrPort, pastAddEvent.Event.DiscPort, pastAddEvent.Event.RaftPort, NodeAdd)
}
}
@ -300,7 +311,7 @@ func populatePermissionedNodes (stack *node.Node, stateReader *ethclient.Client,
for recExists {
recExists = pastDelEvent.Next()
if recExists {
updatePermissionedNodes(stack, pastDelEvent.Event.EnodeId, pastDelEvent.Event.IpAddrPort, pastDelEvent.Event.DiscPort, pastDelEvent.Event.RaftPort, isRaft, NodeDelete)
p.updatePermissionedNodes(pastDelEvent.Event.EnodeId, pastDelEvent.Event.IpAddrPort, pastDelEvent.Event.DiscPort, pastDelEvent.Event.RaftPort, NodeDelete)
}
}
return nil
@ -308,10 +319,10 @@ func populatePermissionedNodes (stack *node.Node, stateReader *ethclient.Client,
// populates the nodes list from permissioned-nodes.json into the permissions
// smart contract
func populateAcctPermissions(stack *node.Node, stateReader *ethclient.Client) error{
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) populateAcctPermissions() error {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("Failed to monitor node delete: ", "err" , err)
log.Error("Failed to monitor node delete: ", "err", err)
return err
}
@ -328,13 +339,12 @@ func populateAcctPermissions(stack *node.Node, stateReader *ethclient.Client) er
return nil
}
// Monitors permissions changes at acount level and uodate the global permissions
// map with the same
func monitorAccountPermissions(stack *node.Node, stateReader *ethclient.Client) {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
func (p *PermissionCtrl) monitorAccountPermissions() {
permissions, err := permbind.NewPermissionsFilterer(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
log.Error ("Failed to monitor Account permissions : ", "err" , err)
log.Error("Failed to monitor Account permissions : ", "err", err)
}
ch := make(chan *permbind.PermissionsAccountAccessModified)
@ -353,14 +363,14 @@ func monitorAccountPermissions(stack *node.Node, stateReader *ethclient.Client)
case newEvent = <-ch:
types.AddAccountAccess(newEvent.Address, newEvent.Access)
}
}
}
}
// Disconnect the node from the network
func disconnectNode (stack *node.Node, enodeId string, isRaft bool){
if isRaft {
func (p *PermissionCtrl) disconnectNode(enodeId string) {
if p.isRaft {
var raftService *raft.RaftService
if err := stack.Service(&raftService); err == nil {
if err := p.node.Service(&raftService); err == nil {
raftApi := raft.NewPublicRaftAPI(raftService)
//get the raftId for the given enodeId
@ -371,7 +381,7 @@ func disconnectNode (stack *node.Node, enodeId string, isRaft bool){
}
} else {
// Istanbul - disconnect the peer
server := stack.Server()
server := p.node.Server()
if server != nil {
node, err := discover.ParseNode(enodeId)
if err == nil {
@ -383,25 +393,24 @@ func disconnectNode (stack *node.Node, enodeId string, isRaft bool){
// helper function to format EnodeId
// This will format the EnodeId and return
func formatEnodeId( enodeId , ipAddrPort, discPort, raftPort string, isRaft bool) string {
func formatEnodeId(enodeId, ipAddrPort, discPort, raftPort string, isRaft bool) string {
newEnodeId := "enode://" + enodeId + "@" + ipAddrPort + "?discPort=" + discPort
if isRaft {
newEnodeId += "&raftport=" + raftPort
newEnodeId += "&raftport=" + raftPort
}
return newEnodeId
}
//populates the nodes list from permissioned-nodes.json into the permissions
//smart contract
func populateStaticNodesToContract(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateReader *ethclient.Client){
//Read the key file from key store. SHOULD WE MAKE IT CONFIG value
key := getKeyFromKeyStore(ctx)
func (p *PermissionCtrl) populateStaticNodesToContract() {
permissionsContract, err := permbind.NewPermissions(params.QuorumPermissionsContract, stateReader)
permissionsContract, err := permbind.NewPermissions(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
utils.Fatalf("Failed to instantiate a Permissions contract: %v", err)
}
auth, err := bind.NewTransactor(strings.NewReader(key), "")
auth, err := bind.NewTransactor(strings.NewReader(p.key), "")
if err != nil {
utils.Fatalf("Failed to create authorized transactor: %v", err)
}
@ -424,7 +433,7 @@ func populateStaticNodesToContract(ctx *cli.Context, stack *node.Node, e *eth.Et
log.Warn("Failed to udpate network boot status ", "err", err)
}
if tx != true {
datadir := ctx.GlobalString(utils.DataDirFlag.Name)
datadir := p.node.InstanceDir()
nodes := p2p.ParsePermissionedNodes(datadir)
for _, node := range nodes {
@ -439,7 +448,7 @@ func populateStaticNodesToContract(ctx *cli.Context, stack *node.Node, e *eth.Et
log.Trace("Adding node to permissions contract", "enodeID", enodeID)
nonce := e.TxPool().Nonce(permissionsSession.TransactOpts.From)
nonce := p.eth.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
tx, err := permissionsSession.ProposeNode(enodeID, ipAddrPort, discPort, raftPort)
@ -449,7 +458,7 @@ func populateStaticNodesToContract(ctx *cli.Context, stack *node.Node, e *eth.Et
log.Debug("Transaction pending", "tx hash", tx.Hash())
}
// update the network boot status to true
nonce := e.TxPool().Nonce(permissionsSession.TransactOpts.From)
nonce := p.eth.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
_, err := permissionsSession.UpdateNetworkBootStatus()

View File

@ -1,5 +1,5 @@
package backend
package permission
/*
import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/log"
@ -140,3 +140,4 @@ func (s *PermissionAPI) ValidNodes() []string {
log.Info("AJ-called6")
return []string{"n1", "n2"}
}
*/

View File

@ -0,0 +1,115 @@
package quorum
import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethclient"
"io/ioutil"
"path/filepath"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/params"
"strings"
"github.com/ethereum/go-ethereum/p2p/discover"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/controls/permbind"
)
type PermissionAPI struct {
txPool *core.TxPool
ethClnt *ethclient.Client
permContr *permbind.Permissions
transOpts *bind.TransactOpts
initialized bool
}
func NewPermissionAPI(e *core.TxPool) *PermissionAPI {
pa := &PermissionAPI{e, nil, nil, nil, false}
return pa
}
func (p *PermissionAPI) Init(ethClnt *ethclient.Client, datadir string) error {
if !p.initialized {
p.ethClnt = ethClnt
key, kerr := getKeyFromKeyStore(datadir)
if kerr != nil {
log.Error("error reading key file", "err", kerr)
return kerr
}
permContr, err := permbind.NewPermissions(params.QuorumPermissionsContract, p.ethClnt)
if err != nil {
return err
}
p.permContr = permContr
auth, err := bind.NewTransactor(strings.NewReader(key), "")
if err != nil {
return err
}
p.transOpts = auth
p.initialized = true
}
return nil
}
func (s *PermissionAPI) ProposeNode(enodeId string) string {
node, err := discover.ParseNode(enodeId)
if err != nil {
return fmt.Sprintf("invalid node id: %v", err)
}
enodeID := node.ID.String()
ipAddr := node.IP.String()
port := fmt.Sprintf("%v", node.TCP)
discPort := fmt.Sprintf("%v", node.UDP)
raftPort := fmt.Sprintf("%v", node.RaftPort)
ipAddrPort := ipAddr + ":" + port
log.Trace("AJ-Adding node to permissions contract", "enodeID", enodeID)
nonce := s.txPool.Nonce(s.transOpts.From)
s.transOpts.Nonce = new(big.Int).SetUint64(nonce)
permissionsSession := &permbind.PermissionsSession{
Contract: s.permContr,
CallOpts: bind.CallOpts{
Pending: true,
},
TransactOpts: bind.TransactOpts{
From: s.transOpts.From,
Signer: s.transOpts.Signer,
GasLimit: 4700000,
GasPrice: big.NewInt(0),
},
}
tx, err := permissionsSession.ProposeNode(enodeID, ipAddrPort, discPort, raftPort)
if err != nil {
log.Warn("AJ-Failed to propose node", "err", err)
}
statusMsg := fmt.Sprintf("Transaction pending tx hash %s", tx.Hash())
log.Debug(statusMsg)
return statusMsg
}
func getKeyFromKeyStore(datadir string) (string, error) {
files, err := ioutil.ReadDir(filepath.Join(datadir, "keystore"))
if err != nil {
return "", err
}
// HACK: here we always use the first key as transactor
var keyPath string
for _, f := range files {
keyPath = filepath.Join(datadir, "keystore", f.Name())
break
}
keyBlob, err := ioutil.ReadFile(keyPath)
if err != nil {
return "", err
}
n := len(keyBlob)
return string(keyBlob[:n]), nil
}

View File

@ -52,7 +52,8 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
)
"github.com/ethereum/go-ethereum/core/quorum"
)
type LesServer interface {
Start(srvr *p2p.Server)
@ -274,6 +275,9 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)
//TODO add perm service
// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
@ -323,6 +327,13 @@ func (s *Ethereum) APIs() []rpc.API {
Service: s.netRPCService,
Public: true,
},
{
Namespace: "permnode",
Version: "1.0",
Service: quorum.NewPermissionAPI(s.txPool),
Public: true,
},
}...)
}

View File

@ -34,14 +34,8 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
"github.com/prometheus/prometheus/util/flock"
"github.com/ethereum/go-ethereum/controls/backend"
/* "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/cmd/utils"*/
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/eth"
)
"github.com/ethereum/go-ethereum/core/quorum"
)
// Node is a container on which services can be registered.
type Node struct {
@ -80,6 +74,15 @@ type Node struct {
log log.Logger
}
func (n *Node) GetRPC(name string) interface{} {
for _, v := range n.rpcAPIs {
if v.Namespace == name {
return v.Service
}
}
return nil
}
// New creates a new P2P node, ready for protocol registration.
func New(conf *Config) (*Node, error) {
// Copy config and resolve the datadir so future changes to the current
@ -255,17 +258,6 @@ func (n *Node) openDataDir() error {
return nil
}
func createEthClient(stack *Node) (*ethclient.Client, *eth.Ethereum, error){
var e *eth.Ethereum
if err := stack.Service(&e); err != nil {
return nil, nil, err
}
rpcClient, err := stack.Attach()
if err != nil {
return nil, nil, err
}
return ethclient.NewClient(rpcClient), e, nil
}
// startRPC is a helper method to start all the various RPC endpoint during node
// startup. It's not meant to be called at any time afterwards as it makes certain
@ -275,16 +267,21 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
apis := n.apis()
for _, service := range services {
//TODO get a ethereum service and pass the config from it to add perm service
apis = append(apis, service.APIs()...)
}
if n.config.EnableNodePermission {
ec, e, err := createEthClient(n)
if err != nil {
utils.Fatalf("Error creating eth client: %v", err)
tapis := service.APIs()
for _, e := range tapis {
//initialize quorum's permission API with ethclient and datadir before starting the service
if e.Namespace == "permnode" {
log.Info("AJ-permnode service found. init the node")
v := e.Service.(*quorum.PermissionAPI)
log.Info("AJ-permnode", "v", v)
/*rpcClient, err := n.Attach()
if err != nil {
return err
}
v.Init(ethclient.NewClient(rpcClient), n.InstanceDir())*/
}
}
apis = append(apis, backend.APIs(ec, e, n.InstanceDir())...)
log.Info("AJ-permissions api added")
apis = append(apis, tapis...)
}
// Start the various API endpoints, terminating all in case of errors