mirror of https://github.com/poanetwork/quorum.git
add api implementation for permission node - propose node
This commit is contained in:
parent
299c17598a
commit
64d8db5678
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
|
@ -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"}
|
||||
}
|
||||
*/
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
|
||||
}...)
|
||||
}
|
||||
|
||||
|
|
53
node/node.go
53
node/node.go
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue