mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[Ready] - RPC & UtxoIndex: keep track of, query and test circulating supply. (#2070)
* start * pass tests, (cannot get before put!) and clean up. * add rpc call. * create and pass tests, fix bugs. fully implement rpc * As always fmt * remover old test * clean up proto comment * put the logger back in place. * revert back to 10 sec limit. * migration, change utxoChanged removal to whole utxoEntryPair, add methods to update circulating supply, intialize circulating supply from reset. * Update utxoindex.go * ad * rename to max, change comment * one more total to max Co-authored-by: Ori Newman <orinewman1@gmail.com>
This commit is contained in:
parent
fa7ea121ff
commit
3908f274ae
@ -161,6 +161,8 @@ const (
|
||||
CmdNewBlockTemplateNotificationMessage
|
||||
CmdGetMempoolEntriesByAddressesRequestMessage
|
||||
CmdGetMempoolEntriesByAddressesResponseMessage
|
||||
CmdGetCoinSupplyRequestMessage
|
||||
CmdGetCoinSupplyResponseMessage
|
||||
)
|
||||
|
||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||
@ -294,8 +296,10 @@ var RPCMessageCommandToString = map[MessageCommand]string{
|
||||
CmdNotifyNewBlockTemplateRequestMessage: "NotifyNewBlockTemplateRequest",
|
||||
CmdNotifyNewBlockTemplateResponseMessage: "NotifyNewBlockTemplateResponse",
|
||||
CmdNewBlockTemplateNotificationMessage: "NewBlockTemplateNotification",
|
||||
CmdGetMempoolEntriesByAddressesRequestMessage: "CmdGetMempoolEntriesByAddressesRequest",
|
||||
CmdGetMempoolEntriesByAddressesResponseMessage: "CmdGetMempoolEntriesByAddressesResponse",
|
||||
CmdGetMempoolEntriesByAddressesRequestMessage: "GetMempoolEntriesByAddressesRequest",
|
||||
CmdGetMempoolEntriesByAddressesResponseMessage: "GetMempoolEntriesByAddressesResponse",
|
||||
CmdGetCoinSupplyRequestMessage: "GetCoinSupplyRequest",
|
||||
CmdGetCoinSupplyResponseMessage: "GetCoinSupplyResponse",
|
||||
}
|
||||
|
||||
// Message is an interface that describes a kaspa message. A type that
|
||||
|
40
app/appmessage/rpc_get_coin_supply.go
Normal file
40
app/appmessage/rpc_get_coin_supply.go
Normal file
@ -0,0 +1,40 @@
|
||||
package appmessage
|
||||
|
||||
// GetCoinSupplyRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetCoinSupplyRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetCoinSupplyRequestMessage) Command() MessageCommand {
|
||||
return CmdGetCoinSupplyRequestMessage
|
||||
}
|
||||
|
||||
// NewGetCoinSupplyRequestMessage returns a instance of the message
|
||||
func NewGetCoinSupplyRequestMessage() *GetCoinSupplyRequestMessage {
|
||||
return &GetCoinSupplyRequestMessage{}
|
||||
}
|
||||
|
||||
// GetCoinSupplyResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetCoinSupplyResponseMessage struct {
|
||||
baseMessage
|
||||
MaxSompi uint64
|
||||
CirculatingSompi uint64
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetCoinSupplyResponseMessage) Command() MessageCommand {
|
||||
return CmdGetCoinSupplyResponseMessage
|
||||
}
|
||||
|
||||
// NewGetCoinSupplyResponseMessage returns a instance of the message
|
||||
func NewGetCoinSupplyResponseMessage(maxSompi uint64, circulatingSompi uint64) *GetCoinSupplyResponseMessage {
|
||||
return &GetCoinSupplyResponseMessage{
|
||||
MaxSompi: maxSompi,
|
||||
CirculatingSompi: circulatingSompi,
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ var handlers = map[appmessage.MessageCommand]handler{
|
||||
appmessage.CmdEstimateNetworkHashesPerSecondRequestMessage: rpchandlers.HandleEstimateNetworkHashesPerSecond,
|
||||
appmessage.CmdNotifyVirtualDaaScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualDaaScoreChanged,
|
||||
appmessage.CmdNotifyNewBlockTemplateRequestMessage: rpchandlers.HandleNotifyNewBlockTemplate,
|
||||
appmessage.CmdGetCoinSupplyRequestMessage: rpchandlers.HandleGetCoinSupply,
|
||||
appmessage.CmdGetMempoolEntriesByAddressesRequestMessage: rpchandlers.HandleGetMempoolEntriesByAddresses,
|
||||
}
|
||||
|
||||
|
@ -378,9 +378,9 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification(
|
||||
notification.Added = append(notification.Added, utxosByAddressesEntries...)
|
||||
}
|
||||
}
|
||||
for scriptPublicKeyString, removedOutpoints := range utxoChanges.Removed {
|
||||
for scriptPublicKeyString, removedPairs := range utxoChanges.Removed {
|
||||
if listenerAddress, ok := nl.propagateUTXOsChangedNotificationAddresses[scriptPublicKeyString]; ok {
|
||||
utxosByAddressesEntries := convertUTXOOutpointsToUTXOsByAddressesEntries(listenerAddress.Address, removedOutpoints)
|
||||
utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, removedPairs)
|
||||
notification.Removed = append(notification.Removed, utxosByAddressesEntries...)
|
||||
}
|
||||
}
|
||||
@ -391,8 +391,8 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification(
|
||||
utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs)
|
||||
notification.Added = append(notification.Added, utxosByAddressesEntries...)
|
||||
}
|
||||
if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok {
|
||||
utxosByAddressesEntries := convertUTXOOutpointsToUTXOsByAddressesEntries(listenerAddress.Address, removedOutpoints)
|
||||
if removedPairs, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok {
|
||||
utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, removedPairs)
|
||||
notification.Removed = append(notification.Removed, utxosByAddressesEntries...)
|
||||
}
|
||||
}
|
||||
@ -406,13 +406,13 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification(
|
||||
utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(addressString, addedPairs)
|
||||
notification.Added = append(notification.Added, utxosByAddressesEntries...)
|
||||
}
|
||||
for scriptPublicKeyString, removedOutpoints := range utxoChanges.Removed {
|
||||
for scriptPublicKeyString, removedPAirs := range utxoChanges.Removed {
|
||||
addressString, err := nl.scriptPubKeyStringToAddressString(scriptPublicKeyString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
utxosByAddressesEntries := convertUTXOOutpointsToUTXOsByAddressesEntries(addressString, removedOutpoints)
|
||||
utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(addressString, removedPAirs)
|
||||
notification.Removed = append(notification.Removed, utxosByAddressesEntries...)
|
||||
}
|
||||
}
|
||||
|
29
app/rpc/rpchandlers/get_coin_supply.go
Normal file
29
app/rpc/rpchandlers/get_coin_supply.go
Normal file
@ -0,0 +1,29 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetCoinSupply handles the respectively named RPC command
|
||||
func HandleGetCoinSupply(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
if !context.Config.UTXOIndex {
|
||||
errorMessage := &appmessage.GetCoinSupplyResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
circulatingSompiSupply, err := context.UTXOIndex.GetCirculatingSompiSupply()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := appmessage.NewGetCoinSupplyResponseMessage(
|
||||
constants.MaxSompi,
|
||||
circulatingSompiSupply,
|
||||
)
|
||||
|
||||
return response, nil
|
||||
}
|
@ -37,6 +37,7 @@ var commandTypes = []reflect.Type{
|
||||
|
||||
reflect.TypeOf(protowire.KaspadMessage_GetUtxosByAddressesRequest{}),
|
||||
reflect.TypeOf(protowire.KaspadMessage_GetBalanceByAddressRequest{}),
|
||||
reflect.TypeOf(protowire.KaspadMessage_GetCoinSupplyRequest{}),
|
||||
|
||||
reflect.TypeOf(protowire.KaspadMessage_BanRequest{}),
|
||||
reflect.TypeOf(protowire.KaspadMessage_UnbanRequest{}),
|
||||
|
@ -5,7 +5,7 @@ package externalapi
|
||||
// score of the block that accepts the tx, its public key script, and how
|
||||
// much it pays.
|
||||
type UTXOEntry interface {
|
||||
Amount() uint64
|
||||
Amount() uint64 // Utxo amount in Sompis
|
||||
ScriptPublicKey() *ScriptPublicKey // The public key script for the output.
|
||||
BlockDAAScore() uint64 // Daa score of the block accepting the tx.
|
||||
IsCoinbase() bool
|
||||
|
@ -20,7 +20,7 @@ type UTXOOutpoints map[externalapi.DomainOutpoint]interface{}
|
||||
// a successful update
|
||||
type UTXOChanges struct {
|
||||
Added map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
Removed map[ScriptPublicKeyString]UTXOOutpoints
|
||||
Removed map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
}
|
||||
|
||||
// ConvertScriptPublicKeyToString converts the given scriptPublicKey to a string
|
||||
|
@ -2,6 +2,8 @@ package utxoindex
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/database/binaryserialization"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
@ -10,11 +12,13 @@ import (
|
||||
|
||||
var utxoIndexBucket = database.MakeBucket([]byte("utxo-index"))
|
||||
var virtualParentsKey = database.MakeBucket([]byte("")).Key([]byte("utxo-index-virtual-parents"))
|
||||
var circulatingSupplyKey = database.MakeBucket([]byte("")).Key([]byte("utxo-index-circulating-supply"))
|
||||
|
||||
type utxoIndexStore struct {
|
||||
database database.Database
|
||||
toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpoints
|
||||
database database.Database
|
||||
toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
|
||||
virtualParents []*externalapi.DomainHash
|
||||
}
|
||||
|
||||
@ -22,7 +26,7 @@ func newUTXOIndexStore(database database.Database) *utxoIndexStore {
|
||||
return &utxoIndexStore{
|
||||
database: database,
|
||||
toAdd: make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs),
|
||||
toRemove: make(map[ScriptPublicKeyString]UTXOOutpoints),
|
||||
toRemove: make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +65,7 @@ func (uis *utxoIndexStore) add(scriptPublicKey *externalapi.ScriptPublicKey, out
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint) error {
|
||||
func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error {
|
||||
key := ConvertScriptPublicKeyToString(scriptPublicKey)
|
||||
log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
@ -76,19 +80,19 @@ func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey,
|
||||
}
|
||||
}
|
||||
|
||||
// Create a UTXOOutpoints entry in `toRemove` if it doesn't exist
|
||||
// Create a UTXOOutpointEntryPair in `toRemove` if it doesn't exist
|
||||
if _, ok := uis.toRemove[key]; !ok {
|
||||
log.Tracef("Creating key %s in `toRemove`", key)
|
||||
uis.toRemove[key] = make(UTXOOutpoints)
|
||||
uis.toRemove[key] = make(UTXOOutpointEntryPairs)
|
||||
}
|
||||
|
||||
// Return an error if the outpoint already exists in `toRemove`
|
||||
toRemoveOutpointsOfKey := uis.toRemove[key]
|
||||
if _, ok := toRemoveOutpointsOfKey[*outpoint]; ok {
|
||||
toRemovePairsOfKey := uis.toRemove[key]
|
||||
if _, ok := toRemovePairsOfKey[*outpoint]; ok {
|
||||
return errors.Errorf("cannot remove outpoint %s because it's being removed already", outpoint)
|
||||
}
|
||||
|
||||
toRemoveOutpointsOfKey[*outpoint] = struct{}{}
|
||||
toRemovePairsOfKey[*outpoint] = utxoEntry
|
||||
|
||||
log.Tracef("Removed outpoint %s:%d from scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
@ -101,7 +105,7 @@ func (uis *utxoIndexStore) updateVirtualParents(virtualParents []*externalapi.Do
|
||||
|
||||
func (uis *utxoIndexStore) discard() {
|
||||
uis.toAdd = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs)
|
||||
uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpoints)
|
||||
uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs)
|
||||
uis.virtualParents = nil
|
||||
}
|
||||
|
||||
@ -115,10 +119,12 @@ func (uis *utxoIndexStore) commit() error {
|
||||
}
|
||||
defer dbTransaction.RollbackUnlessClosed()
|
||||
|
||||
for scriptPublicKeyString, toRemoveOutpointsOfKey := range uis.toRemove {
|
||||
toRemoveSompiSupply := uint64(0)
|
||||
|
||||
for scriptPublicKeyString, toRemoveUTXOOutpointEntryPairs := range uis.toRemove {
|
||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||
for outpointToRemove := range toRemoveOutpointsOfKey {
|
||||
for outpointToRemove, utxoEntryToRemove := range toRemoveUTXOOutpointEntryPairs {
|
||||
key, err := uis.convertOutpointToKey(bucket, &outpointToRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -127,9 +133,12 @@ func (uis *utxoIndexStore) commit() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toRemoveSompiSupply = toRemoveSompiSupply + utxoEntryToRemove.Amount()
|
||||
}
|
||||
}
|
||||
|
||||
toAddSompiSupply := uint64(0)
|
||||
|
||||
for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd {
|
||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||
@ -146,6 +155,7 @@ func (uis *utxoIndexStore) commit() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toAddSompiSupply = toAddSompiSupply + utxoEntryToAdd.Amount()
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +165,11 @@ func (uis *utxoIndexStore) commit() error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = uis.updateCirculatingSompiSupply(dbTransaction, toAddSompiSupply, toRemoveSompiSupply)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dbTransaction.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -165,20 +180,29 @@ func (uis *utxoIndexStore) commit() error {
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) addAndCommitOutpointsWithoutTransaction(utxoPairs []*externalapi.OutpointAndUTXOEntryPair) error {
|
||||
toAddSompiSupply := uint64(0)
|
||||
for _, pair := range utxoPairs {
|
||||
bucket := uis.bucketForScriptPublicKey(pair.UTXOEntry.ScriptPublicKey())
|
||||
key, err := uis.convertOutpointToKey(bucket, pair.Outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serializedUTXOEntry, err := serializeUTXOEntry(pair.UTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = uis.database.Put(key, serializedUTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toAddSompiSupply = toAddSompiSupply + pair.UTXOEntry.Amount()
|
||||
}
|
||||
|
||||
err := uis.updateCirculatingSompiSupplyWithoutTransaction(toAddSompiSupply, uint64(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -211,7 +235,7 @@ func (uis *utxoIndexStore) convertKeyToOutpoint(key *database.Key) (*externalapi
|
||||
|
||||
func (uis *utxoIndexStore) stagedData() (
|
||||
toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs,
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpoints,
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpointEntryPairs,
|
||||
virtualParents []*externalapi.DomainHash) {
|
||||
|
||||
toAddClone := make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs, len(uis.toAdd))
|
||||
@ -223,13 +247,13 @@ func (uis *utxoIndexStore) stagedData() (
|
||||
toAddClone[scriptPublicKeyString] = toAddUTXOOutpointEntryPairsClone
|
||||
}
|
||||
|
||||
toRemoveClone := make(map[ScriptPublicKeyString]UTXOOutpoints, len(uis.toRemove))
|
||||
for scriptPublicKeyString, toRemoveOutpoints := range uis.toRemove {
|
||||
toRemoveOutpointsClone := make(UTXOOutpoints, len(toRemoveOutpoints))
|
||||
for outpoint := range toRemoveOutpoints {
|
||||
toRemoveOutpointsClone[outpoint] = struct{}{}
|
||||
toRemoveClone := make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs, len(uis.toRemove))
|
||||
for scriptPublicKeyString, toRemoveUTXOOutpointEntryPairs := range uis.toRemove {
|
||||
toRemoveUTXOOutpointEntryPairsClone := make(UTXOOutpointEntryPairs, len(toRemoveUTXOOutpointEntryPairs))
|
||||
for outpoint, utxoEntry := range toRemoveUTXOOutpointEntryPairs {
|
||||
toRemoveUTXOOutpointEntryPairsClone[outpoint] = utxoEntry
|
||||
}
|
||||
toRemoveClone[scriptPublicKeyString] = toRemoveOutpointsClone
|
||||
toRemoveClone[scriptPublicKeyString] = toRemoveUTXOOutpointEntryPairsClone
|
||||
}
|
||||
|
||||
return toAddClone, toRemoveClone, uis.virtualParents
|
||||
@ -294,6 +318,11 @@ func (uis *utxoIndexStore) deleteAll() error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = uis.database.Delete(circulatingSupplyKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cursor, err := uis.database.Cursor(utxoIndexBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -313,3 +342,92 @@ func (uis *utxoIndexStore) deleteAll() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) initializeCirculatingSompiSupply() error {
|
||||
|
||||
cursor, err := uis.database.Cursor(utxoIndexBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
circulatingSompiSupplyInDatabase := uint64(0)
|
||||
for cursor.Next() {
|
||||
serializedUTXOEntry, err := cursor.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
utxoEntry, err := deserializeUTXOEntry(serializedUTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circulatingSompiSupplyInDatabase = circulatingSompiSupplyInDatabase + utxoEntry.Amount()
|
||||
}
|
||||
|
||||
err = uis.database.Put(
|
||||
circulatingSupplyKey,
|
||||
binaryserialization.SerializeUint64(circulatingSompiSupplyInDatabase),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) updateCirculatingSompiSupply(dbTransaction database.Transaction, toAddSompiSupply uint64, toRemoveSompiSupply uint64) error {
|
||||
if toAddSompiSupply != toRemoveSompiSupply {
|
||||
circulatingSupplyBytes, err := dbTransaction.Get(circulatingSupplyKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circulatingSupply, err := binaryserialization.DeserializeUint64(circulatingSupplyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTransaction.Put(
|
||||
circulatingSupplyKey,
|
||||
binaryserialization.SerializeUint64(circulatingSupply+toAddSompiSupply-toRemoveSompiSupply),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) updateCirculatingSompiSupplyWithoutTransaction(toAddSompiSupply uint64, toRemoveSompiSupply uint64) error {
|
||||
if toAddSompiSupply != toRemoveSompiSupply {
|
||||
circulatingSupplyBytes, err := uis.database.Get(circulatingSupplyKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circulatingSupply, err := binaryserialization.DeserializeUint64(circulatingSupplyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uis.database.Put(
|
||||
circulatingSupplyKey,
|
||||
binaryserialization.SerializeUint64(circulatingSupply+toAddSompiSupply-toRemoveSompiSupply),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) getCirculatingSompiSupply() (uint64, error) {
|
||||
if uis.isAnythingStaged() {
|
||||
return 0, errors.Errorf("cannot get circulatingSupply while staging isn't empty")
|
||||
}
|
||||
circulatingSupply, err := uis.database.Get(circulatingSupplyKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binaryserialization.DeserializeUint64(circulatingSupply)
|
||||
}
|
||||
|
@ -25,14 +25,20 @@ func New(domain domain.Domain, database database.Database) (*UTXOIndex, error) {
|
||||
domain: domain,
|
||||
store: newUTXOIndexStore(database),
|
||||
}
|
||||
|
||||
isSynced, err := utxoIndex.isSynced()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isSynced {
|
||||
err = utxoIndex.Reset()
|
||||
///Has check is for migration to circulating supply, can be removed eventually.
|
||||
hasCirculatingSupplyKey, err := utxoIndex.store.database.Has(circulatingSupplyKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isSynced || !hasCirculatingSupplyKey {
|
||||
|
||||
err := utxoIndex.Reset()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -56,6 +62,11 @@ func (ui *UTXOIndex) Reset() error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ui.store.initializeCirculatingSompiSupply() //At this point the database is empty, so the sole purpose of this call is to initialize the circulating supply key
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fromOutpoint *externalapi.DomainOutpoint
|
||||
for {
|
||||
const step = 1000
|
||||
@ -161,7 +172,7 @@ func (ui *UTXOIndex) removeUTXOs(toRemove externalapi.UTXOCollection) error {
|
||||
}
|
||||
|
||||
log.Tracef("Removing outpoint %s from UTXO index", outpoint)
|
||||
err = ui.store.remove(entry.ScriptPublicKey(), outpoint)
|
||||
err = ui.store.remove(entry.ScriptPublicKey(), outpoint, entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -179,3 +190,12 @@ func (ui *UTXOIndex) UTXOs(scriptPublicKey *externalapi.ScriptPublicKey) (UTXOOu
|
||||
|
||||
return ui.store.getUTXOOutpointEntryPairs(scriptPublicKey)
|
||||
}
|
||||
|
||||
// GetCirculatingSompiSupply returns the current circulating supply of sompis in the network
|
||||
func (ui *UTXOIndex) GetCirculatingSompiSupply() (uint64, error) {
|
||||
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
|
||||
return ui.store.getCirculatingSompiSupply()
|
||||
}
|
||||
|
@ -154,6 +154,8 @@ type KaspadMessage struct {
|
||||
// *KaspadMessage_NewBlockTemplateNotification
|
||||
// *KaspadMessage_GetMempoolEntriesByAddressesRequest
|
||||
// *KaspadMessage_GetMempoolEntriesByAddressesResponse
|
||||
// *KaspadMessage_GetCoinSupplyRequest
|
||||
// *KaspadMessage_GetCoinSupplyResponse
|
||||
Payload isKaspadMessage_Payload `protobuf_oneof:"payload"`
|
||||
}
|
||||
|
||||
@ -1092,6 +1094,20 @@ func (x *KaspadMessage) GetGetMempoolEntriesByAddressesResponse() *GetMempoolEnt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage) GetGetCoinSupplyRequest() *GetCoinSupplyRequestMessage {
|
||||
if x, ok := x.GetPayload().(*KaspadMessage_GetCoinSupplyRequest); ok {
|
||||
return x.GetCoinSupplyRequest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage) GetGetCoinSupplyResponse() *GetCoinSupplyResponseMessage {
|
||||
if x, ok := x.GetPayload().(*KaspadMessage_GetCoinSupplyResponse); ok {
|
||||
return x.GetCoinSupplyResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isKaspadMessage_Payload interface {
|
||||
isKaspadMessage_Payload()
|
||||
}
|
||||
@ -1608,6 +1624,14 @@ type KaspadMessage_GetMempoolEntriesByAddressesResponse struct {
|
||||
GetMempoolEntriesByAddressesResponse *GetMempoolEntriesByAddressesResponseMessage `protobuf:"bytes,1085,opt,name=getMempoolEntriesByAddressesResponse,proto3,oneof"`
|
||||
}
|
||||
|
||||
type KaspadMessage_GetCoinSupplyRequest struct {
|
||||
GetCoinSupplyRequest *GetCoinSupplyRequestMessage `protobuf:"bytes,1086,opt,name=getCoinSupplyRequest,proto3,oneof"`
|
||||
}
|
||||
|
||||
type KaspadMessage_GetCoinSupplyResponse struct {
|
||||
GetCoinSupplyResponse *GetCoinSupplyResponseMessage `protobuf:"bytes,1087,opt,name=getCoinSupplyResponse,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*KaspadMessage_Addresses) isKaspadMessage_Payload() {}
|
||||
|
||||
func (*KaspadMessage_Block) isKaspadMessage_Payload() {}
|
||||
@ -1864,13 +1888,17 @@ func (*KaspadMessage_GetMempoolEntriesByAddressesRequest) isKaspadMessage_Payloa
|
||||
|
||||
func (*KaspadMessage_GetMempoolEntriesByAddressesResponse) isKaspadMessage_Payload() {}
|
||||
|
||||
func (*KaspadMessage_GetCoinSupplyRequest) isKaspadMessage_Payload() {}
|
||||
|
||||
func (*KaspadMessage_GetCoinSupplyResponse) isKaspadMessage_Payload() {}
|
||||
|
||||
var File_messages_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_messages_proto_rawDesc = []byte{
|
||||
0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x22, 0xfe, 0x6b, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x6f, 0x22, 0xbf, 0x6d, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73,
|
||||
@ -2733,21 +2761,33 @@ var file_messages_proto_rawDesc = []byte{
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48,
|
||||
0x00, 0x52, 0x24, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74,
|
||||
0x72, 0x69, 0x65, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
|
||||
0x61, 0x64, 0x32, 0x50, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
|
||||
0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00,
|
||||
0x28, 0x01, 0x30, 0x01, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61,
|
||||
0x73, 0x70, 0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x43, 0x6f,
|
||||
0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18,
|
||||
0xbe, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00,
|
||||
0x52, 0x14, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x69,
|
||||
0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18,
|
||||
0xbf, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48,
|
||||
0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x32, 0x50, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
|
||||
0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
|
||||
0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b,
|
||||
0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -2892,6 +2932,8 @@ var file_messages_proto_goTypes = []interface{}{
|
||||
(*NewBlockTemplateNotificationMessage)(nil), // 125: protowire.NewBlockTemplateNotificationMessage
|
||||
(*GetMempoolEntriesByAddressesRequestMessage)(nil), // 126: protowire.GetMempoolEntriesByAddressesRequestMessage
|
||||
(*GetMempoolEntriesByAddressesResponseMessage)(nil), // 127: protowire.GetMempoolEntriesByAddressesResponseMessage
|
||||
(*GetCoinSupplyRequestMessage)(nil), // 128: protowire.GetCoinSupplyRequestMessage
|
||||
(*GetCoinSupplyResponseMessage)(nil), // 129: protowire.GetCoinSupplyResponseMessage
|
||||
}
|
||||
var file_messages_proto_depIdxs = []int32{
|
||||
1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage
|
||||
@ -3022,15 +3064,17 @@ var file_messages_proto_depIdxs = []int32{
|
||||
125, // 125: protowire.KaspadMessage.newBlockTemplateNotification:type_name -> protowire.NewBlockTemplateNotificationMessage
|
||||
126, // 126: protowire.KaspadMessage.getMempoolEntriesByAddressesRequest:type_name -> protowire.GetMempoolEntriesByAddressesRequestMessage
|
||||
127, // 127: protowire.KaspadMessage.getMempoolEntriesByAddressesResponse:type_name -> protowire.GetMempoolEntriesByAddressesResponseMessage
|
||||
0, // 128: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage
|
||||
0, // 129: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage
|
||||
0, // 130: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage
|
||||
0, // 131: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage
|
||||
130, // [130:132] is the sub-list for method output_type
|
||||
128, // [128:130] is the sub-list for method input_type
|
||||
128, // [128:128] is the sub-list for extension type_name
|
||||
128, // [128:128] is the sub-list for extension extendee
|
||||
0, // [0:128] is the sub-list for field type_name
|
||||
128, // 128: protowire.KaspadMessage.getCoinSupplyRequest:type_name -> protowire.GetCoinSupplyRequestMessage
|
||||
129, // 129: protowire.KaspadMessage.getCoinSupplyResponse:type_name -> protowire.GetCoinSupplyResponseMessage
|
||||
0, // 130: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage
|
||||
0, // 131: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage
|
||||
0, // 132: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage
|
||||
0, // 133: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage
|
||||
132, // [132:134] is the sub-list for method output_type
|
||||
130, // [130:132] is the sub-list for method input_type
|
||||
130, // [130:130] is the sub-list for extension type_name
|
||||
130, // [130:130] is the sub-list for extension extendee
|
||||
0, // [0:130] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_messages_proto_init() }
|
||||
@ -3183,6 +3227,8 @@ func file_messages_proto_init() {
|
||||
(*KaspadMessage_NewBlockTemplateNotification)(nil),
|
||||
(*KaspadMessage_GetMempoolEntriesByAddressesRequest)(nil),
|
||||
(*KaspadMessage_GetMempoolEntriesByAddressesResponse)(nil),
|
||||
(*KaspadMessage_GetCoinSupplyRequest)(nil),
|
||||
(*KaspadMessage_GetCoinSupplyResponse)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
|
@ -137,6 +137,8 @@ message KaspadMessage {
|
||||
NewBlockTemplateNotificationMessage newBlockTemplateNotification = 1083;
|
||||
GetMempoolEntriesByAddressesRequestMessage getMempoolEntriesByAddressesRequest = 1084;
|
||||
GetMempoolEntriesByAddressesResponseMessage getMempoolEntriesByAddressesResponse = 1085;
|
||||
GetCoinSupplyRequestMessage getCoinSupplyRequest = 1086;
|
||||
GetCoinSupplyResponseMessage getCoinSupplyResponse= 1087;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,8 @@
|
||||
- [MempoolEntryByAddress](#protowire.MempoolEntryByAddress)
|
||||
- [GetMempoolEntriesByAddressesRequestMessage](#protowire.GetMempoolEntriesByAddressesRequestMessage)
|
||||
- [GetMempoolEntriesByAddressesResponseMessage](#protowire.GetMempoolEntriesByAddressesResponseMessage)
|
||||
- [GetCoinSupplyRequestMessage](#protowire.GetCoinSupplyRequestMessage)
|
||||
- [GetCoinSupplyResponseMessage](#protowire.GetCoinSupplyResponseMessage)
|
||||
|
||||
- [SubmitBlockResponseMessage.RejectReason](#protowire.SubmitBlockResponseMessage.RejectReason)
|
||||
|
||||
@ -1817,6 +1819,33 @@ See NotifyNewBlockTemplateRequestMessage
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="protowire.GetCoinSupplyRequestMessage"></a>
|
||||
|
||||
### GetCoinSupplyRequestMessage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="protowire.GetCoinSupplyResponseMessage"></a>
|
||||
|
||||
### GetCoinSupplyResponseMessage
|
||||
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| maxSompi | [uint64](#uint64) | | note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly. |
|
||||
| circulatingSompi | [uint64](#uint64) | | |
|
||||
| error | [RPCError](#protowire.RPCError) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -5953,6 +5953,107 @@ func (x *GetMempoolEntriesByAddressesResponseMessage) GetError() *RPCError {
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetCoinSupplyRequestMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyRequestMessage) Reset() {
|
||||
*x = GetCoinSupplyRequestMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[106]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyRequestMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetCoinSupplyRequestMessage) ProtoMessage() {}
|
||||
|
||||
func (x *GetCoinSupplyRequestMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[106]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetCoinSupplyRequestMessage.ProtoReflect.Descriptor instead.
|
||||
func (*GetCoinSupplyRequestMessage) Descriptor() ([]byte, []int) {
|
||||
return file_rpc_proto_rawDescGZIP(), []int{106}
|
||||
}
|
||||
|
||||
type GetCoinSupplyResponseMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MaxSompi uint64 `protobuf:"varint,1,opt,name=maxSompi,proto3" json:"maxSompi,omitempty"` // note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly.
|
||||
CirculatingSompi uint64 `protobuf:"varint,2,opt,name=circulatingSompi,proto3" json:"circulatingSompi,omitempty"`
|
||||
Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) Reset() {
|
||||
*x = GetCoinSupplyResponseMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[107]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetCoinSupplyResponseMessage) ProtoMessage() {}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[107]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetCoinSupplyResponseMessage.ProtoReflect.Descriptor instead.
|
||||
func (*GetCoinSupplyResponseMessage) Descriptor() ([]byte, []int) {
|
||||
return file_rpc_proto_rawDescGZIP(), []int{107}
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) GetMaxSompi() uint64 {
|
||||
if x != nil {
|
||||
return x.MaxSompi
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) GetCirculatingSompi() uint64 {
|
||||
if x != nil {
|
||||
return x.CirculatingSompi
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) GetError() *RPCError {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_rpc_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_rpc_proto_rawDesc = []byte{
|
||||
@ -6724,10 +6825,21 @@ var file_rpc_proto_rawDesc = []byte{
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2a,
|
||||
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65,
|
||||
0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
|
||||
0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65,
|
||||
0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x1c, 0x47, 0x65,
|
||||
0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61,
|
||||
0x78, 0x53, 0x6f, 0x6d, 0x70, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61,
|
||||
0x78, 0x53, 0x6f, 0x6d, 0x70, 0x69, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6c,
|
||||
0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x6f, 0x6d, 0x70, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x10, 0x63, 0x69, 0x72, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x6f, 0x6d,
|
||||
0x70, 0x69, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
|
||||
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x26,
|
||||
0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73,
|
||||
0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -6743,7 +6855,7 @@ func file_rpc_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 106)
|
||||
var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 108)
|
||||
var file_rpc_proto_goTypes = []interface{}{
|
||||
(SubmitBlockResponseMessage_RejectReason)(0), // 0: protowire.SubmitBlockResponseMessage.RejectReason
|
||||
(*RPCError)(nil), // 1: protowire.RPCError
|
||||
@ -6852,6 +6964,8 @@ var file_rpc_proto_goTypes = []interface{}{
|
||||
(*MempoolEntryByAddress)(nil), // 104: protowire.MempoolEntryByAddress
|
||||
(*GetMempoolEntriesByAddressesRequestMessage)(nil), // 105: protowire.GetMempoolEntriesByAddressesRequestMessage
|
||||
(*GetMempoolEntriesByAddressesResponseMessage)(nil), // 106: protowire.GetMempoolEntriesByAddressesResponseMessage
|
||||
(*GetCoinSupplyRequestMessage)(nil), // 107: protowire.GetCoinSupplyRequestMessage
|
||||
(*GetCoinSupplyResponseMessage)(nil), // 108: protowire.GetCoinSupplyResponseMessage
|
||||
}
|
||||
var file_rpc_proto_depIdxs = []int32{
|
||||
3, // 0: protowire.RpcBlock.header:type_name -> protowire.RpcBlockHeader
|
||||
@ -6929,11 +7043,12 @@ var file_rpc_proto_depIdxs = []int32{
|
||||
33, // 72: protowire.MempoolEntryByAddress.receiving:type_name -> protowire.MempoolEntry
|
||||
104, // 73: protowire.GetMempoolEntriesByAddressesResponseMessage.entries:type_name -> protowire.MempoolEntryByAddress
|
||||
1, // 74: protowire.GetMempoolEntriesByAddressesResponseMessage.error:type_name -> protowire.RPCError
|
||||
75, // [75:75] is the sub-list for method output_type
|
||||
75, // [75:75] is the sub-list for method input_type
|
||||
75, // [75:75] is the sub-list for extension type_name
|
||||
75, // [75:75] is the sub-list for extension extendee
|
||||
0, // [0:75] is the sub-list for field type_name
|
||||
1, // 75: protowire.GetCoinSupplyResponseMessage.error:type_name -> protowire.RPCError
|
||||
76, // [76:76] is the sub-list for method output_type
|
||||
76, // [76:76] is the sub-list for method input_type
|
||||
76, // [76:76] is the sub-list for extension type_name
|
||||
76, // [76:76] is the sub-list for extension extendee
|
||||
0, // [0:76] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_rpc_proto_init() }
|
||||
@ -8214,6 +8329,30 @@ func file_rpc_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetCoinSupplyRequestMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetCoinSupplyResponseMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@ -8221,7 +8360,7 @@ func file_rpc_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_rpc_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 106,
|
||||
NumMessages: 108,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@ -705,3 +705,12 @@ message GetMempoolEntriesByAddressesResponseMessage{
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message GetCoinSupplyRequestMessage{
|
||||
}
|
||||
|
||||
message GetCoinSupplyResponseMessage{
|
||||
uint64 maxSompi = 1; // note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly.
|
||||
uint64 circulatingSompi = 2;
|
||||
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package protowire
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (x *KaspadMessage_GetCoinSupplyRequest) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.GetCoinSupplyRequestMessage{}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetCoinSupplyRequest) fromAppMessage(_ *appmessage.GetCoinSupplyRequestMessage) error {
|
||||
x.GetCoinSupplyRequest = &GetCoinSupplyRequestMessage{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetCoinSupplyResponse) toAppMessage() (appmessage.Message, error) {
|
||||
if x == nil {
|
||||
return nil, errors.Wrapf(errorNil, "KaspadMessage_GetCoinSupplyResponse is nil")
|
||||
}
|
||||
return x.GetCoinSupplyResponse.toAppMessage()
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetCoinSupplyResponse) fromAppMessage(message *appmessage.GetCoinSupplyResponseMessage) error {
|
||||
var err *RPCError
|
||||
if message.Error != nil {
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
x.GetCoinSupplyResponse = &GetCoinSupplyResponseMessage{
|
||||
MaxSompi: message.MaxSompi,
|
||||
CirculatingSompi: message.CirculatingSompi,
|
||||
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetCoinSupplyResponseMessage) toAppMessage() (appmessage.Message, error) {
|
||||
if x == nil {
|
||||
return nil, errors.Wrapf(errorNil, "GetCoinSupplyResponseMessage is nil")
|
||||
}
|
||||
rpcErr, err := x.Error.toAppMessage()
|
||||
// Error is an optional field
|
||||
if err != nil && !errors.Is(err, errorNil) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &appmessage.GetCoinSupplyResponseMessage{
|
||||
MaxSompi: x.MaxSompi,
|
||||
CirculatingSompi: x.CirculatingSompi,
|
||||
|
||||
Error: rpcErr,
|
||||
}, nil
|
||||
}
|
@ -954,6 +954,20 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetCoinSupplyRequestMessage:
|
||||
payload := new(KaspadMessage_GetCoinSupplyRequest)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetCoinSupplyResponseMessage:
|
||||
payload := new(KaspadMessage_GetCoinSupplyResponse)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
20
infrastructure/network/rpcclient/rpc_get_coin_supply.go
Normal file
20
infrastructure/network/rpcclient/rpc_get_coin_supply.go
Normal file
@ -0,0 +1,20 @@
|
||||
package rpcclient
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
// GetCoinSupply sends an RPC request respective to the function's name and returns the RPC server's response
|
||||
func (c *RPCClient) GetCoinSupply() (*appmessage.GetCoinSupplyResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetCoinSupplyRequestMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdGetCoinSupplyResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
geCoinSupplyResponse := response.(*appmessage.GetCoinSupplyResponseMessage)
|
||||
if geCoinSupplyResponse.Error != nil {
|
||||
return nil, c.convertRPCError(geCoinSupplyResponse.Error)
|
||||
}
|
||||
return geCoinSupplyResponse, nil
|
||||
}
|
@ -49,6 +49,27 @@ func TestUTXOIndex(t *testing.T) {
|
||||
mineNextBlock(t, kaspad)
|
||||
}
|
||||
|
||||
//check if rewards corrosponds to circulating supply.
|
||||
getCoinSupplyResponse, err := kaspad.rpcClient.GetCoinSupply()
|
||||
if err != nil {
|
||||
t.Fatalf("Error Retriving Coin supply: %s", err)
|
||||
}
|
||||
|
||||
rewardsMinedSompi := uint64(blockAmountToMine * constants.SompiPerKaspa * 500)
|
||||
getBlockCountResponse, err := kaspad.rpcClient.GetBlockCount()
|
||||
if err != nil {
|
||||
t.Fatalf("Error Retriving BlockCount: %s", err)
|
||||
}
|
||||
rewardsMinedViaBlockCountSompi := uint64(
|
||||
(getBlockCountResponse.BlockCount - 2) * constants.SompiPerKaspa * 500, // -2 because of genesis and virtual.
|
||||
)
|
||||
|
||||
if getCoinSupplyResponse.CirculatingSompi != rewardsMinedSompi {
|
||||
t.Fatalf("Error: Circulating supply Mismatch - Circulating Sompi: %d Sompi Mined: %d", getCoinSupplyResponse.CirculatingSompi, rewardsMinedSompi)
|
||||
} else if getCoinSupplyResponse.CirculatingSompi != rewardsMinedViaBlockCountSompi {
|
||||
t.Fatalf("Error: Circulating supply Mismatch - Circulating Sompi: %d Sompi Mined via Block count: %d", getCoinSupplyResponse.CirculatingSompi, rewardsMinedViaBlockCountSompi)
|
||||
}
|
||||
|
||||
// Collect the UTXO and make sure there's nothing in Removed
|
||||
// Note that we expect blockAmountToMine-1 messages because
|
||||
// the last block won't be accepted until the next block is
|
||||
|
Loading…
x
Reference in New Issue
Block a user