quorum/permissions/node_permissions.go

190 lines
5.7 KiB
Go
Raw Normal View History

2018-07-12 03:00:19 -07:00
package permissions
import (
"fmt"
"encoding/json"
2018-07-12 03:00:19 -07:00
"io/ioutil"
"math/big"
"path/filepath"
"os"
2018-07-12 03:00:19 -07:00
"strings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/cmd/utils"
2018-07-13 18:22:43 -07:00
"github.com/ethereum/go-ethereum/params"
2018-07-12 03:00:19 -07:00
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"gopkg.in/urfave/cli.v1"
)
const (
PERMISSIONED_CONFIG = "permissioned-nodes.json"
)
2018-07-13 18:22:43 -07:00
//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 ){
//Create a new ethclient to for interfacing with the contract
e, stateReader := createEthClient(stack)
//call populate nodes to populate the nodes into contract
populateNodesToContract (ctx, stack, e, stateReader)
//monitor for new nodes addition via smart contract
2018-07-16 19:13:33 -07:00
go monitorNewNodeAdd(stack, stateReader)
2018-07-13 18:22:43 -07:00
}
2018-07-12 03:00:19 -07:00
//populates the nodes list from permissioned-nodes.json into the permissions
//smart contract
2018-07-13 18:22:43 -07:00
func populateNodesToContract(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)
permissionsContract, err := NewPermissions(params.QuorumPermissionsContract, stateReader)
if err != nil {
utils.Fatalf("Failed to instantiate a Permissions contract: %v", err)
}
2018-07-16 19:13:33 -07:00
2018-07-13 18:22:43 -07:00
auth, err := bind.NewTransactor(strings.NewReader(key), "")
if err != nil {
utils.Fatalf("Failed to create authorized transactor: %v", err)
}
permissionsSession := &PermissionsSession{
Contract: permissionsContract,
CallOpts: bind.CallOpts{
Pending: true,
},
TransactOpts: bind.TransactOpts{
From: auth.From,
Signer: auth.Signer,
GasLimit: 3558096384,
GasPrice: big.NewInt(0),
},
}
2018-07-16 19:13:33 -07:00
// datadir := ctx.GlobalString(utils.DataDirFlag.Name)
datadir := stack.DataDir()
2018-07-13 18:22:43 -07:00
nodes := p2p.ParsePermissionedNodes(datadir)
for _, node := range nodes {
enodeID := fmt.Sprintf("%x", node.ID[:])
log.Trace("Adding node to permissions contract", "enodeID", enodeID)
nonce := e.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
tx, err := permissionsSession.ProposeNode(enodeID, true, true)
if err != nil {
log.Warn("Failed to propose node", "err", err)
}
log.Debug("Transaction pending", "tx hash", tx.Hash())
}
}
//This functions listens on the channel for new node approval via smart contract and
// adds the same into permissioned-nodes.json
2018-07-16 19:13:33 -07:00
func monitorNewNodeAdd(stack *node.Node, stateReader *ethclient.Client){
2018-07-13 18:22:43 -07:00
permissions, err := NewPermissionsFilterer(params.QuorumPermissionsContract, stateReader)
if err != nil {
utils.Fatalf("Failed to instantiate a Permissions Filterer: %v", err)
}
2018-07-16 19:13:33 -07:00
datadir := stack.DataDir()
2018-07-13 18:22:43 -07:00
ch := make(chan *PermissionsNewNodeProposed)
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
for {
_, err = permissions.WatchNewNodeProposed(opts, ch)
if err != nil {
log.Info("Failed NewNodeProposed: %v", err)
}
var newEvent *PermissionsNewNodeProposed = <-ch
2018-07-16 19:13:33 -07:00
populatePermissionedNodes(newEvent.EnodeId, datadir)
2018-07-13 18:22:43 -07:00
}
}
//Create an RPC client for the contract interface
func createEthClient(stack *node.Node ) (*eth.Ethereum, *ethclient.Client){
var e *eth.Ethereum
if err := stack.Service(&e); err != nil {
utils.Fatalf("Ethereum service not running: %v", err)
}
rpcClient, err := stack.Attach()
if err != nil {
utils.Fatalf("Failed to attach to self: %v", err)
}
return e, ethclient.NewClient(rpcClient)
}
//This functions reads the first file in key store directory, reads the key
//value and returns the same
func getKeyFromKeyStore(ctx *cli.Context) string {
datadir := ctx.GlobalString(utils.DataDirFlag.Name)
files, err := ioutil.ReadDir(filepath.Join(datadir, "keystore"))
if err != nil {
utils.Fatalf("Failed to read keystore directory: %v", err)
}
2018-07-16 19:13:33 -07:00
// HACK: here we always use the first key as transactor
2018-07-13 18:22:43 -07:00
var keyPath string
for _, f := range files {
keyPath = filepath.Join(datadir, "keystore", f.Name())
break
}
keyBlob, err := ioutil.ReadFile(keyPath)
if err != nil {
utils.Fatalf("Failed to read key file: %v", err)
}
n := len(keyBlob)
return string(keyBlob[:n])
2018-07-12 03:00:19 -07:00
}
2018-07-16 19:13:33 -07:00
//this function populates the new node information into the permissioned-nodes.json file
func populatePermissionedNodes(enodeId string, dataDir string){
log.Debug("populatePermissionedNodes", "DataDir", dataDir, "file", PERMISSIONED_CONFIG)
path := filepath.Join(dataDir, PERMISSIONED_CONFIG)
if _, err := os.Stat(path); err != nil {
log.Error("Read Error for permissioned-nodes.json file. This is because 'permissioned' flag is specified but no permissioned-nodes.json file is present.", "err", err)
return
}
// Load the nodes from the config file
blob, err := ioutil.ReadFile(path)
log.Info("blob is before append: ","blob", blob)
if err != nil {
log.Error("populatePermissionedNodes: Failed to access nodes", "err", err)
return
}
nodelist := []string{}
if err := json.Unmarshal(blob, &nodelist); err != nil {
log.Error("parsePermissionedNodes: Failed to load nodes", "err", err)
return
}
2018-07-16 19:13:33 -07:00
// HACK: currently the ip, discpot and raft port are hard coded. Need to enhance the
//contract to pass these variables as part of the event and change this
newEnodeId := "enode://" + enodeId + "@127.0.0.1:21005?discport=0&raftport=50406"
nodelist = append(nodelist, newEnodeId)
blob, _ = json.Marshal(nodelist)
if err:= ioutil.WriteFile(path, blob, 0644); err!= nil{
log.Error("populatePermissionedNodes: Error writing new node info to file", "err", err)
}
}