github.com/decred/dcrd/blockchain@v1.2.1/subsidy.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2015-2019 The Decred developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package blockchain 7 8 import ( 9 "bytes" 10 "fmt" 11 12 "github.com/decred/dcrd/blockchain/stake" 13 "github.com/decred/dcrd/blockchain/standalone" 14 "github.com/decred/dcrd/chaincfg" 15 "github.com/decred/dcrd/dcrutil" 16 "github.com/decred/dcrd/txscript" 17 "github.com/decred/dcrd/wire" 18 ) 19 20 // The number of values to precalculate on initialization of the subsidy 21 // cache. 22 const subsidyCacheInitWidth = 4 23 24 // SubsidyCache is a structure that caches calculated values of subsidy so that 25 // they're not constantly recalculated. The blockchain struct itself possesses a 26 // pointer to a preinitialized SubsidyCache. 27 // 28 // Deprecated: Use standalone.SubsidyCache instead. 29 type SubsidyCache = standalone.SubsidyCache 30 31 // subsidyParams adapts v1 chaincfg.Params to implement the 32 // standalone.SubsidyParams interface. It is already implemented by the v2 33 // chaincfg.Params, but updating to those requires a major version bump since 34 // the type is used in the public API. 35 type subsidyParams struct { 36 *chaincfg.Params 37 } 38 39 // BaseSubsidyValue returns the starting base max potential subsidy amount for 40 // mined blocks. 41 // 42 // This is part of the standalone.SubsidyParams interface. 43 func (p *subsidyParams) BaseSubsidyValue() int64 { 44 return p.BaseSubsidy 45 } 46 47 // SubsidyReductionMultiplier returns the multiplier to use when performing the 48 // exponential subsidy reduction. 49 // 50 // This is part of the standalone.SubsidyParams interface. 51 func (p *subsidyParams) SubsidyReductionMultiplier() int64 { 52 return p.MulSubsidy 53 } 54 55 // SubsidyReductionDivisor returns the divisor to use when performing the 56 // exponential subsidy reduction. 57 // 58 // This is part of the standalone.SubsidyParams interface. 59 func (p *subsidyParams) SubsidyReductionDivisor() int64 { 60 return p.DivSubsidy 61 } 62 63 // SubsidyReductionIntervalBlocks returns the reduction interval in number of 64 // blocks. 65 // 66 // This is part of the standalone.SubsidyParams interface. 67 func (p *subsidyParams) SubsidyReductionIntervalBlocks() int64 { 68 return p.SubsidyReductionInterval 69 } 70 71 // WorkSubsidyProportion returns the comparative proportion of the subsidy 72 // generated for creating a block (PoW). 73 // 74 // This is part of the standalone.SubsidyParams interface. 75 func (p *subsidyParams) WorkSubsidyProportion() uint16 { 76 return p.WorkRewardProportion 77 } 78 79 // StakeSubsidyProportion returns the comparative proportion of the subsidy 80 // generated for casting stake votes (collectively, per block). 81 // 82 // This is part of the standalone.SubsidyParams interface. 83 func (p *subsidyParams) StakeSubsidyProportion() uint16 { 84 return p.StakeRewardProportion 85 } 86 87 // TreasurySubsidyProportion returns the comparative proportion of the subsidy 88 // allocated to the project treasury. 89 // 90 // This is part of the standalone.SubsidyParams interface. 91 func (p *subsidyParams) TreasurySubsidyProportion() uint16 { 92 return p.BlockTaxProportion 93 } 94 95 // VotesPerBlock returns the maximum number of votes a block must contain to 96 // receive full subsidy. 97 // 98 // This is part of the standalone.SubsidyParams interface. 99 func (p *subsidyParams) VotesPerBlock() uint16 { 100 return p.TicketsPerBlock 101 } 102 103 // StakeValidationBeginHeight returns the height at which votes become required 104 // to extend a block. This height is the first that will be voted on, but will 105 // not include any votes itself. 106 // 107 // This is part of the standalone.SubsidyParams interface. 108 func (p *subsidyParams) StakeValidationBeginHeight() int64 { 109 return p.StakeValidationHeight 110 } 111 112 // NewSubsidyCache initializes a new subsidy cache for a given height. It 113 // precalculates the values of the subsidy that are most likely to be seen by 114 // the client when it connects to the network. 115 // 116 // Deprecated: Use standalone.NewSubsidyCache instead. 117 func NewSubsidyCache(height int64, params *chaincfg.Params) *SubsidyCache { 118 return standalone.NewSubsidyCache(&subsidyParams{params}) 119 } 120 121 // CalcBlockWorkSubsidy calculates the proof of work subsidy for a block as a 122 // proportion of the total subsidy. 123 // 124 // Deprecated: Use standalone.SubsidyCache.CalcWorkSubsidy instead. 125 func CalcBlockWorkSubsidy(subsidyCache *SubsidyCache, height int64, voters uint16, params *chaincfg.Params) int64 { 126 return subsidyCache.CalcWorkSubsidy(height, voters) 127 } 128 129 // CalcStakeVoteSubsidy calculates the subsidy for a stake vote based on the height 130 // of its input SStx. 131 // 132 // Safe for concurrent access. 133 // 134 // Deprecated: Use standalone.SubsidyCache.CalcStakeVoteSubsidy instead. 135 func CalcStakeVoteSubsidy(subsidyCache *SubsidyCache, height int64, params *chaincfg.Params) int64 { 136 return subsidyCache.CalcStakeVoteSubsidy(height) 137 } 138 139 // CalcBlockTaxSubsidy calculates the subsidy for the organization address in the 140 // coinbase. 141 // 142 // Safe for concurrent access. 143 // 144 // Deprecated: Use standalone.SubsidyCache.CalcTreasurySubsidy instead. 145 func CalcBlockTaxSubsidy(subsidyCache *SubsidyCache, height int64, voters uint16, params *chaincfg.Params) int64 { 146 return subsidyCache.CalcTreasurySubsidy(height, voters) 147 } 148 149 // blockOneCoinbasePaysTokens checks to see if the first block coinbase pays 150 // out to the network initial token ledger. 151 func blockOneCoinbasePaysTokens(tx *dcrutil.Tx, params *chaincfg.Params) error { 152 // If no ledger is specified, just return true. 153 if len(params.BlockOneLedger) == 0 { 154 return nil 155 } 156 157 if tx.MsgTx().LockTime != 0 { 158 errStr := fmt.Sprintf("block 1 coinbase has invalid locktime") 159 return ruleError(ErrBlockOneTx, errStr) 160 } 161 162 if tx.MsgTx().Expiry != wire.NoExpiryValue { 163 errStr := fmt.Sprintf("block 1 coinbase has invalid expiry") 164 return ruleError(ErrBlockOneTx, errStr) 165 } 166 167 if tx.MsgTx().TxIn[0].Sequence != wire.MaxTxInSequenceNum { 168 errStr := fmt.Sprintf("block 1 coinbase not finalized") 169 return ruleError(ErrBlockOneInputs, errStr) 170 } 171 172 if len(tx.MsgTx().TxOut) == 0 { 173 errStr := fmt.Sprintf("coinbase outputs empty in block 1") 174 return ruleError(ErrBlockOneOutputs, errStr) 175 } 176 177 ledger := params.BlockOneLedger 178 if len(ledger) != len(tx.MsgTx().TxOut) { 179 errStr := fmt.Sprintf("wrong number of outputs in block 1 coinbase; "+ 180 "got %v, expected %v", len(tx.MsgTx().TxOut), len(ledger)) 181 return ruleError(ErrBlockOneOutputs, errStr) 182 } 183 184 // Check the addresses and output amounts against those in the ledger. 185 const consensusScriptVersion = 0 186 for i, txout := range tx.MsgTx().TxOut { 187 if txout.Version != consensusScriptVersion { 188 str := fmt.Sprintf("block one output %d script version %d is not %d", 189 i, txout.Version, consensusScriptVersion) 190 return ruleError(ErrBlockOneOutputs, str) 191 } 192 193 // There should only be one address. 194 _, addrs, _, err := 195 txscript.ExtractPkScriptAddrs(txout.Version, txout.PkScript, params) 196 if err != nil { 197 return ruleError(ErrBlockOneOutputs, err.Error()) 198 } 199 if len(addrs) != 1 { 200 errStr := fmt.Sprintf("too many addresses in output") 201 return ruleError(ErrBlockOneOutputs, errStr) 202 } 203 204 addrLedger, err := dcrutil.DecodeAddress(ledger[i].Address) 205 if err != nil { 206 return err 207 } 208 209 if !bytes.Equal(addrs[0].ScriptAddress(), addrLedger.ScriptAddress()) { 210 errStr := fmt.Sprintf("address in output %v has non matching "+ 211 "address; got %v (hash160 %x), want %v (hash160 %x)", 212 i, 213 addrs[0].EncodeAddress(), 214 addrs[0].ScriptAddress(), 215 addrLedger.EncodeAddress(), 216 addrLedger.ScriptAddress()) 217 return ruleError(ErrBlockOneOutputs, errStr) 218 } 219 220 if txout.Value != ledger[i].Amount { 221 errStr := fmt.Sprintf("address in output %v has non matching "+ 222 "amount; got %v, want %v", i, txout.Value, ledger[i].Amount) 223 return ruleError(ErrBlockOneOutputs, errStr) 224 } 225 } 226 227 return nil 228 } 229 230 // BlockOneCoinbasePaysTokens checks to see if the first block coinbase pays 231 // out to the network initial token ledger. 232 // 233 // Deprecated: This will be removed in the next major version bump. 234 func BlockOneCoinbasePaysTokens(tx *dcrutil.Tx, params *chaincfg.Params) error { 235 return blockOneCoinbasePaysTokens(tx, params) 236 } 237 238 // coinbasePaysTreasury checks to see if a given block's coinbase correctly pays 239 // the treasury. 240 func coinbasePaysTreasury(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx, height int64, voters uint16, params *chaincfg.Params) error { 241 // Treasury subsidy only applies from block 2 onwards. 242 if height <= 1 { 243 return nil 244 } 245 246 // Treasury subsidy is disabled. 247 if params.BlockTaxProportion == 0 { 248 return nil 249 } 250 251 if len(tx.MsgTx().TxOut) == 0 { 252 str := fmt.Sprintf("invalid coinbase (no outputs)") 253 return ruleError(ErrNoTxOutputs, str) 254 } 255 256 treasuryOutput := tx.MsgTx().TxOut[0] 257 if treasuryOutput.Version != params.OrganizationPkScriptVersion { 258 str := fmt.Sprintf("treasury output version %d is instead of %d", 259 treasuryOutput.Version, params.OrganizationPkScriptVersion) 260 return ruleError(ErrNoTax, str) 261 } 262 if !bytes.Equal(treasuryOutput.PkScript, params.OrganizationPkScript) { 263 str := fmt.Sprintf("treasury output script is %x instead of %x", 264 treasuryOutput.PkScript, params.OrganizationPkScript) 265 return ruleError(ErrNoTax, str) 266 } 267 268 // Calculate the amount of subsidy that should have been paid out to the 269 // Treasury and ensure the subsidy generated is correct. 270 orgSubsidy := subsidyCache.CalcTreasurySubsidy(height, voters) 271 if orgSubsidy != treasuryOutput.Value { 272 str := fmt.Sprintf("treasury output amount is %s instead of %s", 273 dcrutil.Amount(treasuryOutput.Value), dcrutil.Amount(orgSubsidy)) 274 return ruleError(ErrNoTax, str) 275 } 276 277 return nil 278 } 279 280 // CoinbasePaysTax checks to see if a given block's coinbase correctly pays 281 // tax to the developer organization. 282 // 283 // Deprecated: This will be removed in the next major version. 284 func CoinbasePaysTax(subsidyCache *SubsidyCache, tx *dcrutil.Tx, height int64, voters uint16, params *chaincfg.Params) error { 285 return coinbasePaysTreasury(subsidyCache, tx, height, voters, params) 286 } 287 288 // calculateAddedSubsidy calculates the amount of subsidy added by a block 289 // and its parent. The blocks passed to this function MUST be valid blocks 290 // that have already been confirmed to abide by the consensus rules of the 291 // network, or the function might panic. 292 func calculateAddedSubsidy(block, parent *dcrutil.Block) int64 { 293 var subsidy int64 294 if headerApprovesParent(&block.MsgBlock().Header) { 295 subsidy += parent.MsgBlock().Transactions[0].TxIn[0].ValueIn 296 } 297 298 for _, stx := range block.MsgBlock().STransactions { 299 if stake.IsSSGen(stx) { 300 subsidy += stx.TxIn[0].ValueIn 301 } 302 } 303 304 return subsidy 305 } 306 307 // CalculateAddedSubsidy calculates the amount of subsidy added by a block 308 // and its parent. The blocks passed to this function MUST be valid blocks 309 // that have already been confirmed to abide by the consensus rules of the 310 // network, or the function might panic. 311 // 312 // Deprecated: This will no longer be exported in the next major version. 313 func CalculateAddedSubsidy(block, parent *dcrutil.Block) int64 { 314 return calculateAddedSubsidy(block, parent) 315 }