<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package chains

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/ava-labs/avalanchego/api/health"
	"github.com/ava-labs/avalanchego/api/keystore"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains/atomic"
	"github.com/ava-labs/avalanchego/database/prefixdb"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/network"
	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/snow/consensus/snowball"
	"github.com/ava-labs/avalanchego/snow/engine/avalanche/state"
	"github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/snow/engine/common/queue"
	"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
	"github.com/ava-labs/avalanchego/snow/networking/router"
	"github.com/ava-labs/avalanchego/snow/networking/sender"
	"github.com/ava-labs/avalanchego/snow/networking/timeout"
	"github.com/ava-labs/avalanchego/snow/triggers"
	"github.com/ava-labs/avalanchego/snow/validators"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/vms"

	dbManager "github.com/ava-labs/avalanchego/database/manager"

	avcon "github.com/ava-labs/avalanchego/snow/consensus/avalanche"
	aveng "github.com/ava-labs/avalanchego/snow/engine/avalanche"
	avbootstrap "github.com/ava-labs/avalanchego/snow/engine/avalanche/bootstrap"

	smcon "github.com/ava-labs/avalanchego/snow/consensus/snowman"
	smeng "github.com/ava-labs/avalanchego/snow/engine/snowman"
	smbootstrap "github.com/ava-labs/avalanchego/snow/engine/snowman/bootstrap"
)

const (
	defaultChannelSize = 1024
)

var BootstrappedKey = []byte{0x00}

// Manager manages the chains running on this node.
// It can:
//   * Create a chain
//   * Add a registrant. When a chain is created, each registrant calls
//     RegisterChain with the new chain as the argument.
//   * Get the aliases associated with a given chain.
//   * Get the ID of the chain associated with a given alias.
type Manager interface {
	// Return the router this Manager is using to route consensus messages to chains
	Router() router.Router

	// Create a chain in the future
	CreateChain(ChainParameters)

	// Create a chain now
	ForceCreateChain(ChainParameters)

	// Add a registrant [r]. Every time a chain is
	// created, [r].RegisterChain([new chain]) is called.
	AddRegistrant(Registrant)

	// Given an alias, return the ID of the chain associated with that alias
	Lookup(string) (ids.ID, error)

	// Given an alias, return the ID of the VM associated with that alias
	LookupVM(string) (ids.ID, error)

	// Return the aliases associated with a chain
	Aliases(ids.ID) []string

	// Add an alias to a chain
	Alias(ids.ID, string) error

	// Returns the ID of the subnet that is validating the provided chain
	SubnetID(chainID ids.ID) (ids.ID, error)

	// Returns true iff the chain with the given ID exists and is finished bootstrapping
	IsBootstrapped(ids.ID) bool

	Shutdown()
}

// ChainParameters defines the chain being created
type ChainParameters struct {
	ID          ids.ID   // The ID of the chain being created
	SubnetID    ids.ID   // ID of the subnet that validates this chain
	GenesisData []byte   // The genesis data of this chain's ledger
	VMAlias     string   // The ID of the vm this chain is running
	FxAliases   []string // The IDs of the feature extensions this chain is running

	CustomBeacons validators.Set // Should only be set if the default beacons can't be used.
}

type chain struct {
	Name    string
	Engine  common.Engine
	Handler *router.Handler
	Ctx     *snow.Context
	VM      interface{}
	Beacons validators.Set
}

// ChainConfig is configuration settings for the current execution.
// [Settings] is the user-provided settings blob for the chain.
// [Upgrades] is a chain-specific blob for coordinating upgrades.
type ChainConfig struct {
	Settings []byte
	Upgrades []byte
}

// ManagerConfig ...
type ManagerConfig struct {
	StakingEnabled            bool // True iff the network has staking enabled
	MaxPendingMsgs            uint32
	MaxNonStakerPendingMsgs   uint32
	StakerMSGPortion          float64
	StakerCPUPortion          float64
	Log                       logging.Logger
	LogFactory                logging.Factory
	VMManager                 vms.Manager // Manage mappings from vm ID --> vm
	DecisionEvents            *triggers.EventDispatcher
	ConsensusEvents           *triggers.EventDispatcher
	DBManager                 dbManager.Manager
	Router                    router.Router    // Routes incoming messages to the appropriate chain
	Net                       network.Network  // Sends consensus messages to other validators
	ConsensusParams           avcon.Parameters // The consensus parameters (alpha, beta, etc.) for new chains
	EpochFirstTransition      time.Time
	EpochDuration             time.Duration
	Validators                validators.Manager // Validators validating on this chain
	NodeID                    ids.ShortID        // The ID of this node
	NetworkID                 uint32             // ID of the network this node is connected to
	Server                    *server.Server     // Handles HTTP API calls
	Keystore                  keystore.Keystore
	AtomicMemory              *atomic.Memory
	AVAXAssetID               ids.ID
	XChainID                  ids.ID
	CriticalChains            ids.Set          // Chains that can't exit gracefully
	WhitelistedSubnets        ids.Set          // Subnets to validate
	TimeoutManager            *timeout.Manager // Manages request timeouts when sending messages to other validators
	HealthService             health.Service
	RetryBootstrap            bool // Should Bootstrap be retried
	RetryBootstrapMaxAttempts int  // Max number of times to retry bootstrap
	ChainConfigs              map[ids.ID]ChainConfig
	// If true, shut down the node after the Primary Network has bootstrapped
	// and use [FetchOnlyFrom] as beacons
	FetchOnly bool
	// [FetchOnlyFrom] ignored unless [FetchOnly] is true
	FetchOnlyFrom validators.Set
	// ShutdownNodeFunc allows the chain manager to issue a request to shutdown the node
	ShutdownNodeFunc func(exitCode int)
}

type syncedSubnetSignal struct {
	// channel allowing all listeners to wake up as soon as whole subnet gets synced.
	// Closing it down signals to all handlers that subnet is synced.
	mu                    sync.Mutex
	subnetFullySyncedSema chan struct{}
	subnetFullySyncedDone bool
}

func (sign *syncedSubnetSignal) SignalSubnetSynced() {
	if sign != nil {
		sign.mu.Lock()
		defer sign.mu.Unlock()
		if !sign.subnetFullySyncedDone {
			close(sign.subnetFullySyncedSema)
			sign.subnetFullySyncedDone = true
		}
	}
}

type manager struct {
	// Note: The string representation of a chain's ID is also considered to be an alias of the chain
	// That is, [chainID].String() is an alias for the chain, too
	ids.Aliaser
	ManagerConfig

	// Those notified when a chain is created
	registrants []Registrant

	unblocked     bool
	blockedChains []ChainParameters

	// Key: Subnet's ID
	// Value: Subnet description
	subnets map[ids.ID]Subnet

	chainsLock sync.Mutex
	// Key: Chain's ID
	// Value: The chain
	chains map[ids.ID]*router.Handler

	subnetSignal syncedSubnetSignal
}
<commit_msg>Introduced idiomatic use of Sync.Once<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package chains

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/ava-labs/avalanchego/api/health"
	"github.com/ava-labs/avalanchego/api/keystore"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains/atomic"
	"github.com/ava-labs/avalanchego/database/prefixdb"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/network"
	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/snow/consensus/snowball"
	"github.com/ava-labs/avalanchego/snow/engine/avalanche/state"
	"github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/snow/engine/common/queue"
	"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
	"github.com/ava-labs/avalanchego/snow/networking/router"
	"github.com/ava-labs/avalanchego/snow/networking/sender"
	"github.com/ava-labs/avalanchego/snow/networking/timeout"
	"github.com/ava-labs/avalanchego/snow/triggers"
	"github.com/ava-labs/avalanchego/snow/validators"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/vms"

	dbManager "github.com/ava-labs/avalanchego/database/manager"

	avcon "github.com/ava-labs/avalanchego/snow/consensus/avalanche"
	aveng "github.com/ava-labs/avalanchego/snow/engine/avalanche"
	avbootstrap "github.com/ava-labs/avalanchego/snow/engine/avalanche/bootstrap"

	smcon "github.com/ava-labs/avalanchego/snow/consensus/snowman"
	smeng "github.com/ava-labs/avalanchego/snow/engine/snowman"
	smbootstrap "github.com/ava-labs/avalanchego/snow/engine/snowman/bootstrap"
)

const (
	defaultChannelSize = 1024
)

var BootstrappedKey = []byte{0x00}

// Manager manages the chains running on this node.
// It can:
//   * Create a chain
//   * Add a registrant. When a chain is created, each registrant calls
//     RegisterChain with the new chain as the argument.
//   * Get the aliases associated with a given chain.
//   * Get the ID of the chain associated with a given alias.
type Manager interface {
	// Return the router this Manager is using to route consensus messages to chains
	Router() router.Router

	// Create a chain in the future
	CreateChain(ChainParameters)

	// Create a chain now
	ForceCreateChain(ChainParameters)

	// Add a registrant [r]. Every time a chain is
	// created, [r].RegisterChain([new chain]) is called.
	AddRegistrant(Registrant)

	// Given an alias, return the ID of the chain associated with that alias
	Lookup(string) (ids.ID, error)

	// Given an alias, return the ID of the VM associated with that alias
	LookupVM(string) (ids.ID, error)

	// Return the aliases associated with a chain
	Aliases(ids.ID) []string

	// Add an alias to a chain
	Alias(ids.ID, string) error

	// Returns the ID of the subnet that is validating the provided chain
	SubnetID(chainID ids.ID) (ids.ID, error)

	// Returns true iff the chain with the given ID exists and is finished bootstrapping
	IsBootstrapped(ids.ID) bool

	Shutdown()
}

// ChainParameters defines the chain being created
type ChainParameters struct {
	ID          ids.ID   // The ID of the chain being created
	SubnetID    ids.ID   // ID of the subnet that validates this chain
	GenesisData []byte   // The genesis data of this chain's ledger
	VMAlias     string   // The ID of the vm this chain is running
	FxAliases   []string // The IDs of the feature extensions this chain is running

	CustomBeacons validators.Set // Should only be set if the default beacons can't be used.
}

type chain struct {
	Name    string
	Engine  common.Engine
	Handler *router.Handler
	Ctx     *snow.Context
	VM      interface{}
	Beacons validators.Set
}

// ChainConfig is configuration settings for the current execution.
// [Settings] is the user-provided settings blob for the chain.
// [Upgrades] is a chain-specific blob for coordinating upgrades.
type ChainConfig struct {
	Settings []byte
	Upgrades []byte
}

// ManagerConfig ...
type ManagerConfig struct {
	StakingEnabled            bool // True iff the network has staking enabled
	MaxPendingMsgs            uint32
	MaxNonStakerPendingMsgs   uint32
	StakerMSGPortion          float64
	StakerCPUPortion          float64
	Log                       logging.Logger
	LogFactory                logging.Factory
	VMManager                 vms.Manager // Manage mappings from vm ID --> vm
	DecisionEvents            *triggers.EventDispatcher
	ConsensusEvents           *triggers.EventDispatcher
	DBManager                 dbManager.Manager
	Router                    router.Router    // Routes incoming messages to the appropriate chain
	Net                       network.Network  // Sends consensus messages to other validators
	ConsensusParams           avcon.Parameters // The consensus parameters (alpha, beta, etc.) for new chains
	EpochFirstTransition      time.Time
	EpochDuration             time.Duration
	Validators                validators.Manager // Validators validating on this chain
	NodeID                    ids.ShortID        // The ID of this node
	NetworkID                 uint32             // ID of the network this node is connected to
	Server                    *server.Server     // Handles HTTP API calls
	Keystore                  keystore.Keystore
	AtomicMemory              *atomic.Memory
	AVAXAssetID               ids.ID
	XChainID                  ids.ID
	CriticalChains            ids.Set          // Chains that can't exit gracefully
	WhitelistedSubnets        ids.Set          // Subnets to validate
	TimeoutManager            *timeout.Manager // Manages request timeouts when sending messages to other validators
	HealthService             health.Service
	RetryBootstrap            bool // Should Bootstrap be retried
	RetryBootstrapMaxAttempts int  // Max number of times to retry bootstrap
	ChainConfigs              map[ids.ID]ChainConfig
	// If true, shut down the node after the Primary Network has bootstrapped
	// and use [FetchOnlyFrom] as beacons
	FetchOnly bool
	// [FetchOnlyFrom] ignored unless [FetchOnly] is true
	FetchOnlyFrom validators.Set
	// ShutdownNodeFunc allows the chain manager to issue a request to shutdown the node
	ShutdownNodeFunc func(exitCode int)
}

type syncedSubnetSignal struct {
	// channel allowing all listeners to wake up as soon as whole subnet gets synced.
	// Closing it down signals to all handlers that subnet is synced.
	broadcastSubnetSyncedOnce sync.Once
	subnetFullySyncedSema     chan struct{}
}

func (sign *syncedSubnetSignal) SignalSubnetSynced() {
	if sign != nil {
		sign.broadcastSubnetSyncedOnce.Do(func() {
			close(sign.subnetFullySyncedSema)
		})
	}
}

type manager struct {
	// Note: The string representation of a chain's ID is also considered to be an alias of the chain
	// That is, [chainID].String() is an alias for the chain, too
	ids.Aliaser
	ManagerConfig

	// Those notified when a chain is created
	registrants []Registrant

	unblocked     bool
	blockedChains []ChainParameters

	// Key: Subnet's ID
	// Value: Subnet description
	subnets map[ids.ID]Subnet

	chainsLock sync.Mutex
	// Key: Chain's ID
	// Value: The chain
	chains map[ids.ID]*router.Handler

	subnetSignal syncedSubnetSignal
}

{'fraction_non_alphanumeric': 0.08340649692712906, 'fraction_numerical': 0.0033767812521104884, 'mean_word_length': 3.048113723346091, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1255700', 'n_tokens_mistral': 4683, 'n_tokens_neox': 4504, 'n_words': 1346}