From 138ce145dcd0144597dee5d7e22593d4f79cf1dc Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 15 May 2024 14:51:20 -0400 Subject: [PATCH 1/5] Fix pebbledb memory corruption (#3020) --- database/pebble/batch.go | 24 ++++++++---------------- database/pebble/batch_test.go | 2 +- database/pebble/db.go | 22 ++++++---------------- database/pebble/db_test.go | 2 +- database/pebble/iterator.go | 17 +++++++++++------ 5 files changed, 27 insertions(+), 40 deletions(-) diff --git a/database/pebble/batch.go b/database/pebble/batch.go index a53b962dc7be..8778a9473960 100644 --- a/database/pebble/batch.go +++ b/database/pebble/batch.go @@ -56,26 +56,18 @@ func (b *batch) Write() error { return database.ErrClosed } - if !b.written { - // This batch has not been written to the database yet. - if err := updateError(b.batch.Commit(pebble.Sync)); err != nil { + if b.written { + // pebble doesn't support writing a batch twice so we have to clone the + // batch before writing it. + newBatch := b.db.pebbleDB.NewBatch() + if err := newBatch.Apply(b.batch, nil); err != nil { return err } - b.written = true - return nil + b.batch = newBatch } - // pebble doesn't support writing a batch twice so we have to clone - // [b] and commit the clone. - batchClone := b.db.pebbleDB.NewBatch() - - // Copy the batch. - if err := batchClone.Apply(b.batch, nil); err != nil { - return err - } - - // Commit the new batch. - return updateError(batchClone.Commit(pebble.Sync)) + b.written = true + return updateError(b.batch.Commit(pebble.Sync)) } func (b *batch) Reset() { diff --git a/database/pebble/batch_test.go b/database/pebble/batch_test.go index 3d657a874fd3..4fcc537d1e84 100644 --- a/database/pebble/batch_test.go +++ b/database/pebble/batch_test.go @@ -17,7 +17,7 @@ func TestBatch(t *testing.T) { require := require.New(t) dirName := t.TempDir() - db, err := New(dirName, DefaultConfigBytes, logging.NoLog{}, "", prometheus.NewRegistry()) + db, err := New(dirName, nil, logging.NoLog{}, "", prometheus.NewRegistry()) require.NoError(err) batchIntf := db.NewBatch() diff --git a/database/pebble/db.go b/database/pebble/db.go index 77259a217d87..8e99e0690b64 100644 --- a/database/pebble/db.go +++ b/database/pebble/db.go @@ -4,7 +4,6 @@ package pebble import ( - "bytes" "context" "encoding/json" "errors" @@ -44,18 +43,8 @@ var ( MaxOpenFiles: 4096, MaxConcurrentCompactions: 1, } - - DefaultConfigBytes []byte ) -func init() { - var err error - DefaultConfigBytes, err = json.Marshal(DefaultConfig) - if err != nil { - panic(err) - } -} - type Database struct { lock sync.RWMutex pebbleDB *pebble.DB @@ -200,9 +189,10 @@ func (db *Database) Compact(start []byte, end []byte) error { } if end == nil { - // The database.Database spec treats a nil [limit] as a key after all keys - // but pebble treats a nil [limit] as a key before all keys in Compact. - // Use the greatest key in the database as the [limit] to get the desired behavior. + // The database.Database spec treats a nil [limit] as a key after all + // keys but pebble treats a nil [limit] as a key before all keys in + // Compact. Use the greatest key in the database as the [limit] to get + // the desired behavior. it := db.pebbleDB.NewIter(&pebble.IterOptions{}) if !it.Last() { @@ -210,7 +200,7 @@ func (db *Database) Compact(start []byte, end []byte) error { return it.Close() } - end = it.Key() + end = slices.Clone(it.Key()) if err := it.Close(); err != nil { return err } @@ -273,7 +263,7 @@ func keyRange(start, prefix []byte) *pebble.IterOptions { LowerBound: prefix, UpperBound: prefixToUpperBound(prefix), } - if bytes.Compare(start, prefix) == 1 { + if pebble.DefaultComparer.Compare(start, prefix) == 1 { opt.LowerBound = start } return opt diff --git a/database/pebble/db_test.go b/database/pebble/db_test.go index ec6dd3e0fa2d..3b37d9362d92 100644 --- a/database/pebble/db_test.go +++ b/database/pebble/db_test.go @@ -16,7 +16,7 @@ import ( func newDB(t testing.TB) *Database { folder := t.TempDir() - db, err := New(folder, DefaultConfigBytes, logging.NoLog{}, "pebble", prometheus.NewRegistry()) + db, err := New(folder, nil, logging.NoLog{}, "pebble", prometheus.NewRegistry()) require.NoError(t, err) return db.(*Database) } diff --git a/database/pebble/iterator.go b/database/pebble/iterator.go index ab7d8aad11a3..40654dc41d98 100644 --- a/database/pebble/iterator.go +++ b/database/pebble/iterator.go @@ -17,7 +17,7 @@ import ( var ( _ database.Iterator = (*iter)(nil) - errCouldntGetValue = errors.New("couldnt get iterator value") + errCouldNotGetValue = errors.New("could not get iterator value") ) type iter struct { @@ -63,16 +63,16 @@ func (it *iter) Next() bool { return false } - it.nextKey = it.iter.Key() - - var err error - it.nextVal, err = it.iter.ValueAndErr() + key := it.iter.Key() + value, err := it.iter.ValueAndErr() if err != nil { it.hasNext = false - it.err = fmt.Errorf("%w: %w", errCouldntGetValue, err) + it.err = fmt.Errorf("%w: %w", errCouldNotGetValue, err) return false } + it.nextKey = key + it.nextVal = value return true } @@ -122,6 +122,11 @@ func (it *iter) release() { return } + // Cloning these values ensures that calling it.Key() or it.Value() after + // releasing the iterator will not segfault. + it.nextKey = slices.Clone(it.nextKey) + it.nextVal = slices.Clone(it.nextVal) + // Remove the iterator from the list of open iterators. it.db.openIterators.Remove(it) From 0928176698a743af837ec040b011231872821acc Mon Sep 17 00:00:00 2001 From: Tsachi Herman <24438559+tsachiherman@users.noreply.github.com> Date: Thu, 16 May 2024 15:12:24 -0400 Subject: [PATCH 2/5] [vms/avm] fix linter error in benchmark : Use of weak random number generator (#3023) --- config/config_test.go | 8 ++- config/keys.go | 110 +++++++++++++++++---------------- vms/avm/vm_benchmark_test.go | 10 +-- vms/platformvm/service_test.go | 5 +- 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index 820796714b72..68847ca4f6d5 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -22,6 +22,8 @@ import ( "github.com/ava-labs/avalanchego/subnets" ) +const chainConfigFilenameExtention = ".ex" + func TestGetChainConfigsFromFiles(t *testing.T) { tests := map[string]struct { configs map[string]string @@ -72,11 +74,11 @@ func TestGetChainConfigsFromFiles(t *testing.T) { // Create custom configs for key, value := range test.configs { chainDir := filepath.Join(chainsDir, key) - setupFile(t, chainDir, chainConfigFileName+".ex", value) //nolint:goconst + setupFile(t, chainDir, chainConfigFileName+chainConfigFilenameExtention, value) } for key, value := range test.upgrades { chainDir := filepath.Join(chainsDir, key) - setupFile(t, chainDir, chainUpgradeFileName+".ex", value) + setupFile(t, chainDir, chainUpgradeFileName+chainConfigFilenameExtention, value) } v := setupViper(configFile) @@ -161,7 +163,7 @@ func TestSetChainConfigDefaultDir(t *testing.T) { require.Equal(defaultChainConfigDir, v.GetString(ChainConfigDirKey)) chainsDir := filepath.Join(defaultChainConfigDir, "C") - setupFile(t, chainsDir, chainConfigFileName+".ex", "helloworld") + setupFile(t, chainsDir, chainConfigFileName+chainConfigFilenameExtention, "helloworld") chainConfigs, err := getChainConfigs(v) require.NoError(err) expected := map[string]chains.ChainConfig{"C": {Config: []byte("helloworld"), Upgrade: []byte(nil)}} diff --git a/config/keys.go b/config/keys.go index 560b08774fa7..25348ae54c8d 100644 --- a/config/keys.go +++ b/config/keys.go @@ -3,60 +3,64 @@ package config -// #nosec G101 +// the HTTPWriteTimeoutKey was moved here so that it would not generate the +// false-positive linter error "G101: Potential hardcoded credentials" when running golangci-lint. +const HTTPWriteTimeoutKey = "http-write-timeout" // #nosec G101 + const ( - DataDirKey = "data-dir" - ConfigFileKey = "config-file" - ConfigContentKey = "config-file-content" - ConfigContentTypeKey = "config-file-content-type" - VersionKey = "version" - GenesisFileKey = "genesis-file" - GenesisFileContentKey = "genesis-file-content" - NetworkNameKey = "network-id" - ACPSupportKey = "acp-support" - ACPObjectKey = "acp-object" - TxFeeKey = "tx-fee" - CreateAssetTxFeeKey = "create-asset-tx-fee" - CreateSubnetTxFeeKey = "create-subnet-tx-fee" - TransformSubnetTxFeeKey = "transform-subnet-tx-fee" - CreateBlockchainTxFeeKey = "create-blockchain-tx-fee" - AddPrimaryNetworkValidatorFeeKey = "add-primary-network-validator-fee" - AddPrimaryNetworkDelegatorFeeKey = "add-primary-network-delegator-fee" - AddSubnetValidatorFeeKey = "add-subnet-validator-fee" - AddSubnetDelegatorFeeKey = "add-subnet-delegator-fee" - UptimeRequirementKey = "uptime-requirement" - MinValidatorStakeKey = "min-validator-stake" - MaxValidatorStakeKey = "max-validator-stake" - MinDelegatorStakeKey = "min-delegator-stake" - MinDelegatorFeeKey = "min-delegation-fee" - MinStakeDurationKey = "min-stake-duration" - MaxStakeDurationKey = "max-stake-duration" - StakeMaxConsumptionRateKey = "stake-max-consumption-rate" - StakeMinConsumptionRateKey = "stake-min-consumption-rate" - StakeMintingPeriodKey = "stake-minting-period" - StakeSupplyCapKey = "stake-supply-cap" - DBTypeKey = "db-type" - DBReadOnlyKey = "db-read-only" - DBPathKey = "db-dir" - DBConfigFileKey = "db-config-file" - DBConfigContentKey = "db-config-file-content" - PublicIPKey = "public-ip" - PublicIPResolutionFreqKey = "public-ip-resolution-frequency" - PublicIPResolutionServiceKey = "public-ip-resolution-service" - HTTPHostKey = "http-host" - HTTPPortKey = "http-port" - HTTPSEnabledKey = "http-tls-enabled" - HTTPSKeyFileKey = "http-tls-key-file" - HTTPSKeyContentKey = "http-tls-key-file-content" - HTTPSCertFileKey = "http-tls-cert-file" - HTTPSCertContentKey = "http-tls-cert-file-content" - HTTPAllowedOrigins = "http-allowed-origins" - HTTPAllowedHostsKey = "http-allowed-hosts" - HTTPShutdownTimeoutKey = "http-shutdown-timeout" - HTTPShutdownWaitKey = "http-shutdown-wait" - HTTPReadTimeoutKey = "http-read-timeout" - HTTPReadHeaderTimeoutKey = "http-read-header-timeout" - HTTPWriteTimeoutKey = "http-write-timeout" + DataDirKey = "data-dir" + ConfigFileKey = "config-file" + ConfigContentKey = "config-file-content" + ConfigContentTypeKey = "config-file-content-type" + VersionKey = "version" + GenesisFileKey = "genesis-file" + GenesisFileContentKey = "genesis-file-content" + NetworkNameKey = "network-id" + ACPSupportKey = "acp-support" + ACPObjectKey = "acp-object" + TxFeeKey = "tx-fee" + CreateAssetTxFeeKey = "create-asset-tx-fee" + CreateSubnetTxFeeKey = "create-subnet-tx-fee" + TransformSubnetTxFeeKey = "transform-subnet-tx-fee" + CreateBlockchainTxFeeKey = "create-blockchain-tx-fee" + AddPrimaryNetworkValidatorFeeKey = "add-primary-network-validator-fee" + AddPrimaryNetworkDelegatorFeeKey = "add-primary-network-delegator-fee" + AddSubnetValidatorFeeKey = "add-subnet-validator-fee" + AddSubnetDelegatorFeeKey = "add-subnet-delegator-fee" + UptimeRequirementKey = "uptime-requirement" + MinValidatorStakeKey = "min-validator-stake" + MaxValidatorStakeKey = "max-validator-stake" + MinDelegatorStakeKey = "min-delegator-stake" + MinDelegatorFeeKey = "min-delegation-fee" + MinStakeDurationKey = "min-stake-duration" + MaxStakeDurationKey = "max-stake-duration" + StakeMaxConsumptionRateKey = "stake-max-consumption-rate" + StakeMinConsumptionRateKey = "stake-min-consumption-rate" + StakeMintingPeriodKey = "stake-minting-period" + StakeSupplyCapKey = "stake-supply-cap" + DBTypeKey = "db-type" + DBReadOnlyKey = "db-read-only" + DBPathKey = "db-dir" + DBConfigFileKey = "db-config-file" + DBConfigContentKey = "db-config-file-content" + PublicIPKey = "public-ip" + PublicIPResolutionFreqKey = "public-ip-resolution-frequency" + PublicIPResolutionServiceKey = "public-ip-resolution-service" + HTTPHostKey = "http-host" + HTTPPortKey = "http-port" + HTTPSEnabledKey = "http-tls-enabled" + HTTPSKeyFileKey = "http-tls-key-file" + HTTPSKeyContentKey = "http-tls-key-file-content" + HTTPSCertFileKey = "http-tls-cert-file" + HTTPSCertContentKey = "http-tls-cert-file-content" + + HTTPAllowedOrigins = "http-allowed-origins" + HTTPAllowedHostsKey = "http-allowed-hosts" + HTTPShutdownTimeoutKey = "http-shutdown-timeout" + HTTPShutdownWaitKey = "http-shutdown-wait" + HTTPReadTimeoutKey = "http-read-timeout" + HTTPReadHeaderTimeoutKey = "http-read-header-timeout" + HTTPIdleTimeoutKey = "http-idle-timeout" StateSyncIPsKey = "state-sync-ips" StateSyncIDsKey = "state-sync-ids" diff --git a/vms/avm/vm_benchmark_test.go b/vms/avm/vm_benchmark_test.go index 5befa7062dda..e0bb3080c4e1 100644 --- a/vms/avm/vm_benchmark_test.go +++ b/vms/avm/vm_benchmark_test.go @@ -65,7 +65,7 @@ func BenchmarkLoadUser(b *testing.B) { } // GetAllUTXOsBenchmark is a helper func to benchmark the GetAllUTXOs depending on the size -func GetAllUTXOsBenchmark(b *testing.B, utxoCount int) { +func getAllUTXOsBenchmark(b *testing.B, utxoCount int, randSrc rand.Source) { require := require.New(b) env := setup(b, &envConfig{fork: latest}) @@ -76,12 +76,11 @@ func GetAllUTXOsBenchmark(b *testing.B, utxoCount int) { addr := ids.GenerateTestShortID() - // #nosec G404 for i := 0; i < utxoCount; i++ { utxo := &avax.UTXO{ UTXOID: avax.UTXOID{ TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), + OutputIndex: uint32(randSrc.Int63()), }, Asset: avax.Asset{ID: env.vm.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ @@ -129,9 +128,10 @@ func BenchmarkGetUTXOs(b *testing.B) { }, } - for _, count := range tests { + for testIdx, count := range tests { + randSrc := rand.NewSource(int64(testIdx)) b.Run(count.name, func(b *testing.B) { - GetAllUTXOsBenchmark(b, count.utxoCount) + getAllUTXOsBenchmark(b, count.utxoCount, randSrc) }) } } diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go index 8f39770548b8..e44e603ce53d 100644 --- a/vms/platformvm/service_test.go +++ b/vms/platformvm/service_test.go @@ -130,11 +130,12 @@ func TestGetTxStatus(t *testing.T) { sm := m.NewSharedMemory(service.vm.ctx.ChainID) peerSharedMemory := m.NewSharedMemory(service.vm.ctx.XChainID) - // #nosec G404 + randSrc := rand.NewSource(0) + utxo := &avax.UTXO{ UTXOID: avax.UTXOID{ TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), + OutputIndex: uint32(randSrc.Int63()), }, Asset: avax.Asset{ID: service.vm.ctx.AVAXAssetID}, Out: &secp256k1fx.TransferOutput{ From ddd6d25379e207c81832eae0778d1946a8a1d66c Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Fri, 17 May 2024 19:14:49 -0400 Subject: [PATCH 3/5] Simplify sampler interface (#3026) --- network/ip_tracker.go | 4 +-- network/p2p/validators.go | 4 +-- network/peer/set.go | 4 +-- .../consensus/snowman/bootstrapper/sampler.go | 10 ++++-- snow/validators/manager_test.go | 3 +- snow/validators/set.go | 7 ++-- snow/validators/set_test.go | 3 +- utils/sampler/uniform.go | 6 ++-- utils/sampler/uniform_best.go | 2 +- utils/sampler/uniform_replacer.go | 16 +++++----- utils/sampler/uniform_resample.go | 16 +++++----- utils/sampler/uniform_test.go | 32 +++++++++---------- utils/sampler/weighted.go | 6 +--- utils/sampler/weighted_array.go | 6 ++-- utils/sampler/weighted_best.go | 2 +- utils/sampler/weighted_heap.go | 6 ++-- utils/sampler/weighted_linear.go | 6 ++-- utils/sampler/weighted_test.go | 16 +++++----- utils/sampler/weighted_uniform.go | 6 ++-- utils/sampler/weighted_without_replacement.go | 2 +- .../weighted_without_replacement_generic.go | 17 +++++----- .../weighted_without_replacement_test.go | 24 +++++++------- vms/avm/environment_test.go | 4 +-- vms/proposervm/proposer/windower.go | 18 +++++------ 24 files changed, 110 insertions(+), 110 deletions(-) diff --git a/network/ip_tracker.go b/network/ip_tracker.go index 8bca76d7d755..03040b15337e 100644 --- a/network/ip_tracker.go +++ b/network/ip_tracker.go @@ -400,8 +400,8 @@ func (i *ipTracker) GetGossipableIPs( uniform.Initialize(uint64(len(i.gossipableIPs))) for len(ips) < maxNumIPs { - index, err := uniform.Next() - if err != nil { + index, hasNext := uniform.Next() + if !hasNext { return ips } diff --git a/network/p2p/validators.go b/network/p2p/validators.go index 2dee314feb47..161d84d88372 100644 --- a/network/p2p/validators.go +++ b/network/p2p/validators.go @@ -125,8 +125,8 @@ func (v *Validators) Sample(ctx context.Context, limit int) []ids.NodeID { uniform.Initialize(uint64(len(v.validatorList))) for len(sampled) < limit { - i, err := uniform.Next() - if err != nil { + i, hasNext := uniform.Next() + if !hasNext { break } diff --git a/network/peer/set.go b/network/peer/set.go index cbb9675ec305..a90ffc4e56a9 100644 --- a/network/peer/set.go +++ b/network/peer/set.go @@ -124,8 +124,8 @@ func (s *peerSet) Sample(n int, precondition func(Peer) bool) []Peer { peers := make([]Peer, 0, n) for len(peers) < n { - index, err := sampler.Next() - if err != nil { + index, hasNext := sampler.Next() + if !hasNext { // We have run out of peers to attempt to sample. break } diff --git a/snow/consensus/snowman/bootstrapper/sampler.go b/snow/consensus/snowman/bootstrapper/sampler.go index b43f6d915745..56b27d3076ff 100644 --- a/snow/consensus/snowman/bootstrapper/sampler.go +++ b/snow/consensus/snowman/bootstrapper/sampler.go @@ -4,11 +4,15 @@ package bootstrapper import ( + "errors" + "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/sampler" "github.com/ava-labs/avalanchego/utils/set" ) +var errUnexpectedSamplerFailure = errors.New("unexpected sampler failure") + // Sample keys from [elements] uniformly by weight without replacement. The // returned set will have size less than or equal to [maxSize]. This function // will error if the sum of all weights overflows. @@ -36,9 +40,9 @@ func Sample[T comparable](elements map[T]uint64, maxSize int) (set.Set[T], error } maxSize = int(min(uint64(maxSize), totalWeight)) - indices, err := sampler.Sample(maxSize) - if err != nil { - return nil, err + indices, ok := sampler.Sample(maxSize) + if !ok { + return nil, errUnexpectedSamplerFailure } sampledElements := set.NewSet[T](maxSize) diff --git a/snow/validators/manager_test.go b/snow/validators/manager_test.go index cf23d49d39be..365d7ffdf7d7 100644 --- a/snow/validators/manager_test.go +++ b/snow/validators/manager_test.go @@ -11,7 +11,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/utils/sampler" "github.com/ava-labs/avalanchego/utils/set" safemath "github.com/ava-labs/avalanchego/utils/math" @@ -396,7 +395,7 @@ func TestSample(t *testing.T) { require.Equal([]ids.NodeID{nodeID0}, sampled) _, err = m.Sample(subnetID, 2) - require.ErrorIs(err, sampler.ErrOutOfRange) + require.ErrorIs(err, errInsufficientWeight) nodeID1 := ids.GenerateTestNodeID() require.NoError(m.AddStaker(subnetID, nodeID1, nil, ids.Empty, math.MaxInt64-1)) diff --git a/snow/validators/set.go b/snow/validators/set.go index e9bb235f995b..b0c7e5de9ba6 100644 --- a/snow/validators/set.go +++ b/snow/validators/set.go @@ -23,6 +23,7 @@ var ( errDuplicateValidator = errors.New("duplicate validator") errMissingValidator = errors.New("missing validator") errTotalWeightNotUint64 = errors.New("total weight is not a uint64") + errInsufficientWeight = errors.New("insufficient weight") ) // newSet returns a new, empty set of validators. @@ -257,9 +258,9 @@ func (s *vdrSet) sample(size int) ([]ids.NodeID, error) { s.samplerInitialized = true } - indices, err := s.sampler.Sample(size) - if err != nil { - return nil, err + indices, ok := s.sampler.Sample(size) + if !ok { + return nil, errInsufficientWeight } list := make([]ids.NodeID, size) diff --git a/snow/validators/set_test.go b/snow/validators/set_test.go index 480f9dba4f8e..086e5c0b654a 100644 --- a/snow/validators/set_test.go +++ b/snow/validators/set_test.go @@ -11,7 +11,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/bls" - "github.com/ava-labs/avalanchego/utils/sampler" "github.com/ava-labs/avalanchego/utils/set" safemath "github.com/ava-labs/avalanchego/utils/math" @@ -343,7 +342,7 @@ func TestSetSample(t *testing.T) { require.Equal([]ids.NodeID{nodeID0}, sampled) _, err = s.Sample(2) - require.ErrorIs(err, sampler.ErrOutOfRange) + require.ErrorIs(err, errInsufficientWeight) nodeID1 := ids.GenerateTestNodeID() require.NoError(s.Add(nodeID1, nil, ids.Empty, math.MaxInt64-1)) diff --git a/utils/sampler/uniform.go b/utils/sampler/uniform.go index 5ae9a21d8822..5cdf20bc5125 100644 --- a/utils/sampler/uniform.go +++ b/utils/sampler/uniform.go @@ -7,12 +7,12 @@ package sampler type Uniform interface { Initialize(sampleRange uint64) // Sample returns length numbers in the range [0,sampleRange). If there - // aren't enough numbers in the range, an error is returned. If length is + // aren't enough numbers in the range, false is returned. If length is // negative the implementation may panic. - Sample(length int) ([]uint64, error) + Sample(length int) ([]uint64, bool) + Next() (uint64, bool) Reset() - Next() (uint64, error) } // NewUniform returns a new sampler diff --git a/utils/sampler/uniform_best.go b/utils/sampler/uniform_best.go index 21f7870d5bdc..fda2579558f6 100644 --- a/utils/sampler/uniform_best.go +++ b/utils/sampler/uniform_best.go @@ -56,7 +56,7 @@ samplerLoop: start := s.clock.Time() for i := 0; i < s.benchmarkIterations; i++ { - if _, err := sampler.Sample(sampleSize); err != nil { + if _, ok := sampler.Sample(sampleSize); !ok { continue samplerLoop } } diff --git a/utils/sampler/uniform_replacer.go b/utils/sampler/uniform_replacer.go index 80666a238343..9d6f47c2d4d3 100644 --- a/utils/sampler/uniform_replacer.go +++ b/utils/sampler/uniform_replacer.go @@ -36,18 +36,18 @@ func (s *uniformReplacer) Initialize(length uint64) { s.drawsCount = 0 } -func (s *uniformReplacer) Sample(count int) ([]uint64, error) { +func (s *uniformReplacer) Sample(count int) ([]uint64, bool) { s.Reset() results := make([]uint64, count) for i := 0; i < count; i++ { - ret, err := s.Next() - if err != nil { - return nil, err + ret, hasNext := s.Next() + if !hasNext { + return nil, false } results[i] = ret } - return results, nil + return results, true } func (s *uniformReplacer) Reset() { @@ -55,9 +55,9 @@ func (s *uniformReplacer) Reset() { s.drawsCount = 0 } -func (s *uniformReplacer) Next() (uint64, error) { +func (s *uniformReplacer) Next() (uint64, bool) { if s.drawsCount >= s.length { - return 0, ErrOutOfRange + return 0, false } draw := s.rng.Uint64Inclusive(s.length-1-s.drawsCount) + s.drawsCount @@ -65,5 +65,5 @@ func (s *uniformReplacer) Next() (uint64, error) { s.drawn[draw] = s.drawn.get(s.drawsCount, s.drawsCount) s.drawsCount++ - return ret, nil + return ret, true } diff --git a/utils/sampler/uniform_resample.go b/utils/sampler/uniform_resample.go index b05ce62fe886..4325d759b1c0 100644 --- a/utils/sampler/uniform_resample.go +++ b/utils/sampler/uniform_resample.go @@ -23,28 +23,28 @@ func (s *uniformResample) Initialize(length uint64) { s.drawn = make(map[uint64]struct{}) } -func (s *uniformResample) Sample(count int) ([]uint64, error) { +func (s *uniformResample) Sample(count int) ([]uint64, bool) { s.Reset() results := make([]uint64, count) for i := 0; i < count; i++ { - ret, err := s.Next() - if err != nil { - return nil, err + ret, hasNext := s.Next() + if !hasNext { + return nil, false } results[i] = ret } - return results, nil + return results, true } func (s *uniformResample) Reset() { clear(s.drawn) } -func (s *uniformResample) Next() (uint64, error) { +func (s *uniformResample) Next() (uint64, bool) { i := uint64(len(s.drawn)) if i >= s.length { - return 0, ErrOutOfRange + return 0, false } for { @@ -53,6 +53,6 @@ func (s *uniformResample) Next() (uint64, error) { continue } s.drawn[draw] = struct{}{} - return draw, nil + return draw, true } } diff --git a/utils/sampler/uniform_test.go b/utils/sampler/uniform_test.go index eb9862e7656c..99334464b2d5 100644 --- a/utils/sampler/uniform_test.go +++ b/utils/sampler/uniform_test.go @@ -83,8 +83,8 @@ func UniformInitializeMaxUint64Test(t *testing.T, s Uniform) { s.Initialize(math.MaxUint64) for { - val, err := s.Next() - require.NoError(t, err) + val, hasNext := s.Next() + require.True(t, hasNext) if val > math.MaxInt64 { break @@ -95,8 +95,8 @@ func UniformInitializeMaxUint64Test(t *testing.T, s Uniform) { func UniformOutOfRangeTest(t *testing.T, s Uniform) { s.Initialize(0) - _, err := s.Sample(1) - require.ErrorIs(t, err, ErrOutOfRange) + _, ok := s.Sample(1) + require.False(t, ok) } func UniformEmptyTest(t *testing.T, s Uniform) { @@ -104,8 +104,8 @@ func UniformEmptyTest(t *testing.T, s Uniform) { s.Initialize(1) - val, err := s.Sample(0) - require.NoError(err) + val, ok := s.Sample(0) + require.True(ok) require.Empty(val) } @@ -114,8 +114,8 @@ func UniformSingletonTest(t *testing.T, s Uniform) { s.Initialize(1) - val, err := s.Sample(1) - require.NoError(err) + val, ok := s.Sample(1) + require.True(ok) require.Equal([]uint64{0}, val) } @@ -124,8 +124,8 @@ func UniformDistributionTest(t *testing.T, s Uniform) { s.Initialize(3) - val, err := s.Sample(3) - require.NoError(err) + val, ok := s.Sample(3) + require.True(ok) slices.Sort(val) require.Equal([]uint64{0, 1, 2}, val) @@ -134,8 +134,8 @@ func UniformDistributionTest(t *testing.T, s Uniform) { func UniformOverSampleTest(t *testing.T, s Uniform) { s.Initialize(3) - _, err := s.Sample(4) - require.ErrorIs(t, err, ErrOutOfRange) + _, ok := s.Sample(4) + require.False(t, ok) } func UniformLazilySample(t *testing.T, s Uniform) { @@ -146,15 +146,15 @@ func UniformLazilySample(t *testing.T, s Uniform) { for j := 0; j < 2; j++ { sampled := map[uint64]bool{} for i := 0; i < 3; i++ { - val, err := s.Next() - require.NoError(err) + val, hasNext := s.Next() + require.True(hasNext) require.False(sampled[val]) sampled[val] = true } - _, err := s.Next() - require.ErrorIs(err, ErrOutOfRange) + _, hasNext := s.Next() + require.False(hasNext) s.Reset() } diff --git a/utils/sampler/weighted.go b/utils/sampler/weighted.go index 2296da08e97a..64a6493ff860 100644 --- a/utils/sampler/weighted.go +++ b/utils/sampler/weighted.go @@ -3,15 +3,11 @@ package sampler -import "errors" - -var ErrOutOfRange = errors.New("out of range") - // Weighted defines how to sample a specified valued based on a provided // weighted distribution type Weighted interface { Initialize(weights []uint64) error - Sample(sampleValue uint64) (int, error) + Sample(sampleValue uint64) (int, bool) } // NewWeighted returns a new sampler diff --git a/utils/sampler/weighted_array.go b/utils/sampler/weighted_array.go index bbbf98914d68..faae08c0ccbf 100644 --- a/utils/sampler/weighted_array.go +++ b/utils/sampler/weighted_array.go @@ -81,9 +81,9 @@ func (s *weightedArray) Initialize(weights []uint64) error { return nil } -func (s *weightedArray) Sample(value uint64) (int, error) { +func (s *weightedArray) Sample(value uint64) (int, bool) { if len(s.arr) == 0 || s.arr[len(s.arr)-1].cumulativeWeight <= value { - return 0, ErrOutOfRange + return 0, false } minIndex := 0 maxIndex := len(s.arr) - 1 @@ -98,7 +98,7 @@ func (s *weightedArray) Sample(value uint64) (int, error) { currentElem := s.arr[index] currentWeight := currentElem.cumulativeWeight if previousWeight <= value && value < currentWeight { - return currentElem.index, nil + return currentElem.index, true } if value < previousWeight { diff --git a/utils/sampler/weighted_best.go b/utils/sampler/weighted_best.go index 59bf60019144..91ec2ae50135 100644 --- a/utils/sampler/weighted_best.go +++ b/utils/sampler/weighted_best.go @@ -60,7 +60,7 @@ samplerLoop: start := s.clock.Time() for _, sample := range samples { - if _, err := sampler.Sample(sample); err != nil { + if _, ok := sampler.Sample(sample); !ok { continue samplerLoop } } diff --git a/utils/sampler/weighted_heap.go b/utils/sampler/weighted_heap.go index f4002a857e4a..96971657c569 100644 --- a/utils/sampler/weighted_heap.go +++ b/utils/sampler/weighted_heap.go @@ -80,9 +80,9 @@ func (s *weightedHeap) Initialize(weights []uint64) error { return nil } -func (s *weightedHeap) Sample(value uint64) (int, error) { +func (s *weightedHeap) Sample(value uint64) (int, bool) { if len(s.heap) == 0 || s.heap[0].cumulativeWeight <= value { - return 0, ErrOutOfRange + return 0, false } index := 0 @@ -90,7 +90,7 @@ func (s *weightedHeap) Sample(value uint64) (int, error) { currentElement := s.heap[index] currentWeight := currentElement.weight if value < currentWeight { - return currentElement.index, nil + return currentElement.index, true } value -= currentWeight diff --git a/utils/sampler/weighted_linear.go b/utils/sampler/weighted_linear.go index d6f0c5d74fba..c66bd442ab55 100644 --- a/utils/sampler/weighted_linear.go +++ b/utils/sampler/weighted_linear.go @@ -68,15 +68,15 @@ func (s *weightedLinear) Initialize(weights []uint64) error { return nil } -func (s *weightedLinear) Sample(value uint64) (int, error) { +func (s *weightedLinear) Sample(value uint64) (int, bool) { if len(s.arr) == 0 || s.arr[len(s.arr)-1].cumulativeWeight <= value { - return 0, ErrOutOfRange + return 0, false } index := 0 for { if elem := s.arr[index]; value < elem.cumulativeWeight { - return elem.index, nil + return elem.index, true } index++ } diff --git a/utils/sampler/weighted_test.go b/utils/sampler/weighted_test.go index ea08230d175a..286b7f4823a6 100644 --- a/utils/sampler/weighted_test.go +++ b/utils/sampler/weighted_test.go @@ -97,8 +97,8 @@ func WeightedOutOfRangeTest(t *testing.T, s Weighted) { require.NoError(s.Initialize([]uint64{1})) - _, err := s.Sample(1) - require.ErrorIs(err, ErrOutOfRange) + _, ok := s.Sample(1) + require.False(ok) } func WeightedSingletonTest(t *testing.T, s Weighted) { @@ -106,8 +106,8 @@ func WeightedSingletonTest(t *testing.T, s Weighted) { require.NoError(s.Initialize([]uint64{1})) - index, err := s.Sample(0) - require.NoError(err) + index, ok := s.Sample(0) + require.True(ok) require.Zero(index) } @@ -116,8 +116,8 @@ func WeightedWithZeroTest(t *testing.T, s Weighted) { require.NoError(s.Initialize([]uint64{0, 1})) - index, err := s.Sample(0) - require.NoError(err) + index, ok := s.Sample(0) + require.True(ok) require.Equal(1, index) } @@ -128,8 +128,8 @@ func WeightedDistributionTest(t *testing.T, s Weighted) { counts := make([]int, 5) for i := uint64(0); i < 11; i++ { - index, err := s.Sample(i) - require.NoError(err) + index, ok := s.Sample(i) + require.True(ok) counts[index]++ } require.Equal([]int{1, 1, 2, 3, 4}, counts) diff --git a/utils/sampler/weighted_uniform.go b/utils/sampler/weighted_uniform.go index 22dbb6b5ebd5..44836450b3b8 100644 --- a/utils/sampler/weighted_uniform.go +++ b/utils/sampler/weighted_uniform.go @@ -61,9 +61,9 @@ func (s *weightedUniform) Initialize(weights []uint64) error { return nil } -func (s *weightedUniform) Sample(value uint64) (int, error) { +func (s *weightedUniform) Sample(value uint64) (int, bool) { if uint64(len(s.indices)) <= value { - return 0, ErrOutOfRange + return 0, false } - return s.indices[int(value)], nil + return s.indices[int(value)], true } diff --git a/utils/sampler/weighted_without_replacement.go b/utils/sampler/weighted_without_replacement.go index d512cd777909..a5585f0e4300 100644 --- a/utils/sampler/weighted_without_replacement.go +++ b/utils/sampler/weighted_without_replacement.go @@ -8,7 +8,7 @@ package sampler // indices. So duplicate indices can be returned. type WeightedWithoutReplacement interface { Initialize(weights []uint64) error - Sample(count int) ([]int, error) + Sample(count int) ([]int, bool) } // NewDeterministicWeightedWithoutReplacement returns a new sampler diff --git a/utils/sampler/weighted_without_replacement_generic.go b/utils/sampler/weighted_without_replacement_generic.go index c45d64d0b2b0..004ff797b90f 100644 --- a/utils/sampler/weighted_without_replacement_generic.go +++ b/utils/sampler/weighted_without_replacement_generic.go @@ -25,19 +25,20 @@ func (s *weightedWithoutReplacementGeneric) Initialize(weights []uint64) error { return s.w.Initialize(weights) } -func (s *weightedWithoutReplacementGeneric) Sample(count int) ([]int, error) { +func (s *weightedWithoutReplacementGeneric) Sample(count int) ([]int, bool) { s.u.Reset() indices := make([]int, count) for i := 0; i < count; i++ { - weight, err := s.u.Next() - if err != nil { - return nil, err + weight, ok := s.u.Next() + if !ok { + return nil, false } - indices[i], err = s.w.Sample(weight) - if err != nil { - return nil, err + + indices[i], ok = s.w.Sample(weight) + if !ok { + return nil, false } } - return indices, nil + return indices, true } diff --git a/utils/sampler/weighted_without_replacement_test.go b/utils/sampler/weighted_without_replacement_test.go index 8d3469141da1..9edbd8b9bf3b 100644 --- a/utils/sampler/weighted_without_replacement_test.go +++ b/utils/sampler/weighted_without_replacement_test.go @@ -99,8 +99,8 @@ func WeightedWithoutReplacementOutOfRangeTest( require.NoError(s.Initialize([]uint64{1})) - _, err := s.Sample(2) - require.ErrorIs(err, ErrOutOfRange) + _, ok := s.Sample(2) + require.False(ok) } func WeightedWithoutReplacementEmptyWithoutWeightTest( @@ -111,8 +111,8 @@ func WeightedWithoutReplacementEmptyWithoutWeightTest( require.NoError(s.Initialize(nil)) - indices, err := s.Sample(0) - require.NoError(err) + indices, ok := s.Sample(0) + require.True(ok) require.Empty(indices) } @@ -124,8 +124,8 @@ func WeightedWithoutReplacementEmptyTest( require.NoError(s.Initialize([]uint64{1})) - indices, err := s.Sample(0) - require.NoError(err) + indices, ok := s.Sample(0) + require.True(ok) require.Empty(indices) } @@ -137,8 +137,8 @@ func WeightedWithoutReplacementSingletonTest( require.NoError(s.Initialize([]uint64{1})) - indices, err := s.Sample(1) - require.NoError(err) + indices, ok := s.Sample(1) + require.True(ok) require.Equal([]int{0}, indices) } @@ -150,8 +150,8 @@ func WeightedWithoutReplacementWithZeroTest( require.NoError(s.Initialize([]uint64{0, 1})) - indices, err := s.Sample(1) - require.NoError(err) + indices, ok := s.Sample(1) + require.True(ok) require.Equal([]int{1}, indices) } @@ -163,8 +163,8 @@ func WeightedWithoutReplacementDistributionTest( require.NoError(s.Initialize([]uint64{1, 1, 2})) - indices, err := s.Sample(4) - require.NoError(err) + indices, ok := s.Sample(4) + require.True(ok) slices.Sort(indices) require.Equal([]int{0, 1, 2, 2}, indices) diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go index eba565727973..52a76425e7ae 100644 --- a/vms/avm/environment_test.go +++ b/vms/avm/environment_test.go @@ -349,8 +349,8 @@ func sampleAddrs(tb testing.TB, addressFormatter avax.AddressManager, addrs []id sampler.Initialize(uint64(len(addrs))) numAddrs := 1 + rand.Intn(len(addrs)) // #nosec G404 - indices, err := sampler.Sample(numAddrs) - require.NoError(err) + indices, ok := sampler.Sample(numAddrs) + require.True(ok) for _, index := range indices { addr := addrs[index] addrStr, err := addressFormatter.FormatLocalAddress(addr) diff --git a/vms/proposervm/proposer/windower.go b/vms/proposervm/proposer/windower.go index b9a633c702c0..ae79aecafcd5 100644 --- a/vms/proposervm/proposer/windower.go +++ b/vms/proposervm/proposer/windower.go @@ -6,7 +6,6 @@ package proposer import ( "context" "errors" - "fmt" "math/bits" "time" @@ -37,7 +36,8 @@ const ( var ( _ Windower = (*windower)(nil) - ErrAnyoneCanPropose = errors.New("anyone can propose") + ErrAnyoneCanPropose = errors.New("anyone can propose") + ErrUnexpectedSamplerFailure = errors.New("unexpected sampler failure") ) type Windower interface { @@ -132,9 +132,9 @@ func (w *windower) Proposers(ctx context.Context, blockHeight, pChainHeight uint source.Seed(w.chainSource ^ blockHeight) numToSample := int(min(uint64(maxWindows), totalWeight)) - indices, err := sampler.Sample(numToSample) - if err != nil { - return nil, err + indices, ok := sampler.Sample(numToSample) + if !ok { + return nil, ErrUnexpectedSamplerFailure } nodeIDs := make([]ids.NodeID, numToSample) @@ -231,7 +231,7 @@ func (w *windower) makeSampler( pChainHeight uint64, source sampler.Source, ) (sampler.WeightedWithoutReplacement, []validatorData, error) { - // Get the canconical representation of the validator set at the provided + // Get the canonical representation of the validator set at the provided // p-chain height. validatorsMap, err := w.state.GetValidatorSet(ctx, pChainHeight, w.subnetID) if err != nil { @@ -271,9 +271,9 @@ func (w *windower) expectedProposer( // biasing the seed generation. For example, without reversing the slot // height=0 and slot=1 would equal height=1 and slot=0. source.Seed(w.chainSource ^ blockHeight ^ bits.Reverse64(slot)) - indices, err := sampler.Sample(1) - if err != nil { - return ids.EmptyNodeID, fmt.Errorf("failed sampling proposers: %w", err) + indices, ok := sampler.Sample(1) + if !ok { + return ids.EmptyNodeID, ErrUnexpectedSamplerFailure } return validators[indices[0]].id, nil } From cab15c031364c4bd7b46056dc4ed3714a742d0d3 Mon Sep 17 00:00:00 2001 From: Tsachi Herman <24438559+tsachiherman@users.noreply.github.com> Date: Sun, 19 May 2024 11:59:20 -0400 Subject: [PATCH 4/5] [build] Update linter version (#3024) Signed-off-by: Tsachi Herman <24438559+tsachiherman@users.noreply.github.com> Co-authored-by: Stephen Buttolph --- .golangci.yml | 10 +++++----- network/peer/tls_config.go | 3 +-- scripts/lint.sh | 2 +- vms/platformvm/txs/executor/import_test.go | 11 ++++++++--- .../txs/executor/standard_tx_executor_test.go | 2 ++ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 0c4006e9508d..a1991abd29aa 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,11 +2,6 @@ run: timeout: 10m - # Enables skipping of directories: - # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - # Default: true - skip-dirs-use-default: false - # If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes @@ -36,6 +31,11 @@ issues: # Default: 3 max-same-issues: 0 + # Enables skipping of directories: + # - vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + # Default: true + exclude-dirs-use-default: false + linters: disable-all: true enable: diff --git a/network/peer/tls_config.go b/network/peer/tls_config.go index 7de848ed062a..9673b98dc8f1 100644 --- a/network/peer/tls_config.go +++ b/network/peer/tls_config.go @@ -14,7 +14,6 @@ import ( // It is safe, and typically expected, for [keyLogWriter] to be [nil]. // [keyLogWriter] should only be enabled for debugging. func TLSConfig(cert tls.Certificate, keyLogWriter io.Writer) *tls.Config { - // #nosec G402 return &tls.Config{ Certificates: []tls.Certificate{cert}, ClientAuth: tls.RequireAnyClientCert, @@ -24,7 +23,7 @@ func TLSConfig(cert tls.Certificate, keyLogWriter io.Writer) *tls.Config { // // During our security audit by Quantstamp, this was investigated // and confirmed to be safe and correct. - InsecureSkipVerify: true, + InsecureSkipVerify: true, //#nosec G402 MinVersion: tls.VersionTLS13, KeyLogWriter: keyLogWriter, } diff --git a/scripts/lint.sh b/scripts/lint.sh index b2cbaa50fcff..9fb23ae325be 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -32,7 +32,7 @@ fi TESTS=${TESTS:-"golangci_lint license_header require_error_is_no_funcs_as_params single_import interface_compliance_nil require_no_error_inline_func"} function test_golangci_lint { - go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.56.1 + go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.58.1 golangci-lint run --config .golangci.yml } diff --git a/vms/platformvm/txs/executor/import_test.go b/vms/platformvm/txs/executor/import_test.go index c05607526841..c4b831badc92 100644 --- a/vms/platformvm/txs/executor/import_test.go +++ b/vms/platformvm/txs/executor/import_test.go @@ -39,7 +39,8 @@ func TestNewImportTx(t *testing.T) { require.NoError(t, err) customAssetID := ids.GenerateTestID() - + // generate a constant random source generator. + randSrc := rand.NewSource(0) tests := []test{ { description: "can't pay fee", @@ -52,6 +53,7 @@ func TestNewImportTx(t *testing.T) { map[ids.ID]uint64{ env.ctx.AVAXAssetID: env.config.TxFee - 1, }, + randSrc, ), sourceKeys: []*secp256k1.PrivateKey{sourceKey}, expectedErr: builder.ErrInsufficientFunds, @@ -67,6 +69,7 @@ func TestNewImportTx(t *testing.T) { map[ids.ID]uint64{ env.ctx.AVAXAssetID: env.config.TxFee, }, + randSrc, ), sourceKeys: []*secp256k1.PrivateKey{sourceKey}, expectedErr: nil, @@ -82,6 +85,7 @@ func TestNewImportTx(t *testing.T) { map[ids.ID]uint64{ env.ctx.AVAXAssetID: env.config.TxFee, }, + randSrc, ), sourceKeys: []*secp256k1.PrivateKey{sourceKey}, timestamp: env.config.UpgradeConfig.ApricotPhase5Time, @@ -99,6 +103,7 @@ func TestNewImportTx(t *testing.T) { env.ctx.AVAXAssetID: env.config.TxFee, customAssetID: 1, }, + randSrc, ), sourceKeys: []*secp256k1.PrivateKey{sourceKey}, timestamp: env.config.UpgradeConfig.ApricotPhase5Time, @@ -168,6 +173,7 @@ func fundedSharedMemory( sourceKey *secp256k1.PrivateKey, peerChain ids.ID, assets map[ids.ID]uint64, + randSrc rand.Source, ) atomic.SharedMemory { fundedSharedMemoryCalls++ m := atomic.NewMemory(prefixdb.New([]byte{fundedSharedMemoryCalls}, env.baseDB)) @@ -176,11 +182,10 @@ func fundedSharedMemory( peerSharedMemory := m.NewSharedMemory(peerChain) for assetID, amt := range assets { - // #nosec G404 utxo := &avax.UTXO{ UTXOID: avax.UTXOID{ TxID: ids.GenerateTestID(), - OutputIndex: rand.Uint32(), + OutputIndex: uint32(randSrc.Int63()), }, Asset: avax.Asset{ID: assetID}, Out: &secp256k1fx.TransferOutput{ diff --git a/vms/platformvm/txs/executor/standard_tx_executor_test.go b/vms/platformvm/txs/executor/standard_tx_executor_test.go index 28fb5a2404fb..47f26ac5dd13 100644 --- a/vms/platformvm/txs/executor/standard_tx_executor_test.go +++ b/vms/platformvm/txs/executor/standard_tx_executor_test.go @@ -6,6 +6,7 @@ package executor import ( "errors" "math" + "math/rand" "testing" "time" @@ -1185,6 +1186,7 @@ func TestDurangoMemoField(t *testing.T) { map[ids.ID]uint64{ env.ctx.AVAXAssetID: sourceAmount, }, + rand.NewSource(0), ) env.msm.SharedMemory = sharedMemory From eb7ddd75e0bf13b4671b385a9bb7a364b2e8b553 Mon Sep 17 00:00:00 2001 From: cocoyeal <150209682+cocoyeal@users.noreply.github.com> Date: Mon, 20 May 2024 22:42:41 +0800 Subject: [PATCH 5/5] Fix broken docs link (#3028) --- api/admin/service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/admin/service.md b/api/admin/service.md index 94afbf370451..4a2a97c29e13 100644 --- a/api/admin/service.md +++ b/api/admin/service.md @@ -75,7 +75,7 @@ Now, calls to the X-Chain can be made to either `/ext/bc/X` or, equivalently, to Give a blockchain an alias, a different name that can be used any place the blockchain’s ID is used. -:::note Aliasing a chain can also be done via the [Node API](https://docs.avax.network/nodes/configure/avalanchego-config-flags.md#--chain-aliases-file-string). +:::note Aliasing a chain can also be done via the [Node API](/nodes/configure/avalanchego-config-flags.md#--chain-aliases-file-string). Note that the alias is set for each chain on each node individually. In a multi-node Subnet, the same alias should be configured on each node to use an alias across a Subnet successfully. Setting an alias for a chain on one node does not register that alias with other nodes automatically.