Skip to content

Commit

Permalink
update for dcp0012 (subsidy split r2)
Browse files Browse the repository at this point in the history
  • Loading branch information
chappjc committed Jun 20, 2023
1 parent fa4d8e1 commit 1e979f6
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 41 deletions.
2 changes: 1 addition & 1 deletion cmd/dcrdata/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ replace (
require (
github.com/caarlos0/env/v6 v6.10.1
github.com/decred/dcrd/blockchain/stake/v5 v5.0.0
github.com/decred/dcrd/blockchain/standalone/v2 v2.2.0
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
github.com/decred/dcrd/chaincfg/v3 v3.2.0
github.com/decred/dcrd/dcrutil/v4 v4.0.1
Expand Down Expand Up @@ -86,7 +87,6 @@ require (
github.com/decred/dcrd/addrmgr/v2 v2.0.1 // indirect
github.com/decred/dcrd/blockchain/stake/v3 v3.0.0 // indirect
github.com/decred/dcrd/blockchain/stake/v4 v4.0.0 // indirect
github.com/decred/dcrd/blockchain/standalone/v2 v2.2.0 // indirect
github.com/decred/dcrd/blockchain/v4 v4.0.2 // indirect
github.com/decred/dcrd/certgen v1.1.1 // indirect
github.com/decred/dcrd/connmgr/v3 v3.1.0 // indirect
Expand Down
12 changes: 10 additions & 2 deletions cmd/dcrdata/internal/api/apiroutes.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"sync"
"time"

"github.com/decred/dcrd/blockchain/standalone/v2"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrutil/v4"
Expand Down Expand Up @@ -71,6 +72,8 @@ type DataSource interface {
AddressRowsCompact(address string) ([]*dbtypes.AddressRowCompact, error)
Height() int64
IsDCP0010Active(height int64) bool
IsDCP0011Active(height int64) bool
IsDCP0012Active(height int64) bool
AllAgendas() (map[string]dbtypes.MileStone, error)
GetTicketInfo(txid string) (*apitypes.TicketInfo, error)
PowerlessTickets() (*apitypes.PowerlessTickets, error)
Expand Down Expand Up @@ -1271,8 +1274,13 @@ func (c *appContext) blockSubsidies(w http.ResponseWriter, r *http.Request) {
}
}

useDCP0010 := c.DataSource.IsDCP0010Active(idx)
work, stake, tax := txhelpers.RewardsAtBlock(idx, uint16(numVotes), c.Params, useDCP0010)
ssv := standalone.SSVOriginal
if c.DataSource.IsDCP0012Active(idx) {
ssv = standalone.SSVDCP0012
} else if c.DataSource.IsDCP0010Active(idx) {
ssv = standalone.SSVDCP0010
}
work, stake, tax := txhelpers.RewardsAtBlock(idx, uint16(numVotes), c.Params, ssv)
rewards := apitypes.BlockSubsidies{
BlockNum: idx,
BlockHash: hash,
Expand Down
2 changes: 2 additions & 0 deletions cmd/dcrdata/internal/api/insight/apiroutes.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type BlockDataSource interface {
GetTransactionHex(txid *chainhash.Hash) string
Height() int64
DCP0010ActivationHeight() int64
DCP0011ActivationHeight() int64
DCP0012ActivationHeight() int64
InsightAddressTransactions(addr []string, recentBlockHeight int64) (txs, recentTxs []chainhash.Hash, err error)
SendRawTransaction(txhex string) (string, error)
SpendDetailsForFundingTx(fundHash string) ([]*apitypes.SpendByFundingHash, error)
Expand Down
14 changes: 12 additions & 2 deletions cmd/dcrdata/internal/api/insight/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package insight
import (
"math"

"github.com/decred/dcrd/blockchain/standalone/v2"
"github.com/decred/dcrd/dcrutil/v4"
chainjson "github.com/decred/dcrd/rpc/jsonrpc/types/v4"

Expand Down Expand Up @@ -157,10 +158,19 @@ func (iapi *InsightApi) DcrToInsightBlock(inBlocks []*chainjson.GetBlockVerboseR
if dcp0010Height == -1 {
dcp0010Height = math.MaxInt64
}
dcp0012Height := iapi.BlockData.DCP0012ActivationHeight()
if dcp0012Height == -1 {
dcp0012Height = math.MaxInt64
}

RewardAtBlock := func(blocknum int64, voters uint16) float64 {
useDCP0010 := blocknum >= dcp0010Height
work, stake, tax := txhelpers.RewardsAtBlock(blocknum, voters, iapi.params, useDCP0010)
ssv := standalone.SSVOriginal
if blocknum >= dcp0012Height {
ssv = standalone.SSVDCP0012
} else if blocknum >= dcp0010Height {
ssv = standalone.SSVDCP0010
}
work, stake, tax := txhelpers.RewardsAtBlock(blocknum, voters, iapi.params, ssv)
return dcrutil.Amount(work + stake*int64(voters) + tax).ToCoin()
}

Expand Down
2 changes: 2 additions & 0 deletions cmd/dcrdata/internal/explorer/explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ type explorerDataSource interface {
GetHeight() (int64, error)
TxHeight(txid *chainhash.Hash) (height int64)
DCP0010ActivationHeight() int64
DCP0011ActivationHeight() int64
DCP0012ActivationHeight() int64
BlockSubsidy(height int64, voters uint16) *chainjson.GetBlockSubsidyResult
GetExplorerFullBlocks(start int, end int) []*types.BlockInfo
CurrentDifficulty() (float64, error)
Expand Down
3 changes: 2 additions & 1 deletion cmd/dcrdata/internal/explorer/explorerroutes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2468,7 +2468,8 @@ func (exp *explorerUI) StatsPage(w http.ResponseWriter, r *http.Request) {

// Subsidies
dcp0010Height := exp.dataSource.DCP0010ActivationHeight()
ultSubsidy := txhelpers.UltimateSubsidy(exp.ChainParams, dcp0010Height)
dcp0012Height := exp.dataSource.DCP0012ActivationHeight()
ultSubsidy := txhelpers.UltimateSubsidy(exp.ChainParams, dcp0010Height, dcp0012Height)
bestBlockHeight, err := exp.dataSource.GetHeight()
if err != nil {
log.Errorf("GetHeight failed: %v", err)
Expand Down
2 changes: 2 additions & 0 deletions cmd/dcrdata/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,8 @@ func _main(ctx context.Context) error {
// Update the current chain state in the ChainDB.
chainDB.UpdateChainState(blockData.BlockchainInfo)
log.Infof("Current DCP0010 activation height is %d.", chainDB.DCP0010ActivationHeight())
log.Infof("Current DCP0011 activation height is %d.", chainDB.DCP0011ActivationHeight())
log.Infof("Current DCP0012 activation height is %d.", chainDB.DCP0012ActivationHeight())

if err = explore.Store(blockData, msgBlock); err != nil {
return fmt.Errorf("Failed to store initial block data for explorer pages: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion db/dcrpg/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ replace github.com/decred/dcrdata/v8 => ../../
require (
github.com/davecgh/go-spew v1.1.1
github.com/decred/dcrd/blockchain/stake/v5 v5.0.0
github.com/decred/dcrd/blockchain/standalone/v2 v2.2.0
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
github.com/decred/dcrd/chaincfg/v3 v3.2.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
Expand All @@ -29,7 +30,6 @@ require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/decred/base58 v1.0.5 // indirect
github.com/decred/dcrd/blockchain/standalone/v2 v2.2.0 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect
github.com/decred/dcrd/database/v3 v3.0.1 // indirect
Expand Down
73 changes: 70 additions & 3 deletions db/dcrpg/pgblockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"time"

"github.com/decred/dcrd/blockchain/stake/v5"
"github.com/decred/dcrd/blockchain/standalone/v2"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
Expand Down Expand Up @@ -4722,6 +4723,66 @@ func (pgb *ChainDB) IsDCP0010Active(height int64) bool {
return height >= activeHeight
}

// DCP0011ActivationHeight indicates the height at which the blake3pow
// agenda will activate, or -1 if it is not determined yet.
func (pgb *ChainDB) DCP0011ActivationHeight() int64 {
if _, ok := txhelpers.Blake3PowStakeVer(pgb.chainParams); !ok {
return 0 // activate at genesis if no deployment defined in chaincfg.Params
}

agendaInfo, found := pgb.ChainInfo().AgendaMileStones[chaincfg.VoteIDBlake3Pow]
if !found {
log.Warn("The blake3pow agenda is missing.")
return 0
}

switch agendaInfo.Status {
case dbtypes.ActivatedAgendaStatus, dbtypes.LockedInAgendaStatus:
return agendaInfo.Activated // rci already added for lockedin
}
return -1 // not activated, and no future activation height known
}

// IsDCP0011Active indicates if the "blake3pow" consensus deployment is
// active at the given height according to the current status of the agendas.
func (pgb *ChainDB) IsDCP0011Active(height int64) bool {
activeHeight := pgb.DCP0011ActivationHeight()
if activeHeight == -1 {
return false
}
return height >= activeHeight
}

// DCP0012ActivationHeight indicates the height at which the
// changesubsidysplitr2 agenda will activate, or -1 if it is not determined yet.
func (pgb *ChainDB) DCP0012ActivationHeight() int64 {
if _, ok := txhelpers.SubsidySplitR2StakeVer(pgb.chainParams); !ok {
return 0 // activate at genesis if no deployment defined in chaincfg.Params
}

agendaInfo, found := pgb.ChainInfo().AgendaMileStones[chaincfg.VoteIDChangeSubsidySplitR2]
if !found {
log.Warn("The changesubsidysplitr2 agenda is missing.")
return 0
}

switch agendaInfo.Status {
case dbtypes.ActivatedAgendaStatus, dbtypes.LockedInAgendaStatus:
return agendaInfo.Activated // rci already added for lockedin
}
return -1 // not activated, and no future activation height known
}

// IsDCP0012Active indicates if the "blake3pow" consensus deployment is
// active at the given height according to the current status of the agendas.
func (pgb *ChainDB) IsDCP0012Active(height int64) bool {
activeHeight := pgb.DCP0012ActivationHeight()
if activeHeight == -1 {
return false
}
return height >= activeHeight
}

// CurrentCoinSupply gets the current coin supply as an *apitypes.CoinSupply,
// which additionally contains block info and max supply.
func (pgb *ChainDB) CurrentCoinSupply() (supply *apitypes.CoinSupply) {
Expand All @@ -4732,13 +4793,14 @@ func (pgb *ChainDB) CurrentCoinSupply() (supply *apitypes.CoinSupply) {
}

dcp0010Height := pgb.DCP0010ActivationHeight()
dcp0012Height := pgb.DCP0012ActivationHeight()
hash, height := pgb.BestBlockStr()

return &apitypes.CoinSupply{
Height: height,
Hash: hash,
Mined: int64(coinSupply),
Ultimate: txhelpers.UltimateSubsidy(pgb.chainParams, dcp0010Height),
Ultimate: txhelpers.UltimateSubsidy(pgb.chainParams, dcp0010Height, dcp0012Height),
}
}

Expand Down Expand Up @@ -5708,8 +5770,13 @@ func trimmedTxInfoFromMsgTx(txraw *chainjson.TxRawResult, ticketPrice int64, msg
// BlockSubsidy gets the *chainjson.GetBlockSubsidyResult for the given height
// and number of voters, which can be fewer than the network parameter allows.
func (pgb *ChainDB) BlockSubsidy(height int64, voters uint16) *chainjson.GetBlockSubsidyResult {
dcp0010Active := pgb.IsDCP0010Active(height)
work, stake, tax := txhelpers.RewardsAtBlock(height, voters, pgb.chainParams, dcp0010Active)
ssv := standalone.SSVOriginal
if pgb.IsDCP0012Active(height) {
ssv = standalone.SSVDCP0012
} else if pgb.IsDCP0010Active(height) {
ssv = standalone.SSVDCP0010
}
work, stake, tax := txhelpers.RewardsAtBlock(height, voters, pgb.chainParams, ssv)
stake *= int64(voters)
return &chainjson.GetBlockSubsidyResult{
PoW: work,
Expand Down
88 changes: 67 additions & 21 deletions txhelpers/subsidy.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
type netHeight struct {
net uint32
dcp10height int64
dcp12height int64
}

type subsidySumCache struct {
Expand All @@ -41,35 +42,57 @@ func (ssc *subsidySumCache) store(nh netHeight, total int64) {
var ultimateSubsidies = subsidySumCache{m: map[netHeight]int64{}}

// UltimateSubsidy computes the total subsidy over the entire subsidy
// distribution period of the network, given a known height at which the subsidy
// split change goes into effect (DCP0010). If the height is unknown, provide -1
// to perform the computation with the original subsidy split for all heights.
func UltimateSubsidy(params *chaincfg.Params, subsidySplitChangeHeight int64) int64 {
// distribution period of the network, given a known height at which the first
// and second subsidy split change go into effect (DCP0010 and DCP0012). If the
// height is unknown, provide -1 to perform the computation with the original
// subsidy split for all heights.
func UltimateSubsidy(params *chaincfg.Params, dcp0010Height, dcp0012Height int64) int64 {
// Check previously computed ultimate subsidies.
nh := netHeight{uint32(params.Net), subsidySplitChangeHeight}
nh := netHeight{uint32(params.Net), dcp0010Height, dcp0012Height}
result, ok := ultimateSubsidies.load(nh)
if ok {
return result
}

if subsidySplitChangeHeight == -1 {
subsidySplitChangeHeight = math.MaxInt64
}

votesPerBlock := params.VotesPerBlock()
stakeValidationHeight := params.StakeValidationBeginHeight()
reductionInterval := params.SubsidyReductionIntervalBlocks()

subsidyCache := networkSubsidyCache(params)
subsidySum := func(height int64) int64 {
useDCP0010 := height >= subsidySplitChangeHeight
work := subsidyCache.CalcWorkSubsidyV2(height, votesPerBlock, useDCP0010)
vote := subsidyCache.CalcStakeVoteSubsidyV2(height, useDCP0010) * int64(votesPerBlock)
subsidySum := func(height int64, ssv standalone.SubsidySplitVariant) int64 {
work := subsidyCache.CalcWorkSubsidyV3(height, votesPerBlock, ssv)
vote := subsidyCache.CalcStakeVoteSubsidyV3(height, ssv) * int64(votesPerBlock)
// With voters set to max (votesPerBlock), treasury bool is unimportant.
treasury := subsidyCache.CalcTreasurySubsidy(height, votesPerBlock, false)
return work + vote + treasury
}

// Define details to account for partial intervals where the subsidy split
// changes.
subsidySplitChanges := map[int64]struct {
activationHeight int64
splitBefore standalone.SubsidySplitVariant
splitAfter standalone.SubsidySplitVariant
}{
dcp0010Height / reductionInterval: {
activationHeight: dcp0010Height,
splitBefore: standalone.SSVOriginal,
splitAfter: standalone.SSVDCP0010,
},
dcp0012Height / reductionInterval: {
activationHeight: dcp0012Height,
splitBefore: standalone.SSVDCP0010,
splitAfter: standalone.SSVDCP0012,
},
}

if dcp0010Height == -1 {
dcp0010Height = math.MaxInt64
}
if dcp0012Height == -1 {
dcp0012Height = math.MaxInt64
}

totalSubsidy := params.BlockOneSubsidy()
for i := int64(0); ; i++ {
// The first interval contains a few special cases:
Expand All @@ -81,20 +104,43 @@ func UltimateSubsidy(params *chaincfg.Params, subsidySplitChangeHeight int64) in
// first two special blocks.
subsidyCalcHeight := int64(2)
nonVotingBlocks := stakeValidationHeight - subsidyCalcHeight
totalSubsidy += subsidySum(subsidyCalcHeight) * nonVotingBlocks
totalSubsidy += subsidySum(subsidyCalcHeight, standalone.SSVOriginal) * nonVotingBlocks

// Account for the blocks remaining in the interval once voting
// begins.
subsidyCalcHeight = stakeValidationHeight
votingBlocks := reductionInterval - subsidyCalcHeight
totalSubsidy += subsidySum(subsidyCalcHeight) * votingBlocks
totalSubsidy += subsidySum(subsidyCalcHeight, standalone.SSVOriginal) * votingBlocks
continue
}

// Account for the all other reduction intervals until all subsidy has
// been produced.
// Account for partial intervals with subsidy split changes.
subsidyCalcHeight := i * reductionInterval
sum := subsidySum(subsidyCalcHeight)
if change, ok := subsidySplitChanges[i]; ok {
// Account for the blocks up to the point the subsidy split changed.
preChangeBlocks := change.activationHeight - subsidyCalcHeight
totalSubsidy += subsidySum(subsidyCalcHeight, change.splitBefore) *
preChangeBlocks

// Account for the blocks remaining in the interval after the
// subsidy split changed.
subsidyCalcHeight = change.activationHeight
remainingBlocks := reductionInterval - preChangeBlocks
totalSubsidy += subsidySum(subsidyCalcHeight, change.splitAfter) *
remainingBlocks
continue
}

// Account for the all other reduction intervals until all subsidy has
// been produced including partial intervals with subsidy split changes.
splitVariant := standalone.SSVOriginal
switch {
case subsidyCalcHeight >= dcp0012Height:
splitVariant = standalone.SSVDCP0012
case subsidyCalcHeight >= dcp0010Height:
splitVariant = standalone.SSVDCP0010
}
sum := subsidySum(subsidyCalcHeight, splitVariant)
if sum == 0 {
break
}
Expand Down Expand Up @@ -130,10 +176,10 @@ func networkSubsidyCache(p *chaincfg.Params) *standalone.SubsidyCache {
// at for the specified block index, assuming a certain number of votes. The
// stake reward is for a single vote. The total reward for the block is thus
// work + stake * votes + tax.
func RewardsAtBlock(blockIdx int64, votes uint16, p *chaincfg.Params, useDCP0010 bool) (work, stake, tax int64) {
func RewardsAtBlock(blockIdx int64, votes uint16, p *chaincfg.Params, ssv standalone.SubsidySplitVariant) (work, stake, tax int64) {
subsidyCache := networkSubsidyCache(p)
work = subsidyCache.CalcWorkSubsidyV2(blockIdx, votes, useDCP0010)
stake = subsidyCache.CalcStakeVoteSubsidyV2(blockIdx, useDCP0010)
work = subsidyCache.CalcWorkSubsidyV3(blockIdx, votes, ssv)
stake = subsidyCache.CalcStakeVoteSubsidyV3(blockIdx, ssv)
treasuryActive := IsTreasuryActive(p.Net, blockIdx)
tax = subsidyCache.CalcTreasurySubsidy(blockIdx, votes, treasuryActive)
return
Expand Down
Loading

0 comments on commit 1e979f6

Please sign in to comment.