// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package chaincfg

import (
	"bytes"
	"encoding/hex"
	"math/big"
	"time"

	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/wire"
)

// bigOne is 1 represented as a big.Int.  It is defined here to avoid the
// overhead of creating it multiple times.
var bigOne = big.NewInt(1)

// Checkpoint identifies a known good point in the block chain.  Using
// checkpoints allows a few optimizations for old blocks during initial download
// and also prevents forks from old blocks.
//
// Each checkpoint is selected based upon several factors.  See the
// documentation for chain.IsCheckpointCandidate for details on the selection
// criteria.
type Checkpoint struct {
	Height int64
	Hash   *chainhash.Hash
}

// Vote describes a voting instance.  It is self-describing so that the UI can
// be directly implemented using the fields.  Mask determines which bits can be
// used.  Bits are enumerated and must be consecutive.  Each vote requires one
// and only one abstain (bits = 0) and reject vote (IsNo = true).
//
// For example, change block height from int64 to uint64.
//
//	Vote {
//		Id:          "blockheight",
//		Description: "Change block height from int64 to uint64"
//		Mask:        0x0006,
//		Choices:     []Choice{
//			{
//				Id:          "abstain",
//				Description: "abstain voting for change",
//				Bits:        0x0000,
//				IsAbstain:   true,
//				IsNo:        false,
//			},
//			{
//				Id:          "no",
//				Description: "reject changing block height to uint64",
//				Bits:        0x0002,
//				IsAbstain:   false,
//				IsNo:        false,
//			},
//			{
//				Id:          "yes",
//				Description: "accept changing block height to uint64",
//				Bits:        0x0004,
//				IsAbstain:   false,
//				IsNo:        true,
//			},
//		},
//	}
type Vote struct {
	// Single unique word identifying the vote.
	Id string

	// Longer description of what the vote is about.
	Description string

	// Usable bits for this vote.
	Mask uint16

	Choices []Choice
}

// Choice defines one of the possible Choices that make up a vote. The 0 value
// in Bits indicates the default choice.  Care should be taken not to bias a
// vote with the default choice.
type Choice struct {
	// Single unique word identifying vote (e.g. yes)
	Id string

	// Longer description of the vote.
	Description string

	// Bits used for this vote.
	Bits uint16

	// This is the abstain choice.  By convention this must be the 0 vote
	// (abstain) and exist only once in the Vote.Choices array.
	IsAbstain bool

	// This choice indicates a hard No Vote.  By convention this must exist
	// only once in the Vote.Choices array.
	IsNo bool
}

// VoteIndex compares vote to Choice.Bits and returns the index into the
// Choices array.  If the vote is invalid it returns -1.
func (v *Vote) VoteIndex(vote uint16) int {
	vote &= v.Mask
	for k := range v.Choices {
		if vote == v.Choices[k].Bits {
			return k
		}
	}

	return -1
}

const (
	// VoteIDMaxBlockSize is the vote ID for the maximum block size
	// increase agenda used for the hard fork demo.
	VoteIDMaxBlockSize = "maxblocksize"

	// VoteIDSDiffAlgorithm is the vote ID for the new stake difficulty
	// algorithm (aka ticket price) agenda defined by DCP0001.
	VoteIDSDiffAlgorithm = "sdiffalgorithm"

	// VoteIDLNSupport is the vote ID for determining if the developers
	// should work on integrating Lightning Network support.
	VoteIDLNSupport = "lnsupport"

	// VoteIDLNFeatures is the vote ID for the agenda that introduces
	// features useful for the Lightning Network (among other uses) defined
	// by DCP0002 and DCP0003.
	VoteIDLNFeatures = "lnfeatures"

	// VoteIDFixLNSeqLocks is the vote ID for the agenda that corrects the
	// sequence lock functionality needed for Lightning Network (among other
	// uses) defined by DCP0004.
	VoteIDFixLNSeqLocks = "fixlnseqlocks"

	// VoteIDHeaderCommitments is the vote ID for the agenda that repurposes
	// the stake root header field to support header commitments and provides
	// an initial commitment to version 2 GCS filters defined by DCP0005.
	VoteIDHeaderCommitments = "headercommitments"

	// VoteIDTreasury is the vote ID for the agenda that enables the
	// decentralized treasury opcodes defined by DCP0006.
	VoteIDTreasury = "treasury"

	// VoteIDRevertTreasuryPolicy is the vote ID for the agenda that
	// reverts the maximum expenditure policy of the treasury account as
	// defined by DCP0007.
	VoteIDRevertTreasuryPolicy = "reverttreasurypolicy"

	// VoteIDExplicitVersionUpgrades is the vote ID for the agenda that enables
	// rejection of new transaction and script versions until they are
	// explicitly enabled via a consensus vote as defined by DCP0008.
	VoteIDExplicitVersionUpgrades = "explicitverupgrades"

	// VoteIDAutoRevocations is the vote ID for the agenda that enables automatic
	// ticket revocations as defined in DCP0009.
	VoteIDAutoRevocations = "autorevocations"

	// VoteIDChangeSubsidySplit is the vote ID for the agenda that changes the
	// block reward subsidy split to 10% PoW, 80% PoS, and 10% Treasury as
	// defined in DCP0010.
	VoteIDChangeSubsidySplit = "changesubsidysplit"

	// VoteIDBlake3Pow is the vote ID for the agenda that changes the proof of
	// work hashing algorithm to BLAKE3 as defined in DCP0011.
	VoteIDBlake3Pow = "blake3pow"

	// VoteIDChangeSubsidySplitR2 is the vote ID for the agenda that changes the
	// block reward subsidy split to 1% PoW, 89% PoS, and 10% Treasury as
	// defined in DCP0012.
	VoteIDChangeSubsidySplitR2 = "changesubsidysplitr2"
)

// ConsensusDeployment defines details related to a specific consensus rule
// change that is voted in.
type ConsensusDeployment struct {
	// Vote describes the what is being voted on and what the choices are.
	Vote Vote

	// ForcedChoiceID specifies that the indicated vote choice should always be
	// considered as having been the majority result of a vote.  An empty string
	// is the default and indicates that the vote should be conducted normally.
	//
	// This primarily exists to support testing without needing to go through
	// the entire voting process.  For example, it is useful for automatically
	// activating rule changes on newer versions of test networks that were
	// previously accepted on prior versions.
	ForcedChoiceID string

	// StartTime is the median block time after which voting on the deployment
	// starts.
	//
	// NOTE: This field is ignored when the forced choice ID field is set.
	StartTime uint64

	// ExpireTime is the median block time after which the attempted deployment
	// expires.
	//
	// NOTE: This field is ignored when the forced choice ID field is set.
	ExpireTime uint64
}

// TokenPayout is a payout for block 1 which specifies a required script
// version, script, and amount to pay in a transaction output.
type TokenPayout struct {
	ScriptVersion uint16
	Script        []byte
	Amount        int64
}

// DNSSeed identifies a DNS seed.
//
// Deprecated: This will be removed in the next major version bump.
type DNSSeed struct {
	// Host defines the hostname of the seed.
	Host string

	// HasFiltering defines whether the seed supports filtering
	// by service flags (wire.ServiceFlag).
	HasFiltering bool
}

// String returns the hostname of the DNS seed in human-readable form.
func (d DNSSeed) String() string {
	return d.Host
}

// Params defines a Decred network by its parameters.  These parameters may be
// used by Decred applications to differentiate networks as well as addresses
// and keys for one network from those intended for use on another network.
type Params struct {
	// Name defines a human-readable identifier for the network.
	Name string

	// Net defines the magic bytes used to identify the network.
	Net wire.CurrencyNet

	// DefaultPort defines the default peer-to-peer port for the network.
	DefaultPort string

	// DNSSeeds defines a list of DNS seeds for the network that are used
	// as one method to discover peers.
	//
	// Deprecated: This will be removed in the next major version bump.
	DNSSeeds []DNSSeed

	// GenesisBlock defines the first block of the chain.
	GenesisBlock *wire.MsgBlock

	// GenesisHash is the starting block hash.
	GenesisHash chainhash.Hash

	// PowLimit defines the highest allowed proof of work value for a block
	// as a uint256.
	PowLimit *big.Int

	// PowLimitBits defines the highest allowed proof of work value for a
	// block in compact form.
	PowLimitBits uint32

	// ReduceMinDifficulty defines whether the network should reduce the
	// minimum required difficulty after a long enough period of time has
	// passed without finding a block.  This is really only useful for test
	// networks and should not be set on a main network.
	//
	// Deprecated: This will be removed in the next major version bump.
	ReduceMinDifficulty bool

	// MinDiffReductionTime is the amount of time after which the minimum
	// required difficulty should be reduced when a block hasn't been found.
	//
	// NOTE: This only applies if ReduceMinDifficulty is true.
	//
	// Deprecated: This will be removed in the next major version bump.
	MinDiffReductionTime time.Duration

	// GenerateSupported specifies whether or not CPU mining is allowed.
	GenerateSupported bool

	// MaximumBlockSizes are the maximum sizes of a block that can be
	// generated on the network.  It is an array because the max block size
	// can be different values depending on the results of a voting agenda.
	// The first entry is the initial block size for the network, while the
	// other entries are potential block size changes which take effect when
	// the vote for the associated agenda succeeds.
	MaximumBlockSizes []int

	// MaxTxSize is the maximum number of bytes a serialized transaction can
	// be in order to be considered valid by consensus.
	MaxTxSize int

	// TargetTimePerBlock is the desired amount of time to generate each
	// block.
	TargetTimePerBlock time.Duration

	// -------------------------------------------------------------------------
	// Version 1 difficulty algorithm (EMA + BLAKE256) parameters.
	// -------------------------------------------------------------------------

	// WorkDiffAlpha is the stake difficulty EMA calculation alpha (smoothing)
	// value. It is different from a normal EMA alpha. Closer to 1 --> smoother.
	//
	// This only applies to the version 1 difficulty retarget algorithm.
	WorkDiffAlpha int64

	// WorkDiffWindowSize is the number of windows (intervals) used for calculation
	// of the exponentially weighted average.
	//
	// This only applies to the version 1 difficulty retarget algorithm.
	WorkDiffWindowSize int64

	// WorkDiffWindows is the number of windows (intervals) used for calculation
	// of the exponentially weighted average.
	//
	// This only applies to the version 1 difficulty retarget algorithm.
	WorkDiffWindows int64

	// TargetTimespan is the desired amount of time that should elapse
	// before the block difficulty requirement is examined to determine how
	// it should be changed in order to maintain the desired block
	// generation rate.  This value should correspond to the product of
	// WorkDiffWindowSize and TimePerBlock above.
	//
	// This only applies to the version 1 difficulty retarget algorithm.
	TargetTimespan time.Duration

	// RetargetAdjustmentFactor is the adjustment factor used to limit
	// the minimum and maximum amount of adjustment that can occur between
	// difficulty retargets.
	//
	// This only applies to the version 1 difficulty retarget algorithm.
	RetargetAdjustmentFactor int64

	// -------------------------------------------------------------------------
	// Version 2 difficulty algorithm (ASERT + BLAKE3) parameters.
	// -------------------------------------------------------------------------

	// WorkDiffV2Blake3StartBits is the starting difficulty bits to use for
	// proof of work under BLAKE3.
	WorkDiffV2Blake3StartBits uint32

	// WorkDiffV2HalfLife is the number of seconds to use for the relaxation
	// time when calculating how difficult it is to solve a block.  The
	// algorithm sets the difficulty exponentially such that it is halved or
	// doubled for every multiple of this value the most recent block is behind
	// or ahead of the ideal schedule.
	WorkDiffV2HalfLifeSecs int64

	// Subsidy parameters.
	//
	// Subsidy calculation for exponential reductions:
	// 0 for i in range (0, height / SubsidyReductionInterval):
	// 1     subsidy *= MulSubsidy
	// 2     subsidy /= DivSubsidy
	//
	// NOTE: BaseSubsidy must be a max of 140,739,635,871,744 atoms or incorrect
	// results will occur due to int64 overflow.  This value comes from
	// MaxInt64/MaxUint16 = (2^63 - 1)/(2^16 - 1) = 2^47 + 2^31 + 2^15.

	// BaseSubsidy is the starting subsidy amount for mined blocks.
	BaseSubsidy int64

	// Subsidy reduction multiplier.
	MulSubsidy int64

	// Subsidy reduction divisor.
	DivSubsidy int64

	// SubsidyReductionInterval is the reduction interval in blocks.
	SubsidyReductionInterval int64

	// WorkRewardProportion is the comparative amount of the subsidy given for
	// creating a block using the proportions prior to the modified values
	// defined in DCP0010.
	//
	// Deprecated: This will be removed in the next major version bump.
	WorkRewardProportion uint16

	// WorkRewardProportionV2 is the comparative amount of the subsidy given for
	// creating a block using the proportions defined in DCP0010.
	//
	// Deprecated: This will be removed in the next major version bump.
	WorkRewardProportionV2 uint16

	// StakeRewardProportion is the comparative amount of the subsidy given for
	// casting stake votes (collectively, per block) using the proportions prior
	// to the modified values defined in DCP0010.
	//
	// Deprecated: This will be removed in the next major version bump.
	StakeRewardProportion uint16

	// StakeRewardProportionV2 is the comparative amount of the subsidy given
	// for casting stake votes (collectively, per block) using the proportions
	// defined in DCP0010.
	//
	// Deprecated: This will be removed in the next major version bump.
	StakeRewardProportionV2 uint16

	// BlockTaxProportion is the inverse of the percentage of funds for each
	// block to allocate to the developer organization.
	// e.g. 10% --> 10 (or 1 / (1/10))
	// Special case: disable taxes with a value of 0
	//
	// Deprecated: This will be removed in the next major version bump.
	BlockTaxProportion uint16

	// Checkpoints previously housed manual checkpoints ordered from oldest to
	// newest. It is no longer used in any way since manual checkpoints no
	// longer exist.
	//
	// Deprecated: This will be removed in the next major version bump.
	Checkpoints []Checkpoint

	// AssumeValid is the hash of a block that has been externally verified to
	// be valid.  It allows several validation checks to be skipped for blocks
	// that are both an ancestor of the assumed valid block and an ancestor of
	// the best header.  It is also used to determine the old forks rejection
	// checkpoint.  This is intended to be updated periodically with new
	// releases.  It may not be set for networks that do not require it.
	AssumeValid chainhash.Hash

	// MinKnownChainWork is the minimum amount of known total work for the chain
	// at a given point in time.  This is intended to be updated periodically
	// with new releases.  It may be nil for networks that do not require it.
	MinKnownChainWork *big.Int

	// These fields are related to voting on consensus rule changes as
	// defined by BIP0009.
	//
	// RuleChangeActivationQuorum is the number of votes required for a vote
	// to take effect.
	//
	// RuleChangeActivationInterval is the number of blocks in each threshold
	// state retarget window.
	//
	// Deployments define the specific consensus rule changes to be voted
	// on for the stake version (the map key).
	RuleChangeActivationQuorum     uint32
	RuleChangeActivationMultiplier uint32
	RuleChangeActivationDivisor    uint32
	RuleChangeActivationInterval   uint32
	Deployments                    map[uint32][]ConsensusDeployment

	// Enforce current block version once network has upgraded.
	BlockEnforceNumRequired uint64

	// Reject previous block versions once network has upgraded.
	BlockRejectNumRequired uint64

	// The number of nodes to check.
	BlockUpgradeNumToCheck uint64

	// AcceptNonStdTxs is a mempool param to either accept and relay
	// non standard txs to the network or reject them
	AcceptNonStdTxs bool

	// NetworkAddressPrefix is the first letter of the network
	// for any given address encoded as a string.
	NetworkAddressPrefix string

	// Address encoding magics
	PubKeyAddrID     [2]byte // First 2 bytes of a P2PK address
	PubKeyHashAddrID [2]byte // First 2 bytes of a P2PKH address
	PKHEdwardsAddrID [2]byte // First 2 bytes of an Edwards P2PKH address
	PKHSchnorrAddrID [2]byte // First 2 bytes of a secp256k1 Schnorr P2PKH address
	ScriptHashAddrID [2]byte // First 2 bytes of a P2SH address
	PrivateKeyID     [2]byte // First 2 bytes of a WIF private key

	// BIP32 hierarchical deterministic extended key magics
	HDPrivateKeyID [4]byte
	HDPublicKeyID  [4]byte

	// SLIP-0044 registered coin type used for BIP44, used in the hierarchical
	// deterministic path for address generation.
	// All SLIP-0044 registered coin types are defined here:
	// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
	SLIP0044CoinType uint32

	// Legacy BIP44 coin type used in the hierarchical deterministic path for
	// address generation. Previous name was HDCoinType, the LegacyCoinType
	// was introduced for backwards compatibility. Usually, SLIP0044CoinType
	// should be used instead.
	LegacyCoinType uint32

	// MinimumStakeDiff if the minimum amount of Atoms required to purchase a
	// stake ticket.
	MinimumStakeDiff int64

	// Ticket pool sizes for Decred PoS. This denotes the number of possible
	// buckets/number of different ticket numbers. It is also the number of
	// possible winner numbers there are.
	TicketPoolSize uint16

	// Average number of tickets per block for Decred PoS.
	TicketsPerBlock uint16

	// Number of blocks for tickets to mature (spendable at TicketMaturity+1).
	TicketMaturity uint16

	// Number of blocks for tickets to expire after they have matured. This MUST
	// be >= (StakeEnabledHeight + StakeValidationHeight).
	TicketExpiry uint32

	// CoinbaseMaturity is the number of blocks required before newly mined
	// coins (coinbase transactions) can be spent.
	CoinbaseMaturity uint16

	// Maturity for spending SStx change outputs.
	SStxChangeMaturity uint16

	// TicketPoolSizeWeight is the multiplicative weight applied to the
	// ticket pool size difference between a window period and its target
	// when determining the stake system.
	TicketPoolSizeWeight uint16

	// StakeDiffAlpha is the stake difficulty EMA calculation alpha (smoothing)
	// value. It is different from a normal EMA alpha. Closer to 1 --> smoother.
	StakeDiffAlpha int64

	// StakeDiffWindowSize is the number of blocks used for each interval in
	// exponentially weighted average.
	StakeDiffWindowSize int64

	// StakeDiffWindows is the number of windows (intervals) used for calculation
	// of the exponentially weighted average.
	StakeDiffWindows int64

	// StakeVersionInterval determines the interval where the stake version
	// is calculated.
	StakeVersionInterval int64

	// MaxFreshStakePerBlock is the maximum number of new tickets that may be
	// submitted per block.
	MaxFreshStakePerBlock uint8

	// StakeEnabledHeight is the height in which the first ticket could possibly
	// mature.
	StakeEnabledHeight int64

	// StakeValidationHeight is the height at which votes (SSGen) are required
	// to add a new block to the top of the blockchain. This height is the
	// first block that will be voted on, but will include in itself no votes.
	StakeValidationHeight int64

	// StakeBaseSigScript is the consensus stakebase signature script for all
	// votes on the network. This isn't signed in any way, so without forcing
	// it to be this value miners/daemons could freely change it.
	StakeBaseSigScript []byte

	// StakeMajorityMultiplier and StakeMajorityDivisor are used
	// to calculate the super majority of stake votes using integer math as
	// such: X*StakeMajorityMultiplier/StakeMajorityDivisor
	StakeMajorityMultiplier int32
	StakeMajorityDivisor    int32

	// OrganizationPkScript is the output script for block taxes to be
	// distributed to in every block's coinbase. It should ideally be a P2SH
	// multisignature address.  OrganizationPkScriptVersion is the version
	// of the output script.  Until PoS hardforking is implemented, this
	// version must always match for a block to validate.
	OrganizationPkScript        []byte
	OrganizationPkScriptVersion uint16

	// BlockOneLedger specifies the list of payouts in the coinbase of
	// block height 1. If there are no payouts to be given, set this
	// to an empty slice.
	BlockOneLedger []TokenPayout

	// PiKeys is the list of sanctioned Politeia keys. There should be at
	// least two of them at any given time. The corresponding private keys
	// for mainnet and testnet must be guarded with extreme prejudice. On
	// the other hand simnet and regnet have these values hardcoded for
	// easier testing.
	PiKeys [][]byte

	// TreasuryVoteInterval dictates when a TSpend transaction is allowed
	// in a block.
	TreasuryVoteInterval uint64

	// TreasuryVoteIntervalMultiplier is the multiplier to the
	// TreasuryVoteInterval that is needed to calculate Expiry.
	TreasuryVoteIntervalMultiplier uint64

	// TreasuryVoteQuorumMultiplier and TreasuryVoteQuorumDivisor are used
	// to calculate the TSpend vote quorum percentage.
	TreasuryVoteQuorumMultiplier uint64
	TreasuryVoteQuorumDivisor    uint64

	// TreasuryVoteRequiredMultiplier and TreasuryVoteRequiredDivisor are
	// used to calculate the required number of votes percentage.
	TreasuryVoteRequiredMultiplier uint64
	TreasuryVoteRequiredDivisor    uint64

	// TreasuryExpenditureWindow is the number of TVI*Multiplier windows
	// that define a single "expenditure window".
	TreasuryExpenditureWindow uint64

	// TreasuryExpenditurePolicy is the number of previous
	// TreasuryExpenditureWindows that defines how far back to calculate
	// the average expenditure of the treasury for an expenditure policy
	// check.
	TreasuryExpenditurePolicy uint64

	// TreasuryExpenditureBootstrap is the value to use as previous average
	// expenditure when there are no treasury spends inside the entire
	// window defined by TreasuryExpenditurePolicy.
	TreasuryExpenditureBootstrap uint64

	// seeders defines a list of seeders for the network that are used
	// as one method to discover peers.
	seeders []string
}

// HDPrivKeyVersion returns the hierarchical deterministic extended private key
// magic version bytes for the network the parameters define.
func (p *Params) HDPrivKeyVersion() [4]byte {
	return p.HDPrivateKeyID
}

// HDPubKeyVersion returns the hierarchical deterministic extended public key
// magic version bytes for the network the parameters define.
func (p *Params) HDPubKeyVersion() [4]byte {
	return p.HDPublicKeyID
}

// AddrIDPubKeyV0 returns the magic prefix bytes for version 0 pay-to-pubkey
// addresses.
func (p *Params) AddrIDPubKeyV0() [2]byte {
	return p.PubKeyAddrID
}

// AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and the
// signature algorithm is ECDSA.
func (p *Params) AddrIDPubKeyHashECDSAV0() [2]byte {
	return p.PubKeyHashAddrID
}

// AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey and signature
// algorithm are Ed25519.
func (p *Params) AddrIDPubKeyHashEd25519V0() [2]byte {
	return p.PKHEdwardsAddrID
}

// AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes for version 0
// pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and the
// signature algorithm is Schnorr.
func (p *Params) AddrIDPubKeyHashSchnorrV0() [2]byte {
	return p.PKHSchnorrAddrID
}

// AddrIDScriptHashV0 returns the magic prefix bytes for version 0
// pay-to-script-hash addresses.
func (p *Params) AddrIDScriptHashV0() [2]byte {
	return p.ScriptHashAddrID
}

// BaseSubsidyValue returns the starting base max potential subsidy amount for
// mined blocks.  This value is reduced over time and then split proportionally
// between PoW, PoS, and the Treasury.  The reduction is controlled by the
// SubsidyReductionInterval, SubsidyReductionMultiplier, and
// SubsidyReductionDivisor parameters.
func (p *Params) BaseSubsidyValue() int64 {
	return p.BaseSubsidy
}

// SubsidyReductionMultiplier returns the multiplier to use when performing
// the exponential subsidy reduction.
func (p *Params) SubsidyReductionMultiplier() int64 {
	return p.MulSubsidy
}

// SubsidyReductionDivisor returns the divisor to use when performing the
// exponential subsidy reduction.
func (p *Params) SubsidyReductionDivisor() int64 {
	return p.DivSubsidy
}

// SubsidyReductionIntervalBlocks returns the reduction interval in number of
// blocks.
func (p *Params) SubsidyReductionIntervalBlocks() int64 {
	return p.SubsidyReductionInterval
}

// WorkSubsidyProportion returns the comparative proportion of the subsidy
// generated for creating a block (PoW) using the proportions prior to the
// modified values defined in DCP0010.
//
// The proportional split between PoW, PoS, and the Treasury is calculated
// by treating each of the proportional parameters as a ratio to the sum of
// the three proportional parameters: WorkSubsidyProportion,
// StakeSubsidyProportion, and TreasurySubsidyProportion.
//
// For example:
// WorkSubsidyProportion:     6 => 6 / (6+3+1) => 6/10 => 60%
// StakeSubsidyProportion:    3 => 3 / (6+3+1) => 3/10 => 30%
// TreasurySubsidyProportion: 1 => 1 / (6+3+1) => 1/10 => 10%
//
// Deprecated: This will be removed in the next major version bump.
func (p *Params) WorkSubsidyProportion() uint16 {
	return p.WorkRewardProportion
}

// StakeSubsidyProportion returns the comparative proportion of the subsidy
// generated for casting stake votes (collectively, per block) using the
// proportions prior to the modified values defined in DCP0010.  See the
// documentation for WorkSubsidyProportion for more details on how the parameter
// is used.
//
// Deprecated: This will be removed in the next major version bump.
func (p *Params) StakeSubsidyProportion() uint16 {
	return p.StakeRewardProportion
}

// TreasurySubsidyProportion returns the comparative proportion of the
// subsidy allocated to the project treasury.  See the documentation for
// WorkSubsidyProportion for more details on how the parameter is used.
//
// Deprecated: This will be removed in the next major version bump.
func (p *Params) TreasurySubsidyProportion() uint16 {
	return p.BlockTaxProportion
}

// VotesPerBlock returns the maximum number of votes a block must contain to
// receive full subsidy.
func (p *Params) VotesPerBlock() uint16 {
	return p.TicketsPerBlock
}

// StakeValidationBeginHeight returns the height at which votes become required
// to extend a block.  This height is the first that will be voted on, but will
// not include any votes itself.
func (p *Params) StakeValidationBeginHeight() int64 {
	return p.StakeValidationHeight
}

// StakeEnableHeight returns the height at which the first ticket could possibly
// mature.
func (p *Params) StakeEnableHeight() int64 {
	return p.StakeEnabledHeight
}

// TicketExpiryBlocks returns the number of blocks after maturity that tickets
// expire. This will be >= (StakeEnableHeight() + StakeValidationBeginHeight()).
func (p *Params) TicketExpiryBlocks() uint32 {
	return p.TicketExpiry
}

// newHashFromStr converts the passed big-endian hex string into a
// chainhash.Hash.  It only differs from the one available in chainhash in that
// it panics on an error since it will only (and must only) be called with
// hard-coded, and therefore known good, hashes.
func newHashFromStr(hexStr string) *chainhash.Hash {
	hash, err := chainhash.NewHashFromStr(hexStr)
	if err != nil {
		// Ordinarily I don't like panics in library code since it
		// can take applications down without them having a chance to
		// recover which is extremely annoying, however an exception is
		// being made in this case because the only way this can panic
		// is if there is an error in the hard-coded hashes.  Thus it
		// will only ever potentially panic on init and therefore is
		// 100% predictable.
		panic(err)
	}
	return hash
}

// hexDecode decodes the passed hex string and returns the resulting bytes.  It
// panics if an error occurs. This is only provided for the hard-coded constants
// so errors in the source code can be detected. It will only (and must only) be
// called with hard-coded values.
func hexDecode(hexStr string) []byte {
	b, err := hex.DecodeString(hexStr)
	if err != nil {
		panic(err)
	}
	return b
}

// hexToBigInt converts the passed hex string into a big integer and will panic
// if there is an error.  This is only provided for the hard-coded constants so
// errors in the source code can be detected. It will only (and must only) be
// called with hard-coded values.
func hexToBigInt(hexStr string) *big.Int {
	val, ok := new(big.Int).SetString(hexStr, 16)
	if !ok {
		panic("failed to parse big integer from hex: " + hexStr)
	}
	return val
}

// BlockOneSubsidy returns the total subsidy of block height 1 for the
// network.
func (p *Params) BlockOneSubsidy() int64 {
	if len(p.BlockOneLedger) == 0 {
		return 0
	}

	sum := int64(0)
	for _, output := range p.BlockOneLedger {
		sum += output.Amount
	}

	return sum
}

// TotalSubsidyProportions is the sum of WorkReward, StakeReward, and BlockTax
// proportions.
func (p *Params) TotalSubsidyProportions() uint16 {
	return p.WorkRewardProportion + p.StakeRewardProportion + p.BlockTaxProportion
}

// LatestCheckpointHeight is the height of the latest checkpoint block in the
// parameters.
//
// Deprecated: This will be removed in the next major version bump.
func (p *Params) LatestCheckpointHeight() int64 {
	if len(p.Checkpoints) == 0 {
		return 0
	}
	return p.Checkpoints[len(p.Checkpoints)-1].Height
}

// PiKeyExists returns true if the provided key is a sanctioned Pi Key.
func (p *Params) PiKeyExists(key []byte) bool {
	for _, v := range p.PiKeys {
		if bytes.Equal(v, key) {
			return true
		}
	}
	return false
}

// Seeders returns the list of HTTP seeders.
func (p *Params) Seeders() []string {
	return p.seeders
}
