diff --git a/dcrjson/chainsvrcmds.go b/dcrjson/chainsvrcmds.go index c3ac080d28..61d9bb02d7 100644 --- a/dcrjson/chainsvrcmds.go +++ b/dcrjson/chainsvrcmds.go @@ -206,6 +206,21 @@ func NewGetBlockHeaderCmd(hash string, verbose *bool) *GetBlockHeaderCmd { } } +// GetBlockSubsidyCmd defines the getblocksubsidy JSON-RPC command. +type GetBlockSubsidyCmd struct { + Height int64 + Voters uint16 +} + +// NewGetBlockSubsidyCmd returns a new instance which can be used to issue a +// getblocksubsidy JSON-RPC command. +func NewGetBlockSubsidyCmd(height int64, voters uint16) *GetBlockSubsidyCmd { + return &GetBlockSubsidyCmd{ + Height: height, + Voters: voters, + } +} + // TemplateRequest is a request object as defined in BIP22 // (https://en.bitcoin.it/wiki/BIP_0022), it is optionally provided as an // pointer argument to GetBlockTemplateCmd. @@ -775,6 +790,7 @@ func init() { MustRegisterCmd("getblockcount", (*GetBlockCountCmd)(nil), flags) MustRegisterCmd("getblockhash", (*GetBlockHashCmd)(nil), flags) MustRegisterCmd("getblockheader", (*GetBlockHeaderCmd)(nil), flags) + MustRegisterCmd("getblocksubsidy", (*GetBlockSubsidyCmd)(nil), flags) MustRegisterCmd("getblocktemplate", (*GetBlockTemplateCmd)(nil), flags) MustRegisterCmd("getchaintips", (*GetChainTipsCmd)(nil), flags) MustRegisterCmd("getconnectioncount", (*GetConnectionCountCmd)(nil), flags) diff --git a/dcrjson/chainsvrcmds_test.go b/dcrjson/chainsvrcmds_test.go index a340637d58..b32ac24efd 100644 --- a/dcrjson/chainsvrcmds_test.go +++ b/dcrjson/chainsvrcmds_test.go @@ -234,6 +234,20 @@ func TestChainSvrCmds(t *testing.T) { Verbose: dcrjson.Bool(true), }, }, + { + name: "getblocksubsidy", + newCmd: func() (interface{}, error) { + return dcrjson.NewCmd("getblocksubsidy", 123, 256) + }, + staticCmd: func() interface{} { + return dcrjson.NewGetBlockSubsidyCmd(123, 256) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblocksubsidy","params":[123,256],"id":1}`, + unmarshalled: &dcrjson.GetBlockSubsidyCmd{ + Height: 123, + Voters: 256, + }, + }, { name: "getblocktemplate", newCmd: func() (interface{}, error) { diff --git a/dcrjson/chainsvrresults.go b/dcrjson/chainsvrresults.go index 59a621cdcc..4950a40b27 100644 --- a/dcrjson/chainsvrresults.go +++ b/dcrjson/chainsvrresults.go @@ -108,6 +108,15 @@ type GetBlockChainInfoResult struct { ChainWork string `json:"chainwork"` } +// GetBlockSubsidyResult models the data returned from the getblocksubsidy +// command. +type GetBlockSubsidyResult struct { + Developer int64 `json:"developer"` + PoS int64 `json:"pos"` + PoW int64 `json:"pow"` + Total int64 `json:"total"` +} + // GetBlockTemplateResultTx models the transactions field of the // getblocktemplate command. type GetBlockTemplateResultTx struct { diff --git a/rpcserver.go b/rpcserver.go index ef0492e0be..dfa2deecce 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -200,6 +200,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getblockcount": handleGetBlockCount, "getblockhash": handleGetBlockHash, "getblockheader": handleGetBlockHeader, + "getblocksubsidy": handleGetBlockSubsidy, "getcoinsupply": handleGetCoinSupply, "getconnectioncount": handleGetConnectionCount, "getcurrentnet": handleGetCurrentNet, @@ -2128,6 +2129,36 @@ func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct } +// handleGetBlockSubsidy implements the getblocksubsidy command. +func handleGetBlockSubsidy(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*dcrjson.GetBlockSubsidyCmd) + + height := c.Height + voters := c.Voters + + cache := s.chain.FetchSubsidyCache() + if cache == nil { + return nil, rpcInternalError("empty subsidy cache", "") + } + + dev := blockchain.CalcBlockTaxSubsidy(cache, height, voters, + s.server.chainParams) + pos := blockchain.CalcStakeVoteSubsidy(cache, height, + s.server.chainParams) * int64(voters) + pow := blockchain.CalcBlockWorkSubsidy(cache, height, voters, + s.server.chainParams) + total := dev + pos + pow + + rep := dcrjson.GetBlockSubsidyResult{ + Developer: dev, + PoS: pos, + PoW: pow, + Total: total, + } + + return rep, nil +} + // encodeTemplateID encodes the passed details into an ID that can be used to // uniquely identify a block template. func encodeTemplateID(prevHash *chainhash.Hash, lastGenerated time.Time) string { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 2357c33c5b..54a90f6157 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -338,6 +338,17 @@ var helpDescsEnUS = map[string]string{ "getblockheaderverboseresult-stakeroot": "The merkle root of the stake transaction tree", "getblockheaderverboseresult-stakeversion": "The stake version of the block", + // GetBlockSubsidyCmd help. + "getblocksubsidy--synopsis": "Returns information regarding subsidy amounts.", + "getblocksubsidy-height": "The block height", + "getblocksubsidy-voters": "The number of voters", + + // GetBlockSubsidyResult help. + "getblocksubsidyresult-developer": "The developer subsidy", + "getblocksubsidyresult-pos": "The Proof-of-Stake subsidy", + "getblocksubsidyresult-pow": "The Proof-of-Work subsidy", + "getblocksubsidyresult-total": "The total subsidy", + // TemplateRequest help. "templaterequest-mode": "This is 'template', 'proposal', or omitted", "templaterequest-capabilities": "List of capabilities", @@ -897,6 +908,7 @@ var rpcResultTypes = map[string][]interface{}{ "getblockcount": {(*int64)(nil)}, "getblockhash": {(*string)(nil)}, "getblockheader": {(*string)(nil), (*dcrjson.GetBlockHeaderVerboseResult)(nil)}, + "getblocksubsidy": {(*dcrjson.GetBlockSubsidyResult)(nil)}, "getblocktemplate": {(*dcrjson.GetBlockTemplateResult)(nil), (*string)(nil), nil}, "getconnectioncount": {(*int32)(nil)}, "getcurrentnet": {(*uint32)(nil)},