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 17, 2023
1 parent fa4d8e1 commit bf4972d
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 33 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)
var ssv standalone.SubsidySplitVariant = 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 changesubsidysplit 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 changesubsidysplit 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
36 changes: 23 additions & 13 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,19 +42,23 @@ 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
if dcp0010Height == -1 {
dcp0010Height = math.MaxInt64
}
if dcp0012Height == -1 {
dcp0012Height = math.MaxInt64
}

votesPerBlock := params.VotesPerBlock()
Expand All @@ -62,9 +67,14 @@ func UltimateSubsidy(params *chaincfg.Params, subsidySplitChangeHeight int64) in

subsidyCache := networkSubsidyCache(params)
subsidySum := func(height int64) int64 {
useDCP0010 := height >= subsidySplitChangeHeight
work := subsidyCache.CalcWorkSubsidyV2(height, votesPerBlock, useDCP0010)
vote := subsidyCache.CalcStakeVoteSubsidyV2(height, useDCP0010) * int64(votesPerBlock)
var ssv standalone.SubsidySplitVariant = standalone.SSVOriginal
if height >= dcp0012Height {
ssv = standalone.SSVDCP0012
} else if height >= dcp0010Height {
ssv = standalone.SSVDCP0010
}
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
Expand Down Expand Up @@ -130,10 +140,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
20 changes: 10 additions & 10 deletions txhelpers/subsidy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ import (
func TestUltimateSubsidy(t *testing.T) {
// Mainnet
wantMainnetSubsidy := int64(2099999999800912)
totalSubsidy := UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy := UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)

if totalSubsidy != wantMainnetSubsidy {
t.Errorf("Bad total subsidy; want %d, got %d",
wantMainnetSubsidy, totalSubsidy)
}

// verify cache
totalSubsidy2 := UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy2 := UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)
if totalSubsidy != totalSubsidy2 {
t.Errorf("Bad total subsidy; want %d, got %d",
totalSubsidy, totalSubsidy2)
}

// Mainnet with dcp0010 activating at 638976
wantMainnetSubsidy = int64(2100000000015952)
totalSubsidyDCP0010 := UltimateSubsidy(chaincfg.MainNetParams(), 638976)
totalSubsidyDCP0010 := UltimateSubsidy(chaincfg.MainNetParams(), 638976, -1)

if totalSubsidyDCP0010 != wantMainnetSubsidy {
t.Fatalf("Bad total subsidy; want %d, got %d",
Expand All @@ -38,29 +38,29 @@ func TestUltimateSubsidy(t *testing.T) {

// Testnet
wantTestnetSubsidy := int64(526540305161472)
totalTNSubsidy := UltimateSubsidy(chaincfg.TestNet3Params(), -1)
totalTNSubsidy := UltimateSubsidy(chaincfg.TestNet3Params(), -1, -1)

if totalTNSubsidy != wantTestnetSubsidy {
t.Errorf("Bad total subsidy; want %d, got %d",
wantTestnetSubsidy, totalTNSubsidy)
}

// verify cache
totalTNSubsidy2 := UltimateSubsidy(chaincfg.TestNet3Params(), -1)
totalTNSubsidy2 := UltimateSubsidy(chaincfg.TestNet3Params(), -1, -1)
if totalTNSubsidy != totalTNSubsidy2 {
t.Errorf("Bad total subsidy; want %d, got %d",
totalTNSubsidy, totalTNSubsidy2)
}

// re-verify mainnet cache
totalSubsidy3 := UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy3 := UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)
if totalSubsidy != totalSubsidy3 {
t.Errorf("Bad total subsidy; want %d, got %d",
totalSubsidy, totalSubsidy3)
}

// re-verify mainnet cache (dcp0010)
totalSubsidy4 := UltimateSubsidy(chaincfg.MainNetParams(), 638976)
totalSubsidy4 := UltimateSubsidy(chaincfg.MainNetParams(), 638976, -1)
if totalSubsidyDCP0010 != totalSubsidy4 {
t.Errorf("Bad total subsidy; want %d, got %d",
totalSubsidyDCP0010, totalSubsidy4)
Expand All @@ -69,16 +69,16 @@ func TestUltimateSubsidy(t *testing.T) {

func BenchmarkUltimateSubsidy(b *testing.B) {
// warm up
totalSubsidy := UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy := UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)
// verify cache
totalSubsidy2 := UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy2 := UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)
if totalSubsidy != totalSubsidy2 {
b.Errorf("Bad total subsidy; want %d, got %d",
totalSubsidy, totalSubsidy2)
}

for i := 0; i < b.N; i++ {
totalSubsidy = UltimateSubsidy(chaincfg.MainNetParams(), -1)
totalSubsidy = UltimateSubsidy(chaincfg.MainNetParams(), -1, -1)
}

if totalSubsidy != totalSubsidy2 {
Expand Down
Loading

0 comments on commit bf4972d

Please sign in to comment.