[#905] morph/client: Fetch NNS hash once on init

NNS contract hash is taken from the contract with ID=1.
Because morph client is expected to work with the same chain,
and because contract hash doesn't change on update, there is no need to
fetch it from each new endpoint.

Change-Id: Ic6dc18283789da076d6a0b3701139b97037714cc
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
Evgenii Stratonikov 2025-03-21 15:40:40 +03:00 committed by Dmitrii Stepanov
parent 30099194ba
commit a4da1da767
3 changed files with 10 additions and 54 deletions

View file

@ -60,6 +60,7 @@ type Client struct {
rpcActor *actor.Actor // neo-go RPC actor rpcActor *actor.Actor // neo-go RPC actor
gasToken *nep17.Token // neo-go GAS token wrapper gasToken *nep17.Token // neo-go GAS token wrapper
rolemgmt *rolemgmt.Contract // neo-go Designation contract wrapper rolemgmt *rolemgmt.Contract // neo-go Designation contract wrapper
nnsHash util.Uint160 // NNS contract hash
acc *wallet.Account // neo account acc *wallet.Account // neo account
accAddr util.Uint160 // account's address accAddr util.Uint160 // account's address
@ -94,27 +95,12 @@ type Client struct {
type cache struct { type cache struct {
m sync.RWMutex m sync.RWMutex
nnsHash *util.Uint160
gKey *keys.PublicKey gKey *keys.PublicKey
txHeights *lru.Cache[util.Uint256, uint32] txHeights *lru.Cache[util.Uint256, uint32]
metrics metrics.MorphCacheMetrics metrics metrics.MorphCacheMetrics
} }
func (c *cache) nns() *util.Uint160 {
c.m.RLock()
defer c.m.RUnlock()
return c.nnsHash
}
func (c *cache) setNNSHash(nnsHash util.Uint160) {
c.m.Lock()
defer c.m.Unlock()
c.nnsHash = &nnsHash
}
func (c *cache) groupKey() *keys.PublicKey { func (c *cache) groupKey() *keys.PublicKey {
c.m.RLock() c.m.RLock()
defer c.m.RUnlock() defer c.m.RUnlock()
@ -133,7 +119,6 @@ func (c *cache) invalidate() {
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
c.nnsHash = nil
c.gKey = nil c.gKey = nil
c.txHeights.Purge() c.txHeights.Purge()
} }

View file

@ -145,6 +145,11 @@ func New(ctx context.Context, key *keys.PrivateKey, opts ...Option) (*Client, er
if cli.client == nil { if cli.client == nil {
return nil, ErrNoHealthyEndpoint return nil, ErrNoHealthyEndpoint
} }
cs, err := cli.client.GetContractStateByID(nnsContractID)
if err != nil {
return nil, fmt.Errorf("resolve nns hash: %w", err)
}
cli.nnsHash = cs.Hash
cli.setActor(act) cli.setActor(act)
go cli.closeWaiter(ctx) go cli.closeWaiter(ctx)

View file

@ -61,11 +61,7 @@ func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) {
return util.Uint160{}, ErrConnectionLost return util.Uint160{}, ErrConnectionLost
} }
nnsHash, err := c.NNSHash() nnsHash := c.NNSHash()
if err != nil {
return util.Uint160{}, err
}
sh, err = nnsResolve(c.client, nnsHash, name) sh, err = nnsResolve(c.client, nnsHash, name)
if err != nil { if err != nil {
return sh, fmt.Errorf("NNS.resolve: %w", err) return sh, fmt.Errorf("NNS.resolve: %w", err)
@ -74,34 +70,8 @@ func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) {
} }
// NNSHash returns NNS contract hash. // NNSHash returns NNS contract hash.
func (c *Client) NNSHash() (util.Uint160, error) { func (c *Client) NNSHash() util.Uint160 {
c.switchLock.RLock() return c.nnsHash
defer c.switchLock.RUnlock()
if c.inactive {
return util.Uint160{}, ErrConnectionLost
}
success := false
startedAt := time.Now()
defer func() {
c.cache.metrics.AddMethodDuration("NNSContractHash", success, time.Since(startedAt))
}()
nnsHash := c.cache.nns()
if nnsHash == nil {
cs, err := c.client.GetContractStateByID(nnsContractID)
if err != nil {
return util.Uint160{}, fmt.Errorf("NNS contract state: %w", err)
}
c.cache.setNNSHash(cs.Hash)
nnsHash = &cs.Hash
}
success = true
return *nnsHash, nil
} }
func nnsResolveItem(c *rpcclient.WSClient, nnsHash util.Uint160, domain string) (stackitem.Item, error) { func nnsResolveItem(c *rpcclient.WSClient, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
@ -241,11 +211,7 @@ func (c *Client) contractGroupKey() (*keys.PublicKey, error) {
return gKey, nil return gKey, nil
} }
nnsHash, err := c.NNSHash() nnsHash := c.NNSHash()
if err != nil {
return nil, err
}
item, err := nnsResolveItem(c.client, nnsHash, NNSGroupKeyName) item, err := nnsResolveItem(c.client, nnsHash, NNSGroupKeyName)
if err != nil { if err != nil {
return nil, err return nil, err