github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/permission/permission.go (about) 1 package permission 2 3 import ( 4 "fmt" 5 "math/big" 6 "sync" 7 "time" 8 9 "github.com/kisexp/xdchain/common" 10 "github.com/kisexp/xdchain/core" 11 "github.com/kisexp/xdchain/eth" 12 "github.com/kisexp/xdchain/ethclient" 13 "github.com/kisexp/xdchain/log" 14 "github.com/kisexp/xdchain/p2p/enode" 15 "github.com/kisexp/xdchain/params" 16 pcore "github.com/kisexp/xdchain/permission/core" 17 ptype "github.com/kisexp/xdchain/permission/core/types" 18 ) 19 20 // This is to make sure all contract instances are ready and initialized 21 // 22 // Required to be call after standard service start lifecycle 23 func (p *PermissionCtrl) AfterStart() error { 24 log.Debug("permission service: binding contracts") 25 err := <-p.errorChan // capture any error happened during asyncStart. Also wait here if asyncStart is not yet finish 26 if err != nil { 27 return err 28 } 29 if err = p.contract.BindContracts(); err != nil { 30 return fmt.Errorf("populateInitPermissions failed to bind contracts: %v", err) 31 } 32 33 // populate the initial list of permissioned nodes and account accesses 34 if err := p.populateInitPermissions(params.DEFAULT_ORGCACHE_SIZE, params.DEFAULT_ROLECACHE_SIZE, 35 params.DEFAULT_NODECACHE_SIZE, params.DEFAULT_ACCOUNTCACHE_SIZE); err != nil { 36 return fmt.Errorf("populateInitPermissions failed: %v", err) 37 } 38 39 // set the function point for transaction allowed check 40 pcore.PermissionTransactionAllowedFunc = p.IsTransactionAllowed 41 setPermissionService(p) 42 43 // set the default access to ReadOnly 44 pcore.SetDefaults(p.permConfig.NwAdminRole, p.permConfig.OrgAdminRole, p.IsV2Permission()) 45 for _, f := range []func() error{ 46 p.monitorQIP714Block, // monitor block number to activate new permissions controls 47 p.backend.ManageOrgPermissions, // monitor org management related events 48 p.backend.ManageNodePermissions, // monitor org level Node management events 49 p.backend.ManageRolePermissions, // monitor org level role management events 50 p.backend.ManageAccountPermissions, // monitor org level account management events 51 } { 52 if err := f(); err != nil { 53 return err 54 } 55 } 56 57 log.Info("permission service: is now ready") 58 59 return nil 60 } 61 62 // start service asynchronously due to dependencies 63 func (p *PermissionCtrl) asyncStart() { 64 var ethereum *eth.Ethereum 65 // will be blocked here until Node is up 66 if err := p.node.Lifecycle(ðereum); err != nil { 67 p.errorChan <- fmt.Errorf("dependent ethereum service not started") 68 return 69 } 70 defer func() { 71 p.errorChan <- nil 72 }() 73 // for cases where the node is joining an existing network, permission service 74 // can be brought up only after block syncing is complete. This function 75 // waits for block syncing before the starting permissions 76 p.startWaitGroup.Add(1) 77 go func(_wg *sync.WaitGroup) { 78 log.Debug("permission service: waiting for downloader") 79 stopChan, stopSubscription := ptype.SubscribeStopEvent() 80 pollingTicker := time.NewTicker(10 * time.Millisecond) 81 defer func(start time.Time) { 82 log.Debug("permission service: downloader completed", "took", time.Since(start)) 83 stopSubscription.Unsubscribe() 84 pollingTicker.Stop() 85 _wg.Done() 86 }(time.Now()) 87 for { 88 select { 89 case <-pollingTicker.C: 90 if pcore.GetSyncStatus() && !ethereum.Downloader().Synchronising() { 91 return 92 } 93 case <-stopChan: 94 return 95 } 96 } 97 }(p.startWaitGroup) // wait for downloader to sync if any 98 99 log.Debug("permission service: waiting for all dependencies to be ready") 100 p.startWaitGroup.Wait() 101 client, err := p.node.Attach() 102 if err != nil { 103 p.errorChan <- fmt.Errorf("unable to create rpc client: %v", err) 104 return 105 } 106 p.ethClnt = ethclient.NewClient(client) 107 p.eth = ethereum 108 p.isRaft = p.eth.BlockChain().Config().Istanbul == nil && p.eth.BlockChain().Config().Clique == nil 109 p.updateBackEnd() 110 } 111 112 // monitors QIP714Block and set default access 113 func (p *PermissionCtrl) monitorQIP714Block() error { 114 // if QIP714block is not given, set the default access 115 // to readonly 116 if p.eth.BlockChain().Config().QIP714Block == nil || p.eth.BlockChain().Config().IsQIP714(p.eth.BlockChain().CurrentBlock().Number()) { 117 pcore.SetQIP714BlockReached() 118 return nil 119 } 120 //QIP714block is given, monitor block count 121 go func() { 122 chainHeadCh := make(chan core.ChainHeadEvent, 1) 123 headSub := p.eth.BlockChain().SubscribeChainHeadEvent(chainHeadCh) 124 defer headSub.Unsubscribe() 125 stopChan, stopSubscription := ptype.SubscribeStopEvent() 126 defer stopSubscription.Unsubscribe() 127 for { 128 select { 129 case head := <-chainHeadCh: 130 if p.eth.BlockChain().Config().IsQIP714(head.Block.Number()) { 131 pcore.SetQIP714BlockReached() 132 return 133 } 134 case <-stopChan: 135 return 136 } 137 } 138 }() 139 return nil 140 } 141 142 func (p *PermissionCtrl) instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize int) { 143 // instantiate the cache objects for permissions 144 pcore.OrgInfoMap = pcore.NewOrgCache(orgCacheSize) 145 pcore.OrgInfoMap.PopulateCacheFunc(p.populateOrgToCache) 146 147 pcore.RoleInfoMap = pcore.NewRoleCache(roleCacheSize) 148 pcore.RoleInfoMap.PopulateCacheFunc(p.populateRoleToCache) 149 150 pcore.NodeInfoMap = pcore.NewNodeCache(nodeCacheSize) 151 pcore.NodeInfoMap.PopulateCacheFunc(p.populateNodeCache) 152 pcore.NodeInfoMap.PopulateValidateFunc(p.populateNodeCacheAndValidate) 153 154 pcore.AcctInfoMap = pcore.NewAcctCache(accountCacheSize) 155 pcore.AcctInfoMap.PopulateCacheFunc(p.populateAccountToCache) 156 } 157 158 // Thus function checks if the initial network boot up status and if no 159 // populates permissions model with details from permission-config.json 160 func (p *PermissionCtrl) populateInitPermissions(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize int) error { 161 p.instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize) 162 networkInitialized, err := p.contract.GetNetworkBootStatus() 163 if err != nil { 164 // handle the scenario of no contract code. 165 log.Warn("Failed to retrieve network boot status ", "err", err) 166 return err 167 } 168 169 if !networkInitialized { 170 p.backend.MonitorNetworkBootUp() 171 if err := p.bootupNetwork(); err != nil { 172 return err 173 } 174 } else { 175 //populate orgs, nodes, roles and accounts from contract 176 for _, f := range []func() error{ 177 p.populateOrgsFromContract, 178 p.populateNodesFromContract, 179 p.populateRolesFromContract, 180 p.populateAccountsFromContract, 181 } { 182 if err := f(); err != nil { 183 return err 184 } 185 } 186 pcore.SetNetworkBootUpCompleted() 187 } 188 return nil 189 } 190 191 // initialize the permissions model and populate initial values 192 func (p *PermissionCtrl) bootupNetwork() error { 193 if _, err := p.contract.SetPolicy(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, p.permConfig.OrgAdminRole); err != nil { 194 log.Error("bootupNetwork SetPolicy failed", "err", err) 195 return err 196 } 197 if _, err := p.contract.Init(p.permConfig.SubOrgBreadth, p.permConfig.SubOrgDepth); err != nil { 198 log.Error("bootupNetwork init failed", "err", err) 199 return err 200 } 201 202 pcore.OrgInfoMap.UpsertOrg(p.permConfig.NwAdminOrg, "", p.permConfig.NwAdminOrg, big.NewInt(1), pcore.OrgApproved) 203 pcore.RoleInfoMap.UpsertRole(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, true, true, pcore.FullAccess, true) 204 // populate the initial Node list from static-nodes.json 205 if err := p.populateStaticNodesToContract(); err != nil { 206 return err 207 } 208 // populate initial account access to full access 209 if err := p.populateInitAccountAccess(); err != nil { 210 return err 211 } 212 213 // update network status to boot completed 214 if err := p.updateNetworkStatus(); err != nil { 215 log.Error("failed to updated network boot status", "error", err) 216 return err 217 } 218 return nil 219 } 220 221 // populates the account access details from contract into cache 222 func (p *PermissionCtrl) populateAccountsFromContract() error { 223 if numberOfRoles, err := p.contract.GetNumberOfAccounts(); err == nil { 224 iOrgNum := numberOfRoles.Uint64() 225 for k := uint64(0); k < iOrgNum; k++ { 226 if addr, org, role, status, orgAdmin, err := p.contract.GetAccountDetailsFromIndex(big.NewInt(int64(k))); err == nil { 227 pcore.AcctInfoMap.UpsertAccount(org, role, addr, orgAdmin, pcore.AcctStatus(int(status.Int64()))) 228 } 229 } 230 } else { 231 return err 232 } 233 return nil 234 } 235 236 // populates the role details from contract into cache 237 func (p *PermissionCtrl) populateRolesFromContract() error { 238 if numberOfRoles, err := p.contract.GetNumberOfRoles(); err == nil { 239 iOrgNum := numberOfRoles.Uint64() 240 for k := uint64(0); k < iOrgNum; k++ { 241 if roleStruct, err := p.contract.GetRoleDetailsFromIndex(big.NewInt(int64(k))); err == nil { 242 pcore.RoleInfoMap.UpsertRole(roleStruct.OrgId, roleStruct.RoleId, roleStruct.Voter, roleStruct.Admin, pcore.AccessType(int(roleStruct.AccessType.Int64())), roleStruct.Active) 243 } 244 } 245 246 } else { 247 return err 248 } 249 return nil 250 } 251 252 // populates the Node details from contract into cache 253 func (p *PermissionCtrl) populateNodesFromContract() error { 254 if numberOfNodes, err := p.contract.GetNumberOfNodes(); err == nil { 255 iOrgNum := numberOfNodes.Uint64() 256 for k := uint64(0); k < iOrgNum; k++ { 257 if orgId, url, status, err := p.contract.GetNodeDetailsFromIndex(big.NewInt(int64(k))); err == nil { 258 pcore.NodeInfoMap.UpsertNode(orgId, url, pcore.NodeStatus(int(status.Int64()))) 259 } 260 } 261 } else { 262 return err 263 } 264 return nil 265 } 266 267 // populates the org details from contract into cache 268 func (p *PermissionCtrl) populateOrgsFromContract() error { 269 270 if numberOfOrgs, err := p.contract.GetNumberOfOrgs(); err == nil { 271 iOrgNum := numberOfOrgs.Uint64() 272 for k := uint64(0); k < iOrgNum; k++ { 273 if orgId, porgId, ultParent, level, status, err := p.contract.GetOrgInfo(big.NewInt(int64(k))); err == nil { 274 pcore.OrgInfoMap.UpsertOrg(orgId, porgId, ultParent, level, pcore.OrgStatus(int(status.Int64()))) 275 } 276 } 277 } else { 278 return err 279 } 280 return nil 281 } 282 283 // Reads the node list from static-nodes.json and populates into the contract 284 func (p *PermissionCtrl) populateStaticNodesToContract() error { 285 nodes := p.node.Server().Config.StaticNodes 286 for _, node := range nodes { 287 url := pcore.GetNodeUrl(node.EnodeID(), node.IP().String(), uint16(node.TCP()), uint16(node.RaftPort()), p.isRaft) 288 _, err := p.contract.AddAdminNode(url) 289 if err != nil { 290 log.Warn("Failed to propose node", "err", err, "enode", node.EnodeID()) 291 return err 292 } 293 pcore.NodeInfoMap.UpsertNode(p.permConfig.NwAdminOrg, url, 2) 294 } 295 return nil 296 } 297 298 // Invokes the initAccounts function of smart contract to set the initial 299 // set of accounts access to full access 300 func (p *PermissionCtrl) populateInitAccountAccess() error { 301 for _, a := range p.permConfig.Accounts { 302 _, er := p.contract.AddAdminAccount(a) 303 if er != nil { 304 log.Warn("Error adding permission initial account list", "err", er, "account", a) 305 return er 306 } 307 pcore.AcctInfoMap.UpsertAccount(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, a, true, 2) 308 } 309 return nil 310 } 311 312 // updates network boot status to true 313 func (p *PermissionCtrl) updateNetworkStatus() error { 314 _, err := p.contract.UpdateNetworkBootStatus() 315 if err != nil { 316 log.Warn("Failed to udpate network boot status ", "err", err) 317 return err 318 } 319 return nil 320 } 321 322 // getter to get an account record from the contract 323 func (p *PermissionCtrl) populateAccountToCache(acctId common.Address) (*pcore.AccountInfo, error) { 324 account, orgId, roleId, status, isAdmin, err := p.contract.GetAccountDetails(acctId) 325 if err != nil { 326 return nil, err 327 } 328 329 if status.Int64() == 0 { 330 return nil, ptype.ErrAccountNotThere 331 } 332 return &pcore.AccountInfo{AcctId: account, OrgId: orgId, RoleId: roleId, Status: pcore.AcctStatus(status.Int64()), IsOrgAdmin: isAdmin}, nil 333 } 334 335 // getter to get a org record from the contract 336 func (p *PermissionCtrl) populateOrgToCache(orgId string) (*pcore.OrgInfo, error) { 337 org, parentOrgId, ultimateParentId, orgLevel, orgStatus, err := p.contract.GetOrgDetails(orgId) 338 if err != nil { 339 return nil, err 340 } 341 if orgStatus.Int64() == 0 { 342 return nil, ptype.ErrOrgDoesNotExists 343 } 344 orgInfo := pcore.OrgInfo{OrgId: org, ParentOrgId: parentOrgId, UltimateParent: ultimateParentId, Status: pcore.OrgStatus(orgStatus.Int64()), Level: orgLevel} 345 // now need to build the list of sub orgs for this org 346 subOrgIndexes, err := p.contract.GetSubOrgIndexes(orgId) 347 if err != nil { 348 return nil, err 349 } 350 351 if len(subOrgIndexes) == 0 { 352 return &orgInfo, nil 353 } 354 355 // range through the sub org indexes and get the org ids to populate the suborg list 356 for _, s := range subOrgIndexes { 357 subOrgId, _, _, _, _, err := p.contract.GetOrgInfo(s) 358 359 if err != nil { 360 return nil, err 361 } 362 orgInfo.SubOrgList = append(orgInfo.SubOrgList, orgId+"."+subOrgId) 363 364 } 365 return &orgInfo, nil 366 } 367 368 // getter to get a role record from the contract 369 func (p *PermissionCtrl) populateRoleToCache(roleKey *pcore.RoleKey) (*pcore.RoleInfo, error) { 370 roleDetails, err := p.contract.GetRoleDetails(roleKey.RoleId, roleKey.OrgId) 371 372 if err != nil { 373 return nil, err 374 } 375 376 if roleDetails.OrgId == "" { 377 return nil, ptype.ErrInvalidRole 378 } 379 return &pcore.RoleInfo{OrgId: roleDetails.OrgId, RoleId: roleDetails.RoleId, IsVoter: roleDetails.Voter, IsAdmin: roleDetails.Admin, Access: pcore.AccessType(roleDetails.AccessType.Int64()), Active: roleDetails.Active}, nil 380 } 381 382 // getter to get a role record from the contract 383 func (p *PermissionCtrl) populateNodeCache(url string) (*pcore.NodeInfo, error) { 384 orgId, url, status, err := p.contract.GetNodeDetails(url) 385 if err != nil { 386 return nil, err 387 } 388 389 if status.Int64() == 0 { 390 return nil, ptype.ErrNodeDoesNotExists 391 } 392 return &pcore.NodeInfo{OrgId: orgId, Url: url, Status: pcore.NodeStatus(status.Int64())}, nil 393 } 394 395 // getter to get a Node record from the contract 396 func (p *PermissionCtrl) populateNodeCacheAndValidate(hexNodeId, ultimateParentId string) bool { 397 txnAllowed := false 398 passedEnode, _ := enode.ParseV4(hexNodeId) 399 if numberOfNodes, err := p.contract.GetNumberOfNodes(); err == nil { 400 numNodes := numberOfNodes.Uint64() 401 for k := uint64(0); k < numNodes; k++ { 402 if orgId, url, status, err := p.contract.GetNodeDetailsFromIndex(big.NewInt(int64(k))); err == nil { 403 if orgRec, err := pcore.OrgInfoMap.GetOrg(orgId); err != nil { 404 if orgRec.UltimateParent == ultimateParentId { 405 recEnode, _ := enode.ParseV4(url) 406 if recEnode.ID() == passedEnode.ID() { 407 txnAllowed = true 408 pcore.NodeInfoMap.UpsertNode(orgId, url, pcore.NodeStatus(int(status.Int64()))) 409 } 410 } 411 } 412 } 413 } 414 } 415 return txnAllowed 416 }