[#1444] config: Fix data race on morph component init
All checks were successful
Tests and linters / Run gofumpt (pull_request) Successful in 2m12s
DCO action / DCO (pull_request) Successful in 2m55s
Pre-commit hooks / Pre-commit (pull_request) Successful in 3m19s
Tests and linters / Staticcheck (pull_request) Successful in 3m47s
Vulncheck / Vulncheck (pull_request) Successful in 3m55s
Build / Build Components (pull_request) Successful in 4m20s
Tests and linters / Lint (pull_request) Successful in 4m40s
Tests and linters / gopls check (pull_request) Successful in 4m57s
Tests and linters / Tests (pull_request) Successful in 6m10s
Tests and linters / Tests with -race (pull_request) Successful in 7m0s

It could be called for every shard on metabase resync concurrently and
it is possible to get state with initialized client but not initialized
contract hashes.

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
Dmitrii Stepanov 2024-10-23 10:39:19 +03:00
parent 8b6ec57c61
commit e515dd4582
Signed by: dstepanov-yadro
GPG key ID: 237AF1A763293BC0
4 changed files with 13 additions and 11 deletions

View file

@ -13,9 +13,7 @@ import (
) )
func initAccountingService(ctx context.Context, c *cfg) { func initAccountingService(ctx context.Context, c *cfg) {
if c.cfgMorph.client == nil { c.initMorphComponents(ctx)
initMorphComponents(ctx, c)
}
balanceMorphWrapper, err := balance.NewFromMorph(c.cfgMorph.client, c.cfgAccounting.scriptHash, 0) balanceMorphWrapper, err := balance.NewFromMorph(c.cfgMorph.client, c.cfgAccounting.scriptHash, 0)
fatalOnErr(err) fatalOnErr(err)

View file

@ -575,6 +575,9 @@ func (c *cfgGRPC) dropConnection(endpoint string) {
} }
type cfgMorph struct { type cfgMorph struct {
initialized bool
guard sync.Mutex
client *client.Client client *client.Client
notaryEnabled bool notaryEnabled bool
@ -1455,10 +1458,7 @@ func (c *cfg) createTombstoneSource() *tombstone.ExpirationChecker {
func (c *cfg) createContainerInfoProvider(ctx context.Context) container.InfoProvider { func (c *cfg) createContainerInfoProvider(ctx context.Context) container.InfoProvider {
return container.NewInfoProvider(func() (container.Source, error) { return container.NewInfoProvider(func() (container.Source, error) {
// threadsafe: called on init or on sighup when morph initialized c.initMorphComponents(ctx)
if c.cfgMorph.client == nil {
initMorphComponents(ctx, c)
}
cc, err := containerClient.NewFromMorph(c.cfgMorph.client, c.cfgContainer.scriptHash, 0, containerClient.TryNotary()) cc, err := containerClient.NewFromMorph(c.cfgMorph.client, c.cfgContainer.scriptHash, 0, containerClient.TryNotary())
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -28,7 +28,12 @@ const (
notaryDepositRetriesAmount = 300 notaryDepositRetriesAmount = 300
) )
func initMorphComponents(ctx context.Context, c *cfg) { func (c *cfg) initMorphComponents(ctx context.Context) {
c.cfgMorph.guard.Lock()
defer c.cfgMorph.guard.Unlock()
if c.cfgMorph.initialized {
return
}
initMorphClient(ctx, c) initMorphClient(ctx, c)
lookupScriptHashesInNNS(c) // smart contract auto negotiation lookupScriptHashesInNNS(c) // smart contract auto negotiation
@ -70,6 +75,7 @@ func initMorphComponents(ctx context.Context, c *cfg) {
c.netMapSource = netmapSource c.netMapSource = netmapSource
c.cfgNetmap.wrapper = wrap c.cfgNetmap.wrapper = wrap
c.cfgMorph.initialized = true
} }
func initMorphClient(ctx context.Context, c *cfg) { func initMorphClient(ctx context.Context, c *cfg) {

View file

@ -143,9 +143,7 @@ func initNetmapService(ctx context.Context, c *cfg) {
parseAttributes(c) parseAttributes(c)
c.cfgNodeInfo.localInfo.SetStatus(netmapSDK.Offline) c.cfgNodeInfo.localInfo.SetStatus(netmapSDK.Offline)
if c.cfgMorph.client == nil { c.initMorphComponents(ctx)
initMorphComponents(ctx, c)
}
initNetmapState(c) initNetmapState(c)