permission: added cache rebuild when an evicted item is accessed for permission checks

This commit is contained in:
vsmk98 2019-10-02 23:43:24 +08:00
parent cf6e64b513
commit 9a2a3f5b2e
21 changed files with 345 additions and 69 deletions

View File

@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/common"
lru "github.com/hashicorp/golang-lru"
"github.com/hashicorp/golang-lru"
)
type AccessType uint8
@ -129,40 +129,86 @@ type AccountKey struct {
}
type OrgCache struct {
c *lru.Cache
mux sync.Mutex
c *lru.Cache
mux sync.Mutex
reqCh chan string
respCh chan *OrgInfo
evicted bool
}
type NodeCache struct {
c *lru.Cache
c *lru.Cache
reqCh chan string
respCh chan *NodeInfo
evicted bool
}
type RoleCache struct {
c *lru.Cache
c *lru.Cache
reqCh chan *RoleKey
respCh chan *RoleInfo
evicted bool
}
type AcctCache struct {
c *lru.Cache
c *lru.Cache
reqCh chan common.Address
respCh chan *AccountInfo
evicted bool
}
func NewOrgCache() *OrgCache {
c, _ := lru.New(defaultOrgMapLimit)
return &OrgCache{c, sync.Mutex{}}
orgCache := OrgCache{reqCh: make(chan string, 10), respCh: make(chan *OrgInfo, 10), evicted: false}
onEvictedFunc := func(k interface{}, v interface{}) {
orgCache.evicted = true
}
orgCache.c, _ = lru.NewWithEvict(defaultOrgMapLimit, onEvictedFunc)
return &orgCache
}
func NewNodeCache() *NodeCache {
c, _ := lru.New(defaultNodeMapLimit)
return &NodeCache{c}
nodeCache := NodeCache{reqCh: make(chan string, 1), respCh: make(chan *NodeInfo, 1), evicted: false}
onEvictedFunc := func(k interface{}, v interface{}) {
nodeCache.evicted = true
}
nodeCache.c, _ = lru.NewWithEvict(defaultNodeMapLimit, onEvictedFunc)
return &nodeCache
}
func NewRoleCache() *RoleCache {
c, _ := lru.New(defaultRoleMapLimit)
return &RoleCache{c}
roleCache := RoleCache{reqCh: make(chan *RoleKey, 1), respCh: make(chan *RoleInfo, 1), evicted: false}
onEvictedFunc := func(k interface{}, v interface{}) {
roleCache.evicted = true
}
roleCache.c, _ = lru.NewWithEvict(defaultRoleMapLimit, onEvictedFunc)
return &roleCache
}
func NewAcctCache() *AcctCache {
c, _ := lru.New(defaultAccountMapLimit)
return &AcctCache{c}
acctCache := AcctCache{reqCh: make(chan common.Address, 1), respCh: make(chan *AccountInfo, 1), evicted: false}
onEvictedFunc := func(k interface{}, v interface{}) {
acctCache.evicted = true
}
acctCache.c, _ = lru.NewWithEvict(defaultAccountMapLimit, onEvictedFunc)
return &acctCache
}
func (a *AcctCache) GetAcctCacheChannels() (chan common.Address, chan *AccountInfo) {
return a.reqCh, a.respCh
}
func (o *OrgCache) GetOrgCacheChannels() (chan string, chan *OrgInfo) {
return o.reqCh, o.respCh
}
func (r *RoleCache) GetRoleCacheChannels() (chan *RoleKey, chan *RoleInfo) {
return r.reqCh, r.respCh
}
func (n *NodeCache) GetNodeCacheChannels() (chan string, chan *NodeInfo) {
return n.reqCh, n.respCh
}
var syncStarted = false
@ -172,10 +218,14 @@ var QIP714BlockReached = false
var networkAdminRole string
var orgAdminRole string
const defaultOrgMapLimit = 2000
const defaultRoleMapLimit = 2500
const defaultNodeMapLimit = 1000
const defaultAccountMapLimit = 6000
//const defaultOrgMapLimit = 2000
//const defaultRoleMapLimit = 2500
//const defaultNodeMapLimit = 1000
//const defaultAccountMapLimit = 6000
const defaultOrgMapLimit = 2
const defaultRoleMapLimit = 100
const defaultNodeMapLimit = 100
const defaultAccountMapLimit = 2
var OrgInfoMap = NewOrgCache()
var NodeInfoMap = NewNodeCache()
@ -195,7 +245,7 @@ func GetSyncStatus() bool {
}
// sets the default access to Readonly upon QIP714Blokc
func SetDefaultAccess(){
func SetDefaultAccess() {
DefaultAccess = ReadOnly
QIP714BlockReached = true
}
@ -243,12 +293,27 @@ func containsKey(s []string, e string) bool {
}
func (o *OrgCache) GetOrg(orgId string) *OrgInfo {
defer o.mux.Unlock()
o.mux.Lock()
key := OrgKey{OrgId: orgId}
if ent, ok := o.c.Get(key); ok {
return ent.(*OrgInfo)
}
// check if the org cache is evicted. if yes we need
// fetch the record from the contract
if o.evicted {
// send the org details on a channel for permissions to
// populate details from contracts
o.reqCh <- orgId
orgRec := <-o.respCh
if orgRec == nil {
return nil
}
// insert the received record into cache
o.UpsertOrg(orgRec.OrgId, orgRec.ParentOrgId, orgRec.UltimateParent, orgRec.Level, orgRec.Status)
//return the record
return orgRec
}
return nil
}
@ -275,6 +340,24 @@ func (n *NodeCache) GetNodeByUrl(url string) *NodeInfo {
return v.(*NodeInfo)
}
}
// check if the node cache is evicted. if yes we need
// fetch the record from the contract
if n.evicted {
// send the node details on a channel for permissions to
// populate details from contracts
n.reqCh <- url
nodeRec := <- n.respCh
if nodeRec == nil {
return nil
}
// insert the received record into cache
n.UpsertNode(nodeRec.OrgId, nodeRec.Url, nodeRec.Status)
//return the record
return nodeRec
}
return nil
}
@ -297,6 +380,23 @@ func (a *AcctCache) GetAccount(acct common.Address) *AccountInfo {
if v, ok := a.c.Get(AccountKey{acct}); ok {
return v.(*AccountInfo)
}
// check if the account cache is evicted. if yes we need
// fetch the record from the contract
if a.evicted {
// send the account details on a channel for permissions to
// populate details from contracts
a.reqCh <- acct
acctRec := <-a.respCh
// insert the received record into cache
if acctRec == nil {
return nil
}
a.UpsertAccount(acctRec.OrgId, acctRec.RoleId, acctRec.AcctId, acctRec.IsOrgAdmin, acctRec.Status)
//return the record
return acctRec
}
return nil
}
@ -346,6 +446,22 @@ func (r *RoleCache) GetRole(orgId string, roleId string) *RoleInfo {
if ent, ok := r.c.Get(key); ok {
return ent.(*RoleInfo)
}
// check if the role cache is evicted. if yes we need
// fetch the record from the contract
if r.evicted{
// send the role details on a channel for permissions to
// populate details from contracts
r.reqCh <- &key
roleRec := <-r.respCh
if roleRec == nil {
return nil
}
// insert the received record into cache
r.UpsertRole(roleRec.OrgId, roleRec.RoleId, roleRec.IsVoter, roleRec.IsAdmin, roleRec.Access, roleRec.Active)
//return the record
return roleRec
}
return nil
}
@ -393,7 +509,7 @@ func GetAcctAccess(acctId common.Address) AccessType {
}
func ValidateNodeForTxn(hexnodeId string, from common.Address) bool {
if !QIP714BlockReached || hexnodeId == ""{
if !QIP714BlockReached || hexnodeId == "" {
return true
}
@ -412,7 +528,7 @@ func ValidateNodeForTxn(hexnodeId string, from common.Address) bool {
for _, n := range NodeInfoMap.GetNodeList() {
if OrgInfoMap.GetOrg(n.OrgId).UltimateParent == ultimateParent {
recEnodeId, _ := enode.ParseV4(n.Url)
if recEnodeId.ID() == passedEnodeId.ID() {
if recEnodeId.ID() == passedEnodeId.ID() && n.Status == NodeApproved {
return true
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -95,6 +95,9 @@ contract NodeManager {
*/
function getNodeDetails(string calldata enodeId) external view
returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
return ("", enodeId, 0);
}
uint256 nodeIndex = _getNodeIndex(enodeId);
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId,
nodeList[nodeIndex].status);

View File

@ -195,6 +195,23 @@ contract OrgManager {
orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status);
}
/** @notice returns org info for a given org id
* @param _orgId org id
* @return org id
* @return parent org id
* @return ultimate parent id
* @return level in the org tree
* @return status
*/
function getOrgDetails(string calldata _orgId) external view returns (string memory,
string memory, string memory, uint256, uint256) {
if (!checkOrgExists(_orgId)){
return (_orgId, "", "", 0,0);
}
uint256 _orgIndex = _getOrgIndex(_orgId);
return (orgList[_orgIndex].orgId, orgList[_orgIndex].parentId,
orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status);
}
/** @notice returns the master org id for the given org or sub org
* @param _orgId org id
* @return master org id
@ -219,6 +236,9 @@ contract OrgManager {
*/
function checkOrgStatus(string memory _orgId, uint256 _orgStatus)
public view returns (bool){
if (OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0) {
return false;
}
uint256 id = _getOrgIndex(_orgId);
return ((OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0)
&& orgList[id].status == _orgStatus);
@ -334,7 +354,7 @@ contract OrgManager {
/** @notice returns the org index from the org list for the given org
* @return org index
*/
function _getOrgIndex(string memory _orgId) public view returns (uint){
function _getOrgIndex(string memory _orgId) private view returns (uint){
return OrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
}

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 +1 @@
[{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_action","type":"uint256"}],"name":"updateOrg","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_action","type":"uint256"}],"name":"approveOrgStatusUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"getUltimateParent","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_pOrgId","type":"string"},{"name":"_orgId","type":"string"}],"name":"addSubOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"_getOrgIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_orgIndex","type":"uint256"}],"name":"getOrgInfo","outputs":[{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNumberOfOrgs","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"},{"name":"_orgStatus","type":"uint256"}],"name":"checkOrgStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_breadth","type":"uint256"},{"name":"_depth","type":"uint256"}],"name":"setUpOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"}],"name":"approveOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"}],"name":"addOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"checkOrgExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_permUpgradable","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"},{"indexed":false,"name":"_status","type":"uint256"}],"name":"OrgApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"},{"indexed":false,"name":"_status","type":"uint256"}],"name":"OrgPendingApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"}],"name":"OrgSuspended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"}],"name":"OrgSuspensionRevoked","type":"event"}]
[{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_action","type":"uint256"}],"name":"updateOrg","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_action","type":"uint256"}],"name":"approveOrgStatusUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"getUltimateParent","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_pOrgId","type":"string"},{"name":"_orgId","type":"string"}],"name":"addSubOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgIndex","type":"uint256"}],"name":"getOrgInfo","outputs":[{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNumberOfOrgs","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"},{"name":"_orgStatus","type":"uint256"}],"name":"checkOrgStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"},{"name":"_breadth","type":"uint256"},{"name":"_depth","type":"uint256"}],"name":"setUpOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"}],"name":"approveOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"getOrgDetails","outputs":[{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orgId","type":"string"}],"name":"addOrg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orgId","type":"string"}],"name":"checkOrgExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_permUpgradable","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"},{"indexed":false,"name":"_status","type":"uint256"}],"name":"OrgApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"},{"indexed":false,"name":"_status","type":"uint256"}],"name":"OrgPendingApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"}],"name":"OrgSuspended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_orgId","type":"string"},{"indexed":false,"name":"_porgId","type":"string"},{"indexed":false,"name":"_ultParent","type":"string"},{"indexed":false,"name":"_level","type":"uint256"}],"name":"OrgSuspensionRevoked","type":"event"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -294,7 +294,7 @@ func (p *PermissionCtrl) monitorQIP714Block() error {
defer stopSubscription.Unsubscribe()
for {
select {
case head := <-chainHeadCh:
case head := <-chainHeadCh:
if p.eth.ChainConfig().IsQIP714(head.Block.Number()) {
types.SetDefaultAccess()
return
@ -653,6 +653,16 @@ func (p *PermissionCtrl) populateInitPermissions() error {
}
}
// start the cache monitoring functions
for _, f := range []func(){
p.populateAccountCache,
p.populateNodeCache,
p.populateOrgCache,
p.populateRoleCache,
} {
f()
}
return nil
}
@ -853,3 +863,120 @@ func (p *PermissionCtrl) manageRolePermissions() error {
}()
return nil
}
// getter to get an account record from the contract
func (p *PermissionCtrl) populateAccountCache() {
permAcctInterface := &pbind.AcctManagerSession{
Contract: p.permAcct,
CallOpts: bind.CallOpts{
Pending: true,
},
}
reqCh, respCh := types.AcctInfoMap.GetAcctCacheChannels()
go func() {
stopChan, stopSubscription := p.subscribeStopEvent()
defer stopSubscription.Unsubscribe()
for {
select {
case acctId := <-reqCh:
account, orgId, roleId, status, isAdmin, _ := permAcctInterface.GetAccountDetails(acctId)
if orgId == "NONE" {
respCh <- nil
}
respCh <- &types.AccountInfo{AcctId: account, OrgId: orgId, RoleId: roleId, Status: types.AcctStatus(status.Int64()), IsOrgAdmin: isAdmin}
case <-stopChan:
return
}
}
}()
}
// getter to get a org record from the contract
func (p *PermissionCtrl) populateOrgCache() {
permOrgInterface := &pbind.OrgManagerSession{
Contract: p.permOrg,
CallOpts: bind.CallOpts{
Pending: true,
},
}
reqCh, respCh := types.OrgInfoMap.GetOrgCacheChannels()
go func() {
stopChan, stopSubscription := p.subscribeStopEvent()
defer stopSubscription.Unsubscribe()
for {
select {
case orgId := <-reqCh:
org, parentOrgId, ultimateParentId, orgLevel, orgStatus, _ := permOrgInterface.GetOrgDetails(orgId)
if ultimateParentId == "" {
respCh <- nil
}
respCh <- &types.OrgInfo{OrgId: org, ParentOrgId: parentOrgId, UltimateParent: ultimateParentId, Status: types.OrgStatus(orgStatus.Int64()), Level: orgLevel}
case <-stopChan:
return
}
}
}()
}
// getter to get a role record from the contract
func (p *PermissionCtrl) populateRoleCache(){
permRoleInterface := &pbind.RoleManagerSession{
Contract: p.permRole,
CallOpts: bind.CallOpts{
Pending: true,
},
}
reqCh, respCh := types.RoleInfoMap.GetRoleCacheChannels()
go func() {
stopChan, stopSubscription := p.subscribeStopEvent()
defer stopSubscription.Unsubscribe()
for {
select {
case roleKey := <-reqCh:
roleDetails, _ := permRoleInterface.GetRoleDetails(roleKey.RoleId, roleKey.OrgId)
if roleDetails.OrgId == "" {
respCh <- nil
}
respCh <- &types.RoleInfo{OrgId: roleDetails.OrgId, RoleId: roleDetails.RoleId, IsVoter: roleDetails.Voter, IsAdmin: roleDetails.Admin, Access: types.AccessType(roleDetails.AccessType.Int64()), Active: roleDetails.Active}
case <-stopChan:
return
}
}
}()
}
// getter to get a node record from the contract
func (p *PermissionCtrl) populateNodeCache() {
permNodeInterface := &pbind.NodeManagerSession{
Contract: p.permNode,
CallOpts: bind.CallOpts{
Pending: true,
},
}
reqCh, respCh := types.NodeInfoMap.GetNodeCacheChannels()
go func(){
stopChan, stopSubscription := p.subscribeStopEvent()
defer stopSubscription.Unsubscribe()
for {
select {
case url := <-reqCh:
nodeDetails, _ := permNodeInterface.GetNodeDetails(url)
if nodeDetails.NodeStatus.Cmp(big.NewInt(0)) == 0 {
respCh <- nil
}
respCh <- &types.NodeInfo{OrgId: nodeDetails.OrgId, Url: nodeDetails.EnodeId, Status: types.NodeStatus(nodeDetails.NodeStatus.Int64())}
case <-stopChan:
return
}
}
}()
}