Add mutex to params/config (#8160)

* add mutex to params/config

* split config files into test/prod

* add tags checker

* add regression test

* remove debug info

* update bazel config

* go fmt

* make sure that conditional file is kept by gazelle

* update build tag: test -> develop

* gazelle

* remove redundant import

* update deps.md (per Nishant's suggestion)

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Victor Farazdagi 2021-01-04 12:48:39 -08:00 committed by GitHub
parent 04b2e0776d
commit b54743edbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 28 deletions

View File

@ -67,3 +67,14 @@ bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%prysm_
The deps.bzl file should have been updated with the dependency and any transitive dependencies. The deps.bzl file should have been updated with the dependency and any transitive dependencies.
Do NOT add new `go_repository` to the WORKSPACE file. All dependencies should live in deps.bzl. Do NOT add new `go_repository` to the WORKSPACE file. All dependencies should live in deps.bzl.
## Running tests
To enable conditional compilation and custom configuration for tests (where compiled code has more
debug info, while not being completely optimized), we rely on Go's build tags/constraints mechanism
(see official docs on [build constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints)).
Therefore, whenever using `go test`, do not forget to pass in extra build tag, eg:
```bash
go test ./beacon-chain/sync/initial-sync -tags develop
```

View File

@ -5,6 +5,8 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"config.go", "config.go",
"config_utils_develop.go", # keep
"config_utils_prod.go",
"io_config.go", "io_config.go",
"loader.go", "loader.go",
"mainnet_config.go", "mainnet_config.go",
@ -29,6 +31,7 @@ go_test(
name = "go_default_test", name = "go_default_test",
size = "small", size = "small",
srcs = [ srcs = [
"checktags_test.go",
"config_test.go", "config_test.go",
"loader_test.go", "loader_test.go",
], ],
@ -37,9 +40,12 @@ go_test(
"@eth2_spec_tests_minimal//:test_data", "@eth2_spec_tests_minimal//:test_data",
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
gotags = ["develop"],
race = "on",
deps = [ deps = [
"//shared/testutil/assert:go_default_library", "//shared/testutil/assert:go_default_library",
"//shared/testutil/require:go_default_library", "//shared/testutil/require:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library", "@io_bazel_rules_go//go/tools/bazel:go_default_library",
], ],
) )

View File

@ -0,0 +1,11 @@
// +build !develop
package params
import (
log "github.com/sirupsen/logrus"
)
func init() {
log.Fatal("Tests in this package require extra build tag: re-run with `-tags develop`")
}

View File

@ -3,8 +3,6 @@ package params
import ( import (
"time" "time"
"github.com/mohae/deepcopy"
) )
// BeaconChainConfig contains constant configs for node to participate in beacon chain. // BeaconChainConfig contains constant configs for node to participate in beacon chain.
@ -126,27 +124,3 @@ type BeaconChainConfig struct {
// Weak subjectivity values. // Weak subjectivity values.
SafetyDecay uint64 // SafetyDecay is defined as the loss in the 1/3 consensus safety margin of the casper FFG mechanism. SafetyDecay uint64 // SafetyDecay is defined as the loss in the 1/3 consensus safety margin of the casper FFG mechanism.
} }
var beaconConfig = MainnetConfig()
// BeaconConfig retrieves beacon chain config.
func BeaconConfig() *BeaconChainConfig {
return beaconConfig
}
// OverrideBeaconConfig by replacing the config. The preferred pattern is to
// call BeaconConfig(), change the specific parameters, and then call
// OverrideBeaconConfig(c). Any subsequent calls to params.BeaconConfig() will
// return this new configuration.
func OverrideBeaconConfig(c *BeaconChainConfig) {
beaconConfig = c
}
// Copy returns a copy of the config object.
func (c *BeaconChainConfig) Copy() *BeaconChainConfig {
config, ok := deepcopy.Copy(*c).(BeaconChainConfig)
if !ok {
config = *beaconConfig
}
return &config
}

View File

@ -11,7 +11,7 @@ import (
// to make sure that previous test case has already been completed and check can be run. // to make sure that previous test case has already been completed and check can be run.
var testOverrideBeaconConfigExecuted bool var testOverrideBeaconConfigExecuted bool
func TestOverrideBeaconConfig(t *testing.T) { func TestConfig_OverrideBeaconConfig(t *testing.T) {
// Ensure that param modifications are safe. // Ensure that param modifications are safe.
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig() cfg := params.BeaconConfig()
@ -23,7 +23,7 @@ func TestOverrideBeaconConfig(t *testing.T) {
testOverrideBeaconConfigExecuted = true testOverrideBeaconConfigExecuted = true
} }
func TestOverrideBeaconConfigTestTeardown(t *testing.T) { func TestConfig_OverrideBeaconConfigTestTeardown(t *testing.T) {
if !testOverrideBeaconConfigExecuted { if !testOverrideBeaconConfigExecuted {
t.Skip("State leak can occur only if state mutating test has already completed") t.Skip("State leak can occur only if state mutating test has already completed")
} }
@ -32,3 +32,15 @@ func TestOverrideBeaconConfigTestTeardown(t *testing.T) {
t.Fatal("Parameter update has been leaked out of previous test") t.Fatal("Parameter update has been leaked out of previous test")
} }
} }
func TestConfig_DataRace(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
cfg := params.BeaconConfig()
params.OverrideBeaconConfig(cfg)
}()
go func() uint64 {
return params.BeaconConfig().MaxDeposits
}()
}
}

View File

@ -0,0 +1,40 @@
// +build develop
package params
import (
"sync"
"github.com/mohae/deepcopy"
)
var beaconConfig = MainnetConfig()
var beaconConfigLock sync.RWMutex
// BeaconConfig retrieves beacon chain config.
func BeaconConfig() *BeaconChainConfig {
beaconConfigLock.RLock()
defer beaconConfigLock.RUnlock()
return beaconConfig
}
// OverrideBeaconConfig by replacing the config. The preferred pattern is to
// call BeaconConfig(), change the specific parameters, and then call
// OverrideBeaconConfig(c). Any subsequent calls to params.BeaconConfig() will
// return this new configuration.
func OverrideBeaconConfig(c *BeaconChainConfig) {
beaconConfigLock.Lock()
defer beaconConfigLock.Unlock()
beaconConfig = c
}
// Copy returns a copy of the config object.
func (c *BeaconChainConfig) Copy() *BeaconChainConfig {
beaconConfigLock.RLock()
defer beaconConfigLock.RUnlock()
config, ok := deepcopy.Copy(*c).(BeaconChainConfig)
if !ok {
config = *beaconConfig
}
return &config
}

View File

@ -0,0 +1,31 @@
// +build !develop
package params
import (
"github.com/mohae/deepcopy"
)
var beaconConfig = MainnetConfig()
// BeaconConfig retrieves beacon chain config.
func BeaconConfig() *BeaconChainConfig {
return beaconConfig
}
// OverrideBeaconConfig by replacing the config. The preferred pattern is to
// call BeaconConfig(), change the specific parameters, and then call
// OverrideBeaconConfig(c). Any subsequent calls to params.BeaconConfig() will
// return this new configuration.
func OverrideBeaconConfig(c *BeaconChainConfig) {
beaconConfig = c
}
// Copy returns a copy of the config object.
func (c *BeaconChainConfig) Copy() *BeaconChainConfig {
config, ok := deepcopy.Copy(*c).(BeaconChainConfig)
if !ok {
config = *beaconConfig
}
return &config
}