Skip to content

Commit

Permalink
feat: SET-431 remove contract key lookup and lru cache
Browse files Browse the repository at this point in the history
  • Loading branch information
rodion-lim-partior committed Mar 11, 2024
1 parent 04dde76 commit 3bf9f34
Show file tree
Hide file tree
Showing 40 changed files with 777 additions and 514 deletions.
2 changes: 1 addition & 1 deletion core/state_transition_pmh.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (pmh *privateMessageHandler) verify(vmerr error) (bool, error) {
log.Trace("Verify hashes of affected contracts", "expectedHashes", pmh.receivedPrivacyMetadata.ACHashes, "numberOfAffectedAddresses", len(actualACAddresses))
privacyFlag := pmh.receivedPrivacyMetadata.PrivacyFlag
for _, addr := range actualACAddresses {
if core.ContractWhitelistMap != nil && core.ContractWhitelistMap.IsContractWhitelisted(addr) {
if core.ContractWhitelistMap != nil && core.ContractWhitelistMap.GetContractWhitelistByAddress(addr) {
// introduce a whitelist to allow whitelisting of contracts for EP simulation skips
continue
}
Expand Down
18 changes: 3 additions & 15 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -1004,12 +1004,6 @@ web3._extend({
params: 3,
inputFormatter: [null, web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'getContractWhitelistByKey',
call: 'quorumPermission_getContractWhitelistByKey',
params: 1,
inputFormatter: [null]
}),
new web3._extend.Method({
name: 'getContractWhitelistByAddress',
call: 'quorumPermission_getContractWhitelistByAddress',
Expand All @@ -1019,20 +1013,14 @@ web3._extend({
new web3._extend.Method({
name: 'addContractWhitelist',
call: 'quorumPermission_addContractWhitelist',
params: 3,
inputFormatter: [null,web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'revokeContractWhitelistByAddress',
call: 'quorumPermission_revokeContractWhitelistByAddress',
params: 2,
inputFormatter: [web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'revokeContractWhitelistByKey',
call: 'quorumPermission_revokeContractWhitelistByKey',
name: 'revokeContractWhitelist',
call: 'quorumPermission_revokeContractWhitelist',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
inputFormatter: [web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'addNewRole',
Expand Down
17 changes: 8 additions & 9 deletions params/quorum.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package params

const (
PERMISSIONED_CONFIG = "permissioned-nodes.json"
DISALLOWED_CONFIG = "disallowed-nodes.json"
PERMISSION_MODEL_CONFIG = "permission-config.json"
DEFAULT_ORGCACHE_SIZE = 2000
DEFAULT_ROLECACHE_SIZE = 2500
DEFAULT_NODECACHE_SIZE = 1000
DEFAULT_ACCOUNTCACHE_SIZE = 6000
DEFAULT_WHITELISTCACHE_SIZE = 6000
NODE_NAME_LENGTH = 32
PERMISSIONED_CONFIG = "permissioned-nodes.json"
DISALLOWED_CONFIG = "disallowed-nodes.json"
PERMISSION_MODEL_CONFIG = "permission-config.json"
DEFAULT_ORGCACHE_SIZE = 2000
DEFAULT_ROLECACHE_SIZE = 2500
DEFAULT_NODECACHE_SIZE = 1000
DEFAULT_ACCOUNTCACHE_SIZE = 6000
NODE_NAME_LENGTH = 32
)
35 changes: 7 additions & 28 deletions permission/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,11 @@ func (q *QuorumControlsAPI) AcctList() []core.AccountInfo {
return core.AcctInfoMap.GetAcctList()
}

func (q *QuorumControlsAPI) ContractWhitelist() []core.ContractWhitelistInfo {
func (q *QuorumControlsAPI) ContractWhitelist() []common.Address {
return core.ContractWhitelistMap.GetContractWhitelist()
}

func (q *QuorumControlsAPI) GetContractWhitelistByKey(contractKey string) core.ContractWhitelistInfo {
return core.ContractWhitelistMap.GetContractWhitelistByKey(contractKey)
}

func (q *QuorumControlsAPI) GetContractWhitelistByAddress(contractAddress common.Address) core.ContractWhitelistInfo {
func (q *QuorumControlsAPI) GetContractWhitelistByAddress(contractAddress common.Address) bool {
return core.ContractWhitelistMap.GetContractWhitelistByAddress(contractAddress)
}

Expand Down Expand Up @@ -344,12 +340,12 @@ func (q *QuorumControlsAPI) AddNewRole(orgId string, roleId string, access uint8
return actionSuccess, nil
}

func (q *QuorumControlsAPI) AddContractWhitelist(contractKey string, contractAddress common.Address, txa ethapi.SendTxArgs) (string, error) {
func (q *QuorumControlsAPI) AddContractWhitelist(contractAddress common.Address, txa ethapi.SendTxArgs) (string, error) {
contractWhitelistService, err := q.permCtrl.NewPermissionContractWhitelistService(txa)
if err != nil {
return "", err
}
args := ptype.TxArgs{ContractKey: contractKey, ContractAddress: contractAddress, Txa: txa}
args := ptype.TxArgs{ContractAddress: contractAddress, Txa: txa}
if err := q.valAddContractWhitelist(args); err != nil {
return "", err
}
Expand All @@ -361,7 +357,7 @@ func (q *QuorumControlsAPI) AddContractWhitelist(contractKey string, contractAdd
return actionSuccess, nil
}

func (q *QuorumControlsAPI) RevokeContractWhitelistByAddress(contractAddress common.Address, txa ethapi.SendTxArgs) (string, error) {
func (q *QuorumControlsAPI) RevokeContractWhitelist(contractAddress common.Address, txa ethapi.SendTxArgs) (string, error) {
contractWhitelistService, err := q.permCtrl.NewPermissionContractWhitelistService(txa)
if err != nil {
return "", err
Expand All @@ -378,23 +374,6 @@ func (q *QuorumControlsAPI) RevokeContractWhitelistByAddress(contractAddress com
return actionSuccess, nil
}

func (q *QuorumControlsAPI) RevokeContractWhitelistByKey(contractAddress common.Address, txa ethapi.SendTxArgs) (string, error) {
contractWhitelistService, err := q.permCtrl.NewPermissionContractWhitelistService(txa)
if err != nil {
return "", err
}
args := ptype.TxArgs{ContractAddress: contractAddress, Txa: txa}
if err := q.valRevokeContractWhitelist(args); err != nil {
return "", err
}
tx, err := contractWhitelistService.RevokeWhitelistByKey(args)
if err != nil {
return reportExecError(RevokeContractWhitelist, err)
}
log.Debug("executed permission action", "action", RevokeContractWhitelist, "tx", tx)
return actionSuccess, nil
}

func (q *QuorumControlsAPI) RemoveRole(orgId string, roleId string, txa ethapi.SendTxArgs) (string, error) {
roleService, err := q.permCtrl.NewPermissionRoleService(txa)
if err != nil {
Expand Down Expand Up @@ -1021,7 +1000,7 @@ func (q *QuorumControlsAPI) valApproveAdminRole(args ptype.TxArgs) error {
}

func (q *QuorumControlsAPI) valAddContractWhitelist(args ptype.TxArgs) error {
if args.ContractKey == "" || args.ContractAddress == (common.Address{}) {
if args.ContractAddress == (common.Address{}) {
return ptype.ErrInvalidInput
}
// check if caller is network admin
Expand All @@ -1032,7 +1011,7 @@ func (q *QuorumControlsAPI) valAddContractWhitelist(args ptype.TxArgs) error {
}

func (q *QuorumControlsAPI) valRevokeContractWhitelist(args ptype.TxArgs) error {
if args.ContractKey == "" && args.ContractAddress == (common.Address{}) {
if args.ContractAddress == (common.Address{}) {
return ptype.ErrInvalidInput
}
// check if caller is network admin
Expand Down
69 changes: 17 additions & 52 deletions permission/core/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math/big"
"reflect"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -131,12 +132,6 @@ type OrgDetailInfo struct {
SubOrgList []string `json:"subOrgList"`
}

type ContractWhitelistInfo struct {
ContractAddress common.Address `json:"address"`
ContractKey string `json:"key"`
ContractWhitelistStatus uint8 `json:"status"`
}

var syncStarted = false
var defaultAccess = FullAccess
var qip714BlockReached = false
Expand Down Expand Up @@ -255,23 +250,12 @@ func NewAcctCache(cacheSize int) *AcctCache {
}

type ContractWhitelistCache struct {
c *lru.Cache // address to contractWhitelistInfo
c2 *lru.Cache // key to contractWhitelistInfo
evicted bool
populateCacheFunc func(key string, account common.Address) (*ContractWhitelistInfo, error)
}

func (a *ContractWhitelistCache) PopulateCacheFunc(cf func(string, common.Address) (*ContractWhitelistInfo, error)) {
a.populateCacheFunc = cf
c map[common.Address]bool // address to bool
}

func NewContractWhitelistCache(cacheSize int) *ContractWhitelistCache {
contractWhitelistCache := ContractWhitelistCache{evicted: false}
onEvictedFunc := func(k interface{}, v interface{}) {
contractWhitelistCache.evicted = true
}
contractWhitelistCache.c, _ = lru.NewWithEvict(cacheSize, onEvictedFunc)
contractWhitelistCache.c2, _ = lru.NewWithEvict(cacheSize, onEvictedFunc)
func NewContractWhitelistCache() *ContractWhitelistCache {
// we don't use a lru here since the entire whitelist should always be in memory
contractWhitelistCache := ContractWhitelistCache{c: make(map[common.Address]bool)}
return &contractWhitelistCache
}

Expand Down Expand Up @@ -622,44 +606,25 @@ func CheckIfAdminAccount(acctId common.Address) bool {
return false
}

func (c *ContractWhitelistCache) UpsertContractWhitelist(contract common.Address, key string) {
c.c.Add(contract, &ContractWhitelistInfo{contract, key, 0})
c.c2.Add(key, &ContractWhitelistInfo{contract, key, 0})
}

func (c *ContractWhitelistCache) RemoveContractWhitelist(contract common.Address, key string) {
c.c.Remove(contract)
c.c2.Remove(key)
}

func (c *ContractWhitelistCache) GetContractWhitelist() []ContractWhitelistInfo {
clist := make([]ContractWhitelistInfo, len(c.c.Keys()))
for i, k := range c.c.Keys() {
v, _ := c.c.Get(k)
vp := v.(*ContractWhitelistInfo)
clist[i] = *vp
func (c *ContractWhitelistCache) GetContractWhitelist() []common.Address {
keysReflect := reflect.ValueOf(c.c).MapKeys()
keys := make([]common.Address, len(keysReflect))
for i, v := range keysReflect {
keys[i] = v.Interface().(common.Address)
}
return clist
return keys
}

func (c *ContractWhitelistCache) GetContractWhitelistByKey(contractKey string) ContractWhitelistInfo {
v, _ := c.c2.Get(contractKey)
return *v.(*ContractWhitelistInfo)
func (c *ContractWhitelistCache) AddContractWhitelist(contract common.Address) {
c.c[contract] = true
}

func (c *ContractWhitelistCache) GetContractWhitelistByAddress(contractAddress common.Address) ContractWhitelistInfo {
v, _ := c.c.Get(contractAddress)
return *v.(*ContractWhitelistInfo)
func (c *ContractWhitelistCache) RemoveContractWhitelist(contract common.Address) {
delete(c.c, contract)
}

func (c *ContractWhitelistCache) IsContractWhitelisted(contractAddress common.Address) bool {
v, ok := c.c.Get(contractAddress)
if ok {
if v.(*ContractWhitelistInfo).ContractWhitelistStatus != 1 {
// 0 is inactive, 2 means contract whitelist was revoked
return false
}
}
func (c *ContractWhitelistCache) GetContractWhitelistByAddress(contractAddress common.Address) bool {
_, ok := c.c[contractAddress]
return ok
}

Expand Down
1 change: 0 additions & 1 deletion permission/core/types/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ type Backend interface {
ManageRolePermissions() error
// monitors contract whitelist management related events and updates cache accordingly
ManageContractWhitelistPermissions() error

// monitors for network boot up complete event
MonitorNetworkBootUp() error
}
Expand Down
5 changes: 1 addition & 4 deletions permission/core/types/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type TxArgs struct {
AcctId common.Address
AccessType uint8
Action uint8
ContractKey string
ContractAddress common.Address
Txa ethapi.SendTxArgs
}
Expand All @@ -40,7 +39,6 @@ type ContractBackend struct {
type ContractWhitelistService interface {
AddWhitelist(_args TxArgs) (*types.Transaction, error)
RevokeWhitelistByAddress(_args TxArgs) (*types.Transaction, error)
RevokeWhitelistByKey(_args TxArgs) (*types.Transaction, error)
}

type RoleService interface {
Expand Down Expand Up @@ -100,8 +98,7 @@ type InitService interface {
GetNumberOfAccounts() (*big.Int, error)
GetAccountDetails(_account common.Address) (common.Address, string, string, *big.Int, bool, error)

GetContractWhitelistDetailsFromIndex(_cIndex *big.Int) (common.Address, string, *big.Int, error)
GetNumberOfWhitelistedContracts() (*big.Int, error)
GetWhitelistedContracts() ([]common.Address, error)

GetRoleDetailsFromIndex(_rIndex *big.Int) (struct {
RoleId string
Expand Down
27 changes: 8 additions & 19 deletions permission/permission.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (p *PermissionCtrl) AfterStart() error {

// populate the initial list of permissioned nodes, account accesses and contract whitelist
if err := p.populateInitPermissions(params.DEFAULT_ORGCACHE_SIZE, params.DEFAULT_ROLECACHE_SIZE,
params.DEFAULT_NODECACHE_SIZE, params.DEFAULT_ACCOUNTCACHE_SIZE, params.DEFAULT_WHITELISTCACHE_SIZE); err != nil {
params.DEFAULT_NODECACHE_SIZE, params.DEFAULT_ACCOUNTCACHE_SIZE); err != nil {
return fmt.Errorf("populateInitPermissions failed: %v", err)
}

Expand Down Expand Up @@ -140,7 +140,7 @@ func (p *PermissionCtrl) monitorQIP714Block() error {
return nil
}

func (p *PermissionCtrl) instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize, contractWhitelistCacheSize int) {
func (p *PermissionCtrl) instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize int) {
// instantiate the cache objects for permissions
pcore.OrgInfoMap = pcore.NewOrgCache(orgCacheSize)
pcore.OrgInfoMap.PopulateCacheFunc(p.populateOrgToCache)
Expand All @@ -155,14 +155,13 @@ func (p *PermissionCtrl) instantiateCache(orgCacheSize, roleCacheSize, nodeCache
pcore.AcctInfoMap = pcore.NewAcctCache(accountCacheSize)
pcore.AcctInfoMap.PopulateCacheFunc(p.populateAccountToCache)

pcore.ContractWhitelistMap = pcore.NewContractWhitelistCache(contractWhitelistCacheSize)
pcore.ContractWhitelistMap.PopulateCacheFunc(p.populateContractWhitelistToCache)
pcore.ContractWhitelistMap = pcore.NewContractWhitelistCache()
}

// Thus function checks if the initial network boot up status and if no
// populates permissions model with details from permission-config.json
func (p *PermissionCtrl) populateInitPermissions(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize, contractWhitelistCacheSize int) error {
p.instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize, contractWhitelistCacheSize)
func (p *PermissionCtrl) populateInitPermissions(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize int) error {
p.instantiateCache(orgCacheSize, roleCacheSize, nodeCacheSize, accountCacheSize)
networkInitialized, err := p.contract.GetNetworkBootStatus()
if err != nil {
// handle the scenario of no contract code.
Expand Down Expand Up @@ -240,14 +239,9 @@ func (p *PermissionCtrl) populateAccountsFromContract() error {

// populates the contract whitelist details from contract into cache
func (p *PermissionCtrl) populateContractWhitelistFromContract() error {
if numberOfWhitelistedContracts, err := p.contract.GetNumberOfWhitelistedContracts(); err == nil {
iContract := numberOfWhitelistedContracts.Uint64()
for k := uint64(0); k < iContract; k++ {
if addr, key, status, err := p.contract.GetContractWhitelistDetailsFromIndex(big.NewInt(int64(k))); err == nil {
if status.Cmp(big.NewInt(1)) == 0 {
pcore.ContractWhitelistMap.UpsertContractWhitelist(addr, key)
}
}
if whitelistedContracts, err := p.contract.GetWhitelistedContracts(); err == nil {
for _, addr := range whitelistedContracts {
pcore.ContractWhitelistMap.AddContractWhitelist(addr)
}
} else {
return err
Expand Down Expand Up @@ -352,11 +346,6 @@ func (p *PermissionCtrl) populateAccountToCache(acctId common.Address) (*pcore.A
return &pcore.AccountInfo{AcctId: account, OrgId: orgId, RoleId: roleId, Status: pcore.AcctStatus(status.Int64()), IsOrgAdmin: isAdmin}, nil
}

// getter to get a whitelist address from the contract
func (p *PermissionCtrl) populateContractWhitelistToCache(contractKey string, contractAddress common.Address) (*pcore.ContractWhitelistInfo, error) {
return &pcore.ContractWhitelistInfo{ContractAddress: contractAddress, ContractKey: contractKey}, nil
}

// getter to get a org record from the contract
func (p *PermissionCtrl) populateOrgToCache(orgId string) (*pcore.OrgInfo, error) {
org, parentOrgId, ultimateParentId, orgLevel, orgStatus, err := p.contract.GetOrgDetails(orgId)
Expand Down

0 comments on commit 3bf9f34

Please sign in to comment.