mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-1597] Implement a UTXO index (#1221)
* [NOD-1579] Rename AcceptedTxIDs to AcceptedTransactionIDs. * [NOD-1579] Add InsertBlockResult to ValidateAndInsertBlock results. * [NOD-1593] Rename InsertBlockResult to BlockInsertionResult. * [NOD-1593] Add SelectedParentChainChanges to AddBlockToVirtual's result. * [NOD-1593] Implement findSelectedParentChainChanges. * [NOD-1593] Implement TestFindSelectedParentChainChanges. * [NOD-1593] Fix a string. * [NOD-1593] Finish implementing TestFindSelectedParentChainChanges. * [NOD-1593] Fix merge errors. * [NOD-1597] Begin implementing UTXOIndex. * [NOD-1597] Connect UTXOIndex to RPC. * [NOD-1597] Connect Consensus to UTXOIndex. * [NOD-1597] Add AcceptanceData to BlockInfo. * [NOD-1597] Implement UTXOIndex.Update(). * [NOD-1597] Implement add(), remove(), and discard() in utxoIndexStore. * [NOD-1597] Add error cases to add() and remove(). * [NOD-1597] Add special cases to add() and remove(). * [NOD-1597] Implement commit. * [NOD-1597] Add a mutex around UTXOIndex.Update(). * [NOD-1597] Return changes to the UTXO from Update(). * [NOD-1597] Add NotifyUTXOsChangedRequestMessage and related structs. * [NOD-1597] Implement HandleNotifyUTXOsChanged. * [NOD-1597] Begin implementing TestUTXOIndex. * [NOD-1597] Implement RegisterForUTXOsChangedNotifications. * [NOD-1597] Fix bad transaction.ID usage. * [NOD-1597] Implement convertUTXOChangesToUTXOsChangedNotification. * [NOD-1597] Make UTXOsChangedNotificationMessage.Removed UTXOsByAddressesEntry instead of just RPCOutpoint so that the client can discern which address was the UTXO removed for. * [NOD-1597] Collect outpoints in TestUTXOIndex. * [NOD-1597] Rename RPC stuff. * [NOD-1597] Add messages for GetUTXOsByAddresses. * [NOD-1597] Implement HandleGetUTXOsByAddresses. * [NOD-1597] Implement GetUTXOsByAddresses. * [NOD-1597] Implement UTXOs(). * [NOD-1597] Implement getUTXOOutpointEntryPairs(). * [NOD-1597] Expand TestUTXOIndex. * [NOD-1597] Convert SubmitTransaction to use RPCTransaction instead of MsgTx. * [NOD-1597] Finish implementing TestUTXOIndex. * [NOD-1597] Add messages for GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement HandleGetVirtualSelectedParentBlueScore and GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement NotifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Expand TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement notifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Make go lint happy. * [NOD-1593] Fix merge errors. * [NOD-1593] Rename findSelectedParentChainChanges to calculateSelectedParentChainChanges. * [NOD-1593] Expand TestCalculateSelectedParentChainChanges. * [NOD-1597] Add logs to utxoindex.go. * [NOD-1597] Add logs to utxoindex/store.go. * [NOD-1597] Add logs to RPCManager.NotifyXXX functions. * [NOD-1597] Ignore transactions that aren't accepted. * [NOD-1597] Use GetBlockAcceptanceData instead of GetBlockInfo. * [NOD-1597] Convert scriptPublicKey to string directly, instead of using hex. * [NOD-1597] Add a comment. * [NOD-1597] Guard against calling utxoindex methods when utxoindex is turned off. * [NOD-1597] Add lock to UTXOs. * [NOD-1597] Guard against calls to getUTXOOutpointEntryPairs when staging isn't empty.
This commit is contained in:
parent
843edc4ba5
commit
053bb351b5
@ -1,7 +1,11 @@
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
)
|
||||
|
||||
@ -153,3 +157,113 @@ func outpointToDomainOutpoint(outpoint *Outpoint) *externalapi.DomainOutpoint {
|
||||
Index: outpoint.Index,
|
||||
}
|
||||
}
|
||||
|
||||
// RPCTransactionToDomainTransaction converts RPCTransactions to DomainTransactions
|
||||
func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externalapi.DomainTransaction, error) {
|
||||
inputs := make([]*externalapi.DomainTransactionInput, len(rpcTransaction.Inputs))
|
||||
for i, input := range rpcTransaction.Inputs {
|
||||
transactionIDBytes, err := hex.DecodeString(input.PreviousOutpoint.TransactionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transactionID, err := transactionid.FromBytes(transactionIDBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
previousOutpoint := &externalapi.DomainOutpoint{
|
||||
TransactionID: *transactionID,
|
||||
Index: input.PreviousOutpoint.Index,
|
||||
}
|
||||
signatureScript, err := hex.DecodeString(input.SignatureScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inputs[i] = &externalapi.DomainTransactionInput{
|
||||
PreviousOutpoint: *previousOutpoint,
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: input.Sequence,
|
||||
}
|
||||
}
|
||||
outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs))
|
||||
for i, output := range rpcTransaction.Outputs {
|
||||
scriptPublicKey, err := hex.DecodeString(output.ScriptPubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputs[i] = &externalapi.DomainTransactionOutput{
|
||||
Value: output.Amount,
|
||||
ScriptPublicKey: scriptPublicKey,
|
||||
}
|
||||
}
|
||||
|
||||
subnetworkIDBytes, err := hex.DecodeString(rpcTransaction.SubnetworkID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subnetworkID, err := subnetworks.FromBytes(subnetworkIDBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payloadHashBytes, err := hex.DecodeString(rpcTransaction.PayloadHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payloadHash, err := hashes.FromBytes(payloadHashBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload, err := hex.DecodeString(rpcTransaction.Payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &externalapi.DomainTransaction{
|
||||
Version: rpcTransaction.Version,
|
||||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
LockTime: rpcTransaction.LockTime,
|
||||
SubnetworkID: *subnetworkID,
|
||||
Gas: rpcTransaction.LockTime,
|
||||
PayloadHash: *payloadHash,
|
||||
Payload: payload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DomainTransactionToRPCTransaction converts DomainTransactions to RPCTransactions
|
||||
func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransaction) *RPCTransaction {
|
||||
inputs := make([]*RPCTransactionInput, len(transaction.Inputs))
|
||||
for i, input := range transaction.Inputs {
|
||||
transactionID := hex.EncodeToString(input.PreviousOutpoint.TransactionID[:])
|
||||
previousOutpoint := &RPCOutpoint{
|
||||
TransactionID: transactionID,
|
||||
Index: input.PreviousOutpoint.Index,
|
||||
}
|
||||
signatureScript := hex.EncodeToString(input.SignatureScript)
|
||||
inputs[i] = &RPCTransactionInput{
|
||||
PreviousOutpoint: previousOutpoint,
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: input.Sequence,
|
||||
}
|
||||
}
|
||||
outputs := make([]*RPCTransactionOutput, len(transaction.Outputs))
|
||||
for i, output := range transaction.Outputs {
|
||||
scriptPublicKey := hex.EncodeToString(output.ScriptPublicKey)
|
||||
outputs[i] = &RPCTransactionOutput{
|
||||
Amount: output.Value,
|
||||
ScriptPubKey: scriptPublicKey,
|
||||
}
|
||||
}
|
||||
subnetworkID := hex.EncodeToString(transaction.SubnetworkID[:])
|
||||
payloadHash := hex.EncodeToString(transaction.PayloadHash[:])
|
||||
payload := hex.EncodeToString(transaction.Payload)
|
||||
return &RPCTransaction{
|
||||
Version: transaction.Version,
|
||||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
LockTime: transaction.LockTime,
|
||||
SubnetworkID: subnetworkID,
|
||||
Gas: transaction.LockTime,
|
||||
PayloadHash: payloadHash,
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,16 @@ const (
|
||||
CmdShutDownResponseMessage
|
||||
CmdGetHeadersRequestMessage
|
||||
CmdGetHeadersResponseMessage
|
||||
CmdNotifyUTXOsChangedRequestMessage
|
||||
CmdNotifyUTXOsChangedResponseMessage
|
||||
CmdUTXOsChangedNotificationMessage
|
||||
CmdGetUTXOsByAddressesRequestMessage
|
||||
CmdGetUTXOsByAddressesResponseMessage
|
||||
CmdGetVirtualSelectedParentBlueScoreRequestMessage
|
||||
CmdGetVirtualSelectedParentBlueScoreResponseMessage
|
||||
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage
|
||||
CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage
|
||||
CmdVirtualSelectedParentBlueScoreChangedNotificationMessage
|
||||
)
|
||||
|
||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||
@ -139,53 +149,63 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{
|
||||
|
||||
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
||||
var RPCMessageCommandToString = map[MessageCommand]string{
|
||||
CmdGetCurrentNetworkRequestMessage: "GetCurrentNetworkRequest",
|
||||
CmdGetCurrentNetworkResponseMessage: "GetCurrentNetworkResponse",
|
||||
CmdSubmitBlockRequestMessage: "SubmitBlockRequest",
|
||||
CmdSubmitBlockResponseMessage: "SubmitBlockResponse",
|
||||
CmdGetBlockTemplateRequestMessage: "GetBlockTemplateRequest",
|
||||
CmdGetBlockTemplateResponseMessage: "GetBlockTemplateResponse",
|
||||
CmdGetBlockTemplateTransactionMessage: "CmdGetBlockTemplateTransaction",
|
||||
CmdNotifyBlockAddedRequestMessage: "NotifyBlockAddedRequest",
|
||||
CmdNotifyBlockAddedResponseMessage: "NotifyBlockAddedResponse",
|
||||
CmdBlockAddedNotificationMessage: "BlockAddedNotification",
|
||||
CmdGetPeerAddressesRequestMessage: "GetPeerAddressesRequest",
|
||||
CmdGetPeerAddressesResponseMessage: "GetPeerAddressesResponse",
|
||||
CmdGetSelectedTipHashRequestMessage: "GetSelectedTipHashRequest",
|
||||
CmdGetSelectedTipHashResponseMessage: "GetSelectedTipHashResponse",
|
||||
CmdGetMempoolEntryRequestMessage: "GetMempoolEntryRequest",
|
||||
CmdGetMempoolEntryResponseMessage: "GetMempoolEntryResponse",
|
||||
CmdGetConnectedPeerInfoRequestMessage: "GetConnectedPeerInfoRequest",
|
||||
CmdGetConnectedPeerInfoResponseMessage: "GetConnectedPeerInfoResponse",
|
||||
CmdAddPeerRequestMessage: "AddPeerRequest",
|
||||
CmdAddPeerResponseMessage: "AddPeerResponse",
|
||||
CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest",
|
||||
CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse",
|
||||
CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest",
|
||||
CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse",
|
||||
CmdChainChangedNotificationMessage: "ChainChangedNotification",
|
||||
CmdGetBlockRequestMessage: "GetBlockRequest",
|
||||
CmdGetBlockResponseMessage: "GetBlockResponse",
|
||||
CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest",
|
||||
CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse",
|
||||
CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest",
|
||||
CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse",
|
||||
CmdGetBlocksRequestMessage: "GetBlocksRequest",
|
||||
CmdGetBlocksResponseMessage: "GetBlocksResponse",
|
||||
CmdGetBlockCountRequestMessage: "GetBlockCountRequest",
|
||||
CmdGetBlockCountResponseMessage: "GetBlockCountResponse",
|
||||
CmdGetBlockDAGInfoRequestMessage: "GetBlockDAGInfoRequest",
|
||||
CmdGetBlockDAGInfoResponseMessage: "GetBlockDAGInfoResponse",
|
||||
CmdResolveFinalityConflictRequestMessage: "ResolveFinalityConflictRequest",
|
||||
CmdResolveFinalityConflictResponseMessage: "ResolveFinalityConflictResponse",
|
||||
CmdNotifyFinalityConflictsRequestMessage: "NotifyFinalityConflictsRequest",
|
||||
CmdNotifyFinalityConflictsResponseMessage: "NotifyFinalityConflictsResponse",
|
||||
CmdFinalityConflictNotificationMessage: "FinalityConflictNotification",
|
||||
CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification",
|
||||
CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequestMessage",
|
||||
CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponseMessage",
|
||||
CmdGetHeadersRequestMessage: "GetHeadersRequest",
|
||||
CmdGetHeadersResponseMessage: "GetHeadersResponse",
|
||||
CmdGetCurrentNetworkRequestMessage: "GetCurrentNetworkRequest",
|
||||
CmdGetCurrentNetworkResponseMessage: "GetCurrentNetworkResponse",
|
||||
CmdSubmitBlockRequestMessage: "SubmitBlockRequest",
|
||||
CmdSubmitBlockResponseMessage: "SubmitBlockResponse",
|
||||
CmdGetBlockTemplateRequestMessage: "GetBlockTemplateRequest",
|
||||
CmdGetBlockTemplateResponseMessage: "GetBlockTemplateResponse",
|
||||
CmdGetBlockTemplateTransactionMessage: "CmdGetBlockTemplateTransaction",
|
||||
CmdNotifyBlockAddedRequestMessage: "NotifyBlockAddedRequest",
|
||||
CmdNotifyBlockAddedResponseMessage: "NotifyBlockAddedResponse",
|
||||
CmdBlockAddedNotificationMessage: "BlockAddedNotification",
|
||||
CmdGetPeerAddressesRequestMessage: "GetPeerAddressesRequest",
|
||||
CmdGetPeerAddressesResponseMessage: "GetPeerAddressesResponse",
|
||||
CmdGetSelectedTipHashRequestMessage: "GetSelectedTipHashRequest",
|
||||
CmdGetSelectedTipHashResponseMessage: "GetSelectedTipHashResponse",
|
||||
CmdGetMempoolEntryRequestMessage: "GetMempoolEntryRequest",
|
||||
CmdGetMempoolEntryResponseMessage: "GetMempoolEntryResponse",
|
||||
CmdGetConnectedPeerInfoRequestMessage: "GetConnectedPeerInfoRequest",
|
||||
CmdGetConnectedPeerInfoResponseMessage: "GetConnectedPeerInfoResponse",
|
||||
CmdAddPeerRequestMessage: "AddPeerRequest",
|
||||
CmdAddPeerResponseMessage: "AddPeerResponse",
|
||||
CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest",
|
||||
CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse",
|
||||
CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest",
|
||||
CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse",
|
||||
CmdChainChangedNotificationMessage: "ChainChangedNotification",
|
||||
CmdGetBlockRequestMessage: "GetBlockRequest",
|
||||
CmdGetBlockResponseMessage: "GetBlockResponse",
|
||||
CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest",
|
||||
CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse",
|
||||
CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest",
|
||||
CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse",
|
||||
CmdGetBlocksRequestMessage: "GetBlocksRequest",
|
||||
CmdGetBlocksResponseMessage: "GetBlocksResponse",
|
||||
CmdGetBlockCountRequestMessage: "GetBlockCountRequest",
|
||||
CmdGetBlockCountResponseMessage: "GetBlockCountResponse",
|
||||
CmdGetBlockDAGInfoRequestMessage: "GetBlockDAGInfoRequest",
|
||||
CmdGetBlockDAGInfoResponseMessage: "GetBlockDAGInfoResponse",
|
||||
CmdResolveFinalityConflictRequestMessage: "ResolveFinalityConflictRequest",
|
||||
CmdResolveFinalityConflictResponseMessage: "ResolveFinalityConflictResponse",
|
||||
CmdNotifyFinalityConflictsRequestMessage: "NotifyFinalityConflictsRequest",
|
||||
CmdNotifyFinalityConflictsResponseMessage: "NotifyFinalityConflictsResponse",
|
||||
CmdFinalityConflictNotificationMessage: "FinalityConflictNotification",
|
||||
CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification",
|
||||
CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequest",
|
||||
CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponse",
|
||||
CmdGetHeadersRequestMessage: "GetHeadersRequest",
|
||||
CmdGetHeadersResponseMessage: "GetHeadersResponse",
|
||||
CmdNotifyUTXOsChangedRequestMessage: "NotifyUTXOsChangedRequest",
|
||||
CmdNotifyUTXOsChangedResponseMessage: "NotifyUTXOsChangedResponse",
|
||||
CmdUTXOsChangedNotificationMessage: "UTXOsChangedNotification",
|
||||
CmdGetUTXOsByAddressesRequestMessage: "GetUTXOsByAddressesRequest",
|
||||
CmdGetUTXOsByAddressesResponseMessage: "GetUTXOsByAddressesResponse",
|
||||
CmdGetVirtualSelectedParentBlueScoreRequestMessage: "GetVirtualSelectedParentBlueScoreRequest",
|
||||
CmdGetVirtualSelectedParentBlueScoreResponseMessage: "GetVirtualSelectedParentBlueScoreResponse",
|
||||
CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: "NotifyVirtualSelectedParentBlueScoreChangedRequest",
|
||||
CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage: "NotifyVirtualSelectedParentBlueScoreChangedResponse",
|
||||
CmdVirtualSelectedParentBlueScoreChangedNotificationMessage: "VirtualSelectedParentBlueScoreChangedNotification",
|
||||
}
|
||||
|
||||
// Message is an interface that describes a kaspa message. A type that
|
||||
|
41
app/appmessage/rpc_get_utxos_by_addresses.go
Normal file
41
app/appmessage/rpc_get_utxos_by_addresses.go
Normal file
@ -0,0 +1,41 @@
|
||||
package appmessage
|
||||
|
||||
// GetUTXOsByAddressesRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetUTXOsByAddressesRequestMessage struct {
|
||||
baseMessage
|
||||
Addresses []string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetUTXOsByAddressesRequestMessage) Command() MessageCommand {
|
||||
return CmdGetUTXOsByAddressesRequestMessage
|
||||
}
|
||||
|
||||
// NewGetUTXOsByAddressesRequestMessage returns a instance of the message
|
||||
func NewGetUTXOsByAddressesRequestMessage(addresses []string) *GetUTXOsByAddressesRequestMessage {
|
||||
return &GetUTXOsByAddressesRequestMessage{
|
||||
Addresses: addresses,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUTXOsByAddressesResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetUTXOsByAddressesResponseMessage struct {
|
||||
baseMessage
|
||||
Entries []*UTXOsByAddressesEntry
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetUTXOsByAddressesResponseMessage) Command() MessageCommand {
|
||||
return CmdGetUTXOsByAddressesResponseMessage
|
||||
}
|
||||
|
||||
// NewGetUTXOsByAddressesResponseMessage returns a instance of the message
|
||||
func NewGetUTXOsByAddressesResponseMessage(entries []*UTXOsByAddressesEntry) *GetUTXOsByAddressesResponseMessage {
|
||||
return &GetUTXOsByAddressesResponseMessage{
|
||||
Entries: entries,
|
||||
}
|
||||
}
|
38
app/appmessage/rpc_get_virtual_selected_parent_blue_score.go
Normal file
38
app/appmessage/rpc_get_virtual_selected_parent_blue_score.go
Normal file
@ -0,0 +1,38 @@
|
||||
package appmessage
|
||||
|
||||
// GetVirtualSelectedParentBlueScoreRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetVirtualSelectedParentBlueScoreRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetVirtualSelectedParentBlueScoreRequestMessage) Command() MessageCommand {
|
||||
return CmdGetVirtualSelectedParentBlueScoreRequestMessage
|
||||
}
|
||||
|
||||
// NewGetVirtualSelectedParentBlueScoreRequestMessage returns a instance of the message
|
||||
func NewGetVirtualSelectedParentBlueScoreRequestMessage() *GetVirtualSelectedParentBlueScoreRequestMessage {
|
||||
return &GetVirtualSelectedParentBlueScoreRequestMessage{}
|
||||
}
|
||||
|
||||
// GetVirtualSelectedParentBlueScoreResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetVirtualSelectedParentBlueScoreResponseMessage struct {
|
||||
baseMessage
|
||||
BlueScore uint64
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetVirtualSelectedParentBlueScoreResponseMessage) Command() MessageCommand {
|
||||
return CmdGetVirtualSelectedParentBlueScoreResponseMessage
|
||||
}
|
||||
|
||||
// NewGetVirtualSelectedParentBlueScoreResponseMessage returns a instance of the message
|
||||
func NewGetVirtualSelectedParentBlueScoreResponseMessage(blueScore uint64) *GetVirtualSelectedParentBlueScoreResponseMessage {
|
||||
return &GetVirtualSelectedParentBlueScoreResponseMessage{
|
||||
BlueScore: blueScore,
|
||||
}
|
||||
}
|
62
app/appmessage/rpc_notify_utxos_changed.go
Normal file
62
app/appmessage/rpc_notify_utxos_changed.go
Normal file
@ -0,0 +1,62 @@
|
||||
package appmessage
|
||||
|
||||
// NotifyUTXOsChangedRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyUTXOsChangedRequestMessage struct {
|
||||
baseMessage
|
||||
Addresses []string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyUTXOsChangedRequestMessage) Command() MessageCommand {
|
||||
return CmdNotifyUTXOsChangedRequestMessage
|
||||
}
|
||||
|
||||
// NewNotifyUTXOsChangedRequestMessage returns a instance of the message
|
||||
func NewNotifyUTXOsChangedRequestMessage(addresses []string) *NotifyUTXOsChangedRequestMessage {
|
||||
return &NotifyUTXOsChangedRequestMessage{
|
||||
Addresses: addresses,
|
||||
}
|
||||
}
|
||||
|
||||
// NotifyUTXOsChangedResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyUTXOsChangedResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyUTXOsChangedResponseMessage) Command() MessageCommand {
|
||||
return CmdNotifyUTXOsChangedResponseMessage
|
||||
}
|
||||
|
||||
// NewNotifyUTXOsChangedResponseMessage returns a instance of the message
|
||||
func NewNotifyUTXOsChangedResponseMessage() *NotifyUTXOsChangedResponseMessage {
|
||||
return &NotifyUTXOsChangedResponseMessage{}
|
||||
}
|
||||
|
||||
// UTXOsChangedNotificationMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type UTXOsChangedNotificationMessage struct {
|
||||
baseMessage
|
||||
Added []*UTXOsByAddressesEntry
|
||||
Removed []*UTXOsByAddressesEntry
|
||||
}
|
||||
|
||||
// UTXOsByAddressesEntry represents a UTXO of some address
|
||||
type UTXOsByAddressesEntry struct {
|
||||
Address string
|
||||
Outpoint *RPCOutpoint
|
||||
UTXOEntry *RPCUTXOEntry
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *UTXOsChangedNotificationMessage) Command() MessageCommand {
|
||||
return CmdUTXOsChangedNotificationMessage
|
||||
}
|
||||
|
||||
// NewUTXOsChangedNotificationMessage returns a instance of the message
|
||||
func NewUTXOsChangedNotificationMessage() *UTXOsChangedNotificationMessage {
|
||||
return &UTXOsChangedNotificationMessage{}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package appmessage
|
||||
|
||||
// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Command() MessageCommand {
|
||||
return CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage
|
||||
}
|
||||
|
||||
// NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage returns a instance of the message
|
||||
func NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage() *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage {
|
||||
return &NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{}
|
||||
}
|
||||
|
||||
// NotifyVirtualSelectedParentBlueScoreChangedResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Command() MessageCommand {
|
||||
return CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage
|
||||
}
|
||||
|
||||
// NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage returns a instance of the message
|
||||
func NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage() *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage {
|
||||
return &NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{}
|
||||
}
|
||||
|
||||
// VirtualSelectedParentBlueScoreChangedNotificationMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type VirtualSelectedParentBlueScoreChangedNotificationMessage struct {
|
||||
baseMessage
|
||||
VirtualSelectedParentBlueScore uint64
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *VirtualSelectedParentBlueScoreChangedNotificationMessage) Command() MessageCommand {
|
||||
return CmdVirtualSelectedParentBlueScoreChangedNotificationMessage
|
||||
}
|
||||
|
||||
// NewVirtualSelectedParentBlueScoreChangedNotificationMessage returns a instance of the message
|
||||
func NewVirtualSelectedParentBlueScoreChangedNotificationMessage(
|
||||
virtualSelectedParentBlueScore uint64) *VirtualSelectedParentBlueScoreChangedNotificationMessage {
|
||||
|
||||
return &VirtualSelectedParentBlueScoreChangedNotificationMessage{
|
||||
VirtualSelectedParentBlueScore: virtualSelectedParentBlueScore,
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ package appmessage
|
||||
// its respective RPC message
|
||||
type SubmitTransactionRequestMessage struct {
|
||||
baseMessage
|
||||
Transaction *MsgTx
|
||||
Transaction *RPCTransaction
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
@ -13,7 +13,7 @@ func (msg *SubmitTransactionRequestMessage) Command() MessageCommand {
|
||||
}
|
||||
|
||||
// NewSubmitTransactionRequestMessage returns a instance of the message
|
||||
func NewSubmitTransactionRequestMessage(transaction *MsgTx) *SubmitTransactionRequestMessage {
|
||||
func NewSubmitTransactionRequestMessage(transaction *RPCTransaction) *SubmitTransactionRequestMessage {
|
||||
return &SubmitTransactionRequestMessage{
|
||||
Transaction: transaction,
|
||||
}
|
||||
@ -23,7 +23,7 @@ func NewSubmitTransactionRequestMessage(transaction *MsgTx) *SubmitTransactionRe
|
||||
// its respective RPC message
|
||||
type SubmitTransactionResponseMessage struct {
|
||||
baseMessage
|
||||
TxID string
|
||||
TransactionID string
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
@ -34,8 +34,52 @@ func (msg *SubmitTransactionResponseMessage) Command() MessageCommand {
|
||||
}
|
||||
|
||||
// NewSubmitTransactionResponseMessage returns a instance of the message
|
||||
func NewSubmitTransactionResponseMessage(txID string) *SubmitTransactionResponseMessage {
|
||||
func NewSubmitTransactionResponseMessage(transactionID string) *SubmitTransactionResponseMessage {
|
||||
return &SubmitTransactionResponseMessage{
|
||||
TxID: txID,
|
||||
TransactionID: transactionID,
|
||||
}
|
||||
}
|
||||
|
||||
// RPCTransaction is a kaspad transaction representation meant to be
|
||||
// used over RPC
|
||||
type RPCTransaction struct {
|
||||
Version int32
|
||||
Inputs []*RPCTransactionInput
|
||||
Outputs []*RPCTransactionOutput
|
||||
LockTime uint64
|
||||
SubnetworkID string
|
||||
Gas uint64
|
||||
PayloadHash string
|
||||
Payload string
|
||||
}
|
||||
|
||||
// RPCTransactionInput is a kaspad transaction input representation
|
||||
// meant to be used over RPC
|
||||
type RPCTransactionInput struct {
|
||||
PreviousOutpoint *RPCOutpoint
|
||||
SignatureScript string
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
// RPCTransactionOutput is a kaspad transaction output representation
|
||||
// meant to be used over RPC
|
||||
type RPCTransactionOutput struct {
|
||||
Amount uint64
|
||||
ScriptPubKey string
|
||||
}
|
||||
|
||||
// RPCOutpoint is a kaspad outpoint representation meant to be used
|
||||
// over RPC
|
||||
type RPCOutpoint struct {
|
||||
TransactionID string
|
||||
Index uint32
|
||||
}
|
||||
|
||||
// RPCUTXOEntry is a kaspad utxo entry representation meant to be used
|
||||
// over RPC
|
||||
type RPCUTXOEntry struct {
|
||||
Amount uint64
|
||||
ScriptPubKey string
|
||||
BlockBlueScore uint64
|
||||
IsCoinbase bool
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
"sync/atomic"
|
||||
|
||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
@ -93,6 +94,12 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var utxoIndex *utxoindex.UTXOIndex
|
||||
if cfg.UTXOIndex {
|
||||
utxoIndex = utxoindex.New(domain.Consensus(), db)
|
||||
log.Infof("UTXO index started")
|
||||
}
|
||||
|
||||
connectionManager, err := connmanager.New(cfg, netAdapter, addressManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -101,7 +108,7 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, interrupt)
|
||||
rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, utxoIndex, interrupt)
|
||||
|
||||
return &ComponentManager{
|
||||
cfg: cfg,
|
||||
@ -121,11 +128,20 @@ func setupRPC(
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
utxoIndex *utxoindex.UTXOIndex,
|
||||
shutDownChan chan<- struct{},
|
||||
) *rpc.Manager {
|
||||
|
||||
rpcManager := rpc.NewManager(
|
||||
cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, shutDownChan)
|
||||
cfg,
|
||||
domain,
|
||||
netAdapter,
|
||||
protocolManager,
|
||||
connectionManager,
|
||||
addressManager,
|
||||
utxoIndex,
|
||||
shutDownChan,
|
||||
)
|
||||
protocolManager.SetOnBlockAddedToDAGHandler(rpcManager.NotifyBlockAddedToDAG)
|
||||
|
||||
return rpcManager
|
||||
|
@ -17,7 +17,9 @@ import (
|
||||
// OnNewBlock updates the mempool after a new block arrival, and
|
||||
// relays newly unorphaned transactions and possibly rebroadcast
|
||||
// manually added transactions when not in IBD.
|
||||
func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error {
|
||||
func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock,
|
||||
blockInsertionResult *externalapi.BlockInsertionResult) error {
|
||||
|
||||
hash := consensushashing.BlockHash(block)
|
||||
log.Debugf("OnNewBlock start for block %s", hash)
|
||||
defer log.Debugf("OnNewBlock end for block %s", hash)
|
||||
@ -37,7 +39,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error {
|
||||
|
||||
if f.onBlockAddedToDAGHandler != nil {
|
||||
log.Tracef("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash)
|
||||
err := f.onBlockAddedToDAGHandler(newBlock)
|
||||
err := f.onBlockAddedToDAGHandler(newBlock, blockInsertionResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -89,7 +91,7 @@ func (f *FlowContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks
|
||||
|
||||
// AddBlock adds the given block to the DAG and propagates it.
|
||||
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
||||
_, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
log.Infof("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)
|
||||
@ -97,7 +99,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = f.OnNewBlock(block)
|
||||
err = f.OnNewBlock(block, blockInsertionResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
|
||||
// OnBlockAddedToDAGHandler is a handler function that's triggered
|
||||
// when a block is added to the DAG
|
||||
type OnBlockAddedToDAGHandler func(block *externalapi.DomainBlock) error
|
||||
type OnBlockAddedToDAGHandler func(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error
|
||||
|
||||
// OnTransactionAddedToMempoolHandler is a handler function that's triggered
|
||||
// when a transaction is added to the mempool
|
||||
|
@ -25,7 +25,7 @@ type RelayInvsContext interface {
|
||||
Domain() domain.Domain
|
||||
Config() *config.Config
|
||||
NetAdapter() *netadapter.NetAdapter
|
||||
OnNewBlock(block *externalapi.DomainBlock) error
|
||||
OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error
|
||||
SharedRequestedBlocks() *SharedRequestedBlocks
|
||||
Broadcast(message appmessage.Message) error
|
||||
AddOrphan(orphanBlock *externalapi.DomainBlock)
|
||||
@ -102,7 +102,7 @@ func (flow *handleRelayInvsFlow) start() error {
|
||||
}
|
||||
|
||||
log.Debugf("Processing block %s", inv.Hash)
|
||||
missingParents, err := flow.processBlock(block)
|
||||
missingParents, blockInsertionResult, err := flow.processBlock(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -121,7 +121,7 @@ func (flow *handleRelayInvsFlow) start() error {
|
||||
return err
|
||||
}
|
||||
log.Infof("Accepted block %s via relay", inv.Hash)
|
||||
err = flow.OnNewBlock(block)
|
||||
err = flow.OnNewBlock(block, blockInsertionResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -199,22 +199,22 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
|
||||
}
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
|
||||
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) {
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
_, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
||||
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||
return nil, nil, errors.Wrapf(err, "failed to process block %s", blockHash)
|
||||
}
|
||||
|
||||
missingParentsError := &ruleerrors.ErrMissingParents{}
|
||||
if errors.As(err, missingParentsError) {
|
||||
return missingParentsError.MissingParentHashes, nil
|
||||
return missingParentsError.MissingParentHashes, nil, nil
|
||||
}
|
||||
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
||||
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||
return nil, nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||
}
|
||||
return nil, nil
|
||||
return nil, blockInsertionResult, nil
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) error {
|
||||
|
@ -283,11 +283,11 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
|
||||
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
|
||||
}
|
||||
|
||||
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||
if err != nil {
|
||||
return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash)
|
||||
}
|
||||
err = flow.OnNewBlock(block)
|
||||
err = flow.OnNewBlock(block, blockInsertionResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ import (
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
@ -25,6 +27,7 @@ func NewManager(
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
utxoIndex *utxoindex.UTXOIndex,
|
||||
shutDownChan chan<- struct{}) *Manager {
|
||||
|
||||
manager := Manager{
|
||||
@ -35,6 +38,7 @@ func NewManager(
|
||||
protocolManager,
|
||||
connectionManager,
|
||||
addressManager,
|
||||
utxoIndex,
|
||||
shutDownChan,
|
||||
),
|
||||
}
|
||||
@ -44,19 +48,63 @@ func NewManager(
|
||||
}
|
||||
|
||||
// NotifyBlockAddedToDAG notifies the manager that a block has been added to the DAG
|
||||
func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock) error {
|
||||
notification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block))
|
||||
return m.context.NotificationManager.NotifyBlockAdded(notification)
|
||||
func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyBlockAddedToDAG")
|
||||
defer onEnd()
|
||||
|
||||
if m.context.Config.UTXOIndex {
|
||||
err := m.notifyUTXOsChanged(blockInsertionResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := m.notifyVirtualSelectedParentBlueScoreChanged()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block))
|
||||
return m.context.NotificationManager.NotifyBlockAdded(blockAddedNotification)
|
||||
}
|
||||
|
||||
// NotifyFinalityConflict notifies the manager that there's a finality conflict in the DAG
|
||||
func (m *Manager) NotifyFinalityConflict(violatingBlockHash string) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyFinalityConflict")
|
||||
defer onEnd()
|
||||
|
||||
notification := appmessage.NewFinalityConflictNotificationMessage(violatingBlockHash)
|
||||
return m.context.NotificationManager.NotifyFinalityConflict(notification)
|
||||
}
|
||||
|
||||
// NotifyFinalityConflictResolved notifies the manager that a finality conflict in the DAG has been resolved
|
||||
func (m *Manager) NotifyFinalityConflictResolved(finalityBlockHash string) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyFinalityConflictResolved")
|
||||
defer onEnd()
|
||||
|
||||
notification := appmessage.NewFinalityConflictResolvedNotificationMessage(finalityBlockHash)
|
||||
return m.context.NotificationManager.NotifyFinalityConflictResolved(notification)
|
||||
}
|
||||
|
||||
func (m *Manager) notifyUTXOsChanged(blockInsertionResult *externalapi.BlockInsertionResult) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyUTXOsChanged")
|
||||
defer onEnd()
|
||||
|
||||
utxoIndexChanges, err := m.context.UTXOIndex.Update(blockInsertionResult.SelectedParentChainChanges)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.context.NotificationManager.NotifyUTXOsChanged(utxoIndexChanges)
|
||||
}
|
||||
|
||||
func (m *Manager) notifyVirtualSelectedParentBlueScoreChanged() error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentBlueScoreChanged")
|
||||
defer onEnd()
|
||||
|
||||
virtualInfo, err := m.context.Domain.Consensus().GetVirtualInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notification := appmessage.NewVirtualSelectedParentBlueScoreChangedNotificationMessage(virtualInfo.BlueScore)
|
||||
return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification)
|
||||
}
|
||||
|
@ -12,28 +12,32 @@ import (
|
||||
type handler func(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error)
|
||||
|
||||
var handlers = map[appmessage.MessageCommand]handler{
|
||||
appmessage.CmdGetCurrentNetworkRequestMessage: rpchandlers.HandleGetCurrentNetwork,
|
||||
appmessage.CmdSubmitBlockRequestMessage: rpchandlers.HandleSubmitBlock,
|
||||
appmessage.CmdGetBlockTemplateRequestMessage: rpchandlers.HandleGetBlockTemplate,
|
||||
appmessage.CmdNotifyBlockAddedRequestMessage: rpchandlers.HandleNotifyBlockAdded,
|
||||
appmessage.CmdGetPeerAddressesRequestMessage: rpchandlers.HandleGetPeerAddresses,
|
||||
appmessage.CmdGetSelectedTipHashRequestMessage: rpchandlers.HandleGetSelectedTipHash,
|
||||
appmessage.CmdGetMempoolEntryRequestMessage: rpchandlers.HandleGetMempoolEntry,
|
||||
appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo,
|
||||
appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer,
|
||||
appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction,
|
||||
appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged,
|
||||
appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock,
|
||||
appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork,
|
||||
appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock,
|
||||
appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks,
|
||||
appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount,
|
||||
appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo,
|
||||
appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict,
|
||||
appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts,
|
||||
appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries,
|
||||
appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown,
|
||||
appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders,
|
||||
appmessage.CmdGetCurrentNetworkRequestMessage: rpchandlers.HandleGetCurrentNetwork,
|
||||
appmessage.CmdSubmitBlockRequestMessage: rpchandlers.HandleSubmitBlock,
|
||||
appmessage.CmdGetBlockTemplateRequestMessage: rpchandlers.HandleGetBlockTemplate,
|
||||
appmessage.CmdNotifyBlockAddedRequestMessage: rpchandlers.HandleNotifyBlockAdded,
|
||||
appmessage.CmdGetPeerAddressesRequestMessage: rpchandlers.HandleGetPeerAddresses,
|
||||
appmessage.CmdGetSelectedTipHashRequestMessage: rpchandlers.HandleGetSelectedTipHash,
|
||||
appmessage.CmdGetMempoolEntryRequestMessage: rpchandlers.HandleGetMempoolEntry,
|
||||
appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo,
|
||||
appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer,
|
||||
appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction,
|
||||
appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged,
|
||||
appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock,
|
||||
appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork,
|
||||
appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock,
|
||||
appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks,
|
||||
appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount,
|
||||
appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo,
|
||||
appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict,
|
||||
appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts,
|
||||
appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries,
|
||||
appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown,
|
||||
appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders,
|
||||
appmessage.CmdNotifyUTXOsChangedRequestMessage: rpchandlers.HandleNotifyUTXOsChanged,
|
||||
appmessage.CmdGetUTXOsByAddressesRequestMessage: rpchandlers.HandleGetUTXOsByAddresses,
|
||||
appmessage.CmdGetVirtualSelectedParentBlueScoreRequestMessage: rpchandlers.HandleGetVirtualSelectedParentBlueScore,
|
||||
appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentBlueScoreChanged,
|
||||
}
|
||||
|
||||
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
||||
|
@ -3,6 +3,7 @@ package rpccontext
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
@ -17,6 +18,7 @@ type Context struct {
|
||||
ProtocolManager *protocol.Manager
|
||||
ConnectionManager *connmanager.ConnectionManager
|
||||
AddressManager *addressmanager.AddressManager
|
||||
UTXOIndex *utxoindex.UTXOIndex
|
||||
ShutDownChan chan<- struct{}
|
||||
|
||||
NotificationManager *NotificationManager
|
||||
@ -29,6 +31,7 @@ func NewContext(cfg *config.Config,
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
utxoIndex *utxoindex.UTXOIndex,
|
||||
shutDownChan chan<- struct{}) *Context {
|
||||
|
||||
context := &Context{
|
||||
@ -38,8 +41,10 @@ func NewContext(cfg *config.Config,
|
||||
ProtocolManager: protocolManager,
|
||||
ConnectionManager: connectionManager,
|
||||
AddressManager: addressManager,
|
||||
UTXOIndex: utxoIndex,
|
||||
ShutDownChan: shutDownChan,
|
||||
}
|
||||
context.NotificationManager = NewNotificationManager()
|
||||
|
||||
return context
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
"sync"
|
||||
@ -13,12 +15,23 @@ type NotificationManager struct {
|
||||
listeners map[*routerpkg.Router]*NotificationListener
|
||||
}
|
||||
|
||||
// UTXOsChangedNotificationAddress represents a kaspad address.
|
||||
// This type is meant to be used in UTXOsChanged notifications
|
||||
type UTXOsChangedNotificationAddress struct {
|
||||
Address string
|
||||
ScriptPublicKeyString utxoindex.ScriptPublicKeyString
|
||||
}
|
||||
|
||||
// NotificationListener represents a registered RPC notification listener
|
||||
type NotificationListener struct {
|
||||
propagateBlockAddedNotifications bool
|
||||
propagateChainChangedNotifications bool
|
||||
propagateFinalityConflictNotifications bool
|
||||
propagateFinalityConflictResolvedNotifications bool
|
||||
propagateBlockAddedNotifications bool
|
||||
propagateChainChangedNotifications bool
|
||||
propagateFinalityConflictNotifications bool
|
||||
propagateFinalityConflictResolvedNotifications bool
|
||||
propagateUTXOsChangedNotifications bool
|
||||
propagateVirtualSelectedParentBlueScoreChangedNotifications bool
|
||||
|
||||
propagateUTXOsChangedNotificationAddresses []*UTXOsChangedNotificationAddress
|
||||
}
|
||||
|
||||
// NewNotificationManager creates a new NotificationManager
|
||||
@ -123,12 +136,58 @@ func (nm *NotificationManager) NotifyFinalityConflictResolved(notification *appm
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyUTXOsChanged notifies the notification manager that UTXOs have been changed
|
||||
func (nm *NotificationManager) NotifyUTXOsChanged(utxoChanges *utxoindex.UTXOChanges) error {
|
||||
nm.RLock()
|
||||
defer nm.RUnlock()
|
||||
|
||||
for router, listener := range nm.listeners {
|
||||
if listener.propagateUTXOsChangedNotifications {
|
||||
// Filter utxoChanges and create a notification
|
||||
notification := listener.convertUTXOChangesToUTXOsChangedNotification(utxoChanges)
|
||||
|
||||
// Don't send the notification if it's empty
|
||||
if len(notification.Added) == 0 && len(notification.Removed) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Enqueue the notification
|
||||
err := router.OutgoingRoute().Enqueue(notification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyVirtualSelectedParentBlueScoreChanged notifies the notification manager that the DAG's
|
||||
// virtual selected parent blue score has changed
|
||||
func (nm *NotificationManager) NotifyVirtualSelectedParentBlueScoreChanged(
|
||||
notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) error {
|
||||
|
||||
nm.RLock()
|
||||
defer nm.RUnlock()
|
||||
|
||||
for router, listener := range nm.listeners {
|
||||
if listener.propagateVirtualSelectedParentBlueScoreChangedNotifications {
|
||||
err := router.OutgoingRoute().Enqueue(notification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newNotificationListener() *NotificationListener {
|
||||
return &NotificationListener{
|
||||
propagateBlockAddedNotifications: false,
|
||||
propagateChainChangedNotifications: false,
|
||||
propagateFinalityConflictNotifications: false,
|
||||
propagateFinalityConflictResolvedNotifications: false,
|
||||
propagateBlockAddedNotifications: false,
|
||||
propagateChainChangedNotifications: false,
|
||||
propagateFinalityConflictNotifications: false,
|
||||
propagateFinalityConflictResolvedNotifications: false,
|
||||
propagateUTXOsChangedNotifications: false,
|
||||
propagateVirtualSelectedParentBlueScoreChangedNotifications: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,3 +214,40 @@ func (nl *NotificationListener) PropagateFinalityConflictNotifications() {
|
||||
func (nl *NotificationListener) PropagateFinalityConflictResolvedNotifications() {
|
||||
nl.propagateFinalityConflictResolvedNotifications = true
|
||||
}
|
||||
|
||||
// PropagateUTXOsChangedNotifications instructs the listener to send UTXOs changed notifications
|
||||
// to the remote listener
|
||||
func (nl *NotificationListener) PropagateUTXOsChangedNotifications(addresses []*UTXOsChangedNotificationAddress) {
|
||||
nl.propagateUTXOsChangedNotifications = true
|
||||
nl.propagateUTXOsChangedNotificationAddresses = addresses
|
||||
}
|
||||
|
||||
func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification(
|
||||
utxoChanges *utxoindex.UTXOChanges) *appmessage.UTXOsChangedNotificationMessage {
|
||||
|
||||
notification := &appmessage.UTXOsChangedNotificationMessage{}
|
||||
for _, listenerAddress := range nl.propagateUTXOsChangedNotificationAddresses {
|
||||
listenerScriptPublicKeyString := listenerAddress.ScriptPublicKeyString
|
||||
if addedPairs, ok := utxoChanges.Added[listenerScriptPublicKeyString]; ok {
|
||||
notification.Added = ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs)
|
||||
}
|
||||
if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok {
|
||||
for outpoint := range removedOutpoints {
|
||||
notification.Removed = append(notification.Removed, &appmessage.UTXOsByAddressesEntry{
|
||||
Address: listenerAddress.Address,
|
||||
Outpoint: &appmessage.RPCOutpoint{
|
||||
TransactionID: hex.EncodeToString(outpoint.TransactionID[:]),
|
||||
Index: outpoint.Index,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return notification
|
||||
}
|
||||
|
||||
// PropagateVirtualSelectedParentBlueScoreChangedNotifications instructs the listener to send
|
||||
// virtual selected parent blue score notifications to the remote listener
|
||||
func (nl *NotificationListener) PropagateVirtualSelectedParentBlueScoreChangedNotifications() {
|
||||
nl.propagateVirtualSelectedParentBlueScoreChangedNotifications = true
|
||||
}
|
||||
|
29
app/rpc/rpccontext/utxos_by_addresses.go
Normal file
29
app/rpc/rpccontext/utxos_by_addresses.go
Normal file
@ -0,0 +1,29 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
)
|
||||
|
||||
// ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries converts
|
||||
// UTXOOutpointEntryPairs to a slice of UTXOsByAddressesEntry
|
||||
func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pairs utxoindex.UTXOOutpointEntryPairs) []*appmessage.UTXOsByAddressesEntry {
|
||||
utxosByAddressesEntries := make([]*appmessage.UTXOsByAddressesEntry, 0, len(pairs))
|
||||
for outpoint, utxoEntry := range pairs {
|
||||
utxosByAddressesEntries = append(utxosByAddressesEntries, &appmessage.UTXOsByAddressesEntry{
|
||||
Address: address,
|
||||
Outpoint: &appmessage.RPCOutpoint{
|
||||
TransactionID: hex.EncodeToString(outpoint.TransactionID[:]),
|
||||
Index: outpoint.Index,
|
||||
},
|
||||
UTXOEntry: &appmessage.RPCUTXOEntry{
|
||||
Amount: utxoEntry.Amount(),
|
||||
ScriptPubKey: hex.EncodeToString(utxoEntry.ScriptPublicKey()),
|
||||
BlockBlueScore: utxoEntry.BlockBlueScore(),
|
||||
IsCoinbase: utxoEntry.IsCoinbase(),
|
||||
},
|
||||
})
|
||||
}
|
||||
return utxosByAddressesEntries
|
||||
}
|
45
app/rpc/rpchandlers/get_utxos_by_addresses.go
Normal file
45
app/rpc/rpchandlers/get_utxos_by_addresses.go
Normal file
@ -0,0 +1,45 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
// HandleGetUTXOsByAddresses handles the respectively named RPC command
|
||||
func HandleGetUTXOsByAddresses(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
if !context.Config.UTXOIndex {
|
||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
getUTXOsByAddressesRequest := request.(*appmessage.GetUTXOsByAddressesRequestMessage)
|
||||
|
||||
allEntries := make([]*appmessage.UTXOsByAddressesEntry, 0)
|
||||
for _, addressString := range getUTXOsByAddressesRequest.Addresses {
|
||||
address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
scriptPublicKey, err := txscript.PayToAddrScript(address)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
utxoOutpointEntryPairs, err := context.UTXOIndex.UTXOs(scriptPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries := rpccontext.ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(addressString, utxoOutpointEntryPairs)
|
||||
allEntries = append(allEntries, entries...)
|
||||
}
|
||||
|
||||
response := appmessage.NewGetUTXOsByAddressesResponseMessage(allEntries)
|
||||
return response, nil
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetVirtualSelectedParentBlueScore handles the respectively named RPC command
|
||||
func HandleGetVirtualSelectedParentBlueScore(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
virtualInfo, err := context.Domain.Consensus().GetVirtualInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appmessage.NewGetVirtualSelectedParentBlueScoreResponseMessage(virtualInfo.BlueScore), nil
|
||||
}
|
51
app/rpc/rpchandlers/notify_utxos_changed.go
Normal file
51
app/rpc/rpchandlers/notify_utxos_changed.go
Normal file
@ -0,0 +1,51 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
// HandleNotifyUTXOsChanged handles the respectively named RPC command
|
||||
func HandleNotifyUTXOsChanged(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
if !context.Config.UTXOIndex {
|
||||
errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage()
|
||||
errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
notifyUTXOsChangedRequest := request.(*appmessage.NotifyUTXOsChangedRequestMessage)
|
||||
|
||||
addresses := make([]*rpccontext.UTXOsChangedNotificationAddress, len(notifyUTXOsChangedRequest.Addresses))
|
||||
for i, addressString := range notifyUTXOsChangedRequest.Addresses {
|
||||
address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix)
|
||||
if err != nil {
|
||||
errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage()
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
scriptPublicKey, err := txscript.PayToAddrScript(address)
|
||||
if err != nil {
|
||||
errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage()
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
scriptPublicKeyString := utxoindex.ConvertScriptPublicKeyToString(scriptPublicKey)
|
||||
addresses[i] = &rpccontext.UTXOsChangedNotificationAddress{
|
||||
Address: addressString,
|
||||
ScriptPublicKeyString: scriptPublicKeyString,
|
||||
}
|
||||
}
|
||||
|
||||
listener, err := context.NotificationManager.Listener(router)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listener.PropagateUTXOsChangedNotifications(addresses)
|
||||
|
||||
response := appmessage.NewNotifyUTXOsChangedResponseMessage()
|
||||
return response, nil
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleNotifyVirtualSelectedParentBlueScoreChanged handles the respectively named RPC command
|
||||
func HandleNotifyVirtualSelectedParentBlueScoreChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
listener, err := context.NotificationManager.Listener(router)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listener.PropagateVirtualSelectedParentBlueScoreChangedNotifications()
|
||||
|
||||
response := appmessage.NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage()
|
||||
return response, nil
|
||||
}
|
@ -13,9 +13,15 @@ import (
|
||||
func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
submitTransactionRequest := request.(*appmessage.SubmitTransactionRequestMessage)
|
||||
|
||||
domainTransaction := appmessage.MsgTxToDomainTransaction(submitTransactionRequest.Transaction)
|
||||
domainTransaction, err := appmessage.RPCTransactionToDomainTransaction(submitTransactionRequest.Transaction)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitTransactionResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse transaction: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
transactionID := consensushashing.TransactionID(domainTransaction)
|
||||
err := context.ProtocolManager.AddTransaction(domainTransaction)
|
||||
err = context.ProtocolManager.AddTransaction(domainTransaction)
|
||||
if err != nil {
|
||||
if !errors.As(err, &mempool.RuleError{}) {
|
||||
return nil, err
|
||||
|
@ -141,6 +141,13 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
|
||||
return blockInfo, nil
|
||||
}
|
||||
|
||||
func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.acceptanceDataStore.Get(s.databaseContext, blockHash)
|
||||
}
|
||||
|
||||
func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
@ -196,10 +203,16 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
|
||||
}
|
||||
|
||||
func (s *consensus) Tips() ([]*externalapi.DomainHash, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.consensusStateStore.Tips(s.databaseContext)
|
||||
}
|
||||
|
||||
func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
blockRelations, err := s.blockRelationStore.BlockRelation(s.databaseContext, model.VirtualBlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -212,11 +225,16 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
virtualGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, model.VirtualBlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &externalapi.VirtualInfo{
|
||||
ParentHashes: blockRelations.Parents,
|
||||
Bits: bits,
|
||||
PastMedianTime: pastMedianTime,
|
||||
BlueScore: virtualGHOSTDAGData.BlueScore(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package serialization
|
||||
|
||||
import "github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
)
|
||||
|
||||
// DomainAcceptanceDataToDbAcceptanceData converts model.AcceptanceData to DbAcceptanceData
|
||||
func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData model.AcceptanceData) *DbAcceptanceData {
|
||||
func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData externalapi.AcceptanceData) *DbAcceptanceData {
|
||||
dbBlockAcceptanceData := make([]*DbBlockAcceptanceData, len(domainAcceptanceData))
|
||||
for i, blockAcceptanceData := range domainAcceptanceData {
|
||||
dbTransactionAcceptanceData := make([]*DbTransactionAcceptanceData,
|
||||
@ -29,10 +31,10 @@ func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData model.Acceptanc
|
||||
}
|
||||
|
||||
// DbAcceptanceDataToDomainAcceptanceData converts DbAcceptanceData to model.AcceptanceData
|
||||
func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) (model.AcceptanceData, error) {
|
||||
domainAcceptanceData := make(model.AcceptanceData, len(dbAcceptanceData.BlockAcceptanceData))
|
||||
func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) (externalapi.AcceptanceData, error) {
|
||||
domainAcceptanceData := make(externalapi.AcceptanceData, len(dbAcceptanceData.BlockAcceptanceData))
|
||||
for i, dbBlockAcceptanceData := range dbAcceptanceData.BlockAcceptanceData {
|
||||
domainTransactionAcceptanceData := make([]*model.TransactionAcceptanceData,
|
||||
domainTransactionAcceptanceData := make([]*externalapi.TransactionAcceptanceData,
|
||||
len(dbBlockAcceptanceData.TransactionAcceptanceData))
|
||||
|
||||
for j, dbTransactionAcceptanceData := range dbBlockAcceptanceData.TransactionAcceptanceData {
|
||||
@ -40,14 +42,14 @@ func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainTransactionAcceptanceData[j] = &model.TransactionAcceptanceData{
|
||||
domainTransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{
|
||||
Transaction: domainTransaction,
|
||||
Fee: dbTransactionAcceptanceData.Fee,
|
||||
IsAccepted: dbTransactionAcceptanceData.IsAccepted,
|
||||
}
|
||||
}
|
||||
|
||||
domainAcceptanceData[i] = &model.BlockAcceptanceData{
|
||||
domainAcceptanceData[i] = &externalapi.BlockAcceptanceData{
|
||||
TransactionAcceptanceData: domainTransactionAcceptanceData,
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ var bucket = dbkeys.MakeBucket([]byte("acceptance-data"))
|
||||
|
||||
// acceptanceDataStore represents a store of AcceptanceData
|
||||
type acceptanceDataStore struct {
|
||||
staging map[externalapi.DomainHash]model.AcceptanceData
|
||||
staging map[externalapi.DomainHash]externalapi.AcceptanceData
|
||||
toDelete map[externalapi.DomainHash]struct{}
|
||||
cache *lrucache.LRUCache
|
||||
}
|
||||
@ -21,14 +21,14 @@ type acceptanceDataStore struct {
|
||||
// New instantiates a new AcceptanceDataStore
|
||||
func New(cacheSize int) model.AcceptanceDataStore {
|
||||
return &acceptanceDataStore{
|
||||
staging: make(map[externalapi.DomainHash]model.AcceptanceData),
|
||||
staging: make(map[externalapi.DomainHash]externalapi.AcceptanceData),
|
||||
toDelete: make(map[externalapi.DomainHash]struct{}),
|
||||
cache: lrucache.New(cacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
// Stage stages the given acceptanceData for the given blockHash
|
||||
func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) {
|
||||
func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData) {
|
||||
ads.staging[*blockHash] = acceptanceData.Clone()
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ func (ads *acceptanceDataStore) IsStaged() bool {
|
||||
}
|
||||
|
||||
func (ads *acceptanceDataStore) Discard() {
|
||||
ads.staging = make(map[externalapi.DomainHash]model.AcceptanceData)
|
||||
ads.staging = make(map[externalapi.DomainHash]externalapi.AcceptanceData)
|
||||
ads.toDelete = make(map[externalapi.DomainHash]struct{})
|
||||
}
|
||||
|
||||
@ -67,13 +67,13 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error {
|
||||
}
|
||||
|
||||
// Get gets the acceptanceData associated with the given blockHash
|
||||
func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.AcceptanceData, error) {
|
||||
func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) {
|
||||
if acceptanceData, ok := ads.staging[*blockHash]; ok {
|
||||
return acceptanceData.Clone(), nil
|
||||
}
|
||||
|
||||
if acceptanceData, ok := ads.cache.Get(blockHash); ok {
|
||||
return acceptanceData.(model.AcceptanceData).Clone(), nil
|
||||
return acceptanceData.(externalapi.AcceptanceData).Clone(), nil
|
||||
}
|
||||
|
||||
acceptanceDataBytes, err := dbContext.Get(ads.hashAsKey(blockHash))
|
||||
@ -98,12 +98,12 @@ func (ads *acceptanceDataStore) Delete(blockHash *externalapi.DomainHash) {
|
||||
ads.toDelete[*blockHash] = struct{}{}
|
||||
}
|
||||
|
||||
func (ads *acceptanceDataStore) serializeAcceptanceData(acceptanceData model.AcceptanceData) ([]byte, error) {
|
||||
func (ads *acceptanceDataStore) serializeAcceptanceData(acceptanceData externalapi.AcceptanceData) ([]byte, error) {
|
||||
dbAcceptanceData := serialization.DomainAcceptanceDataToDbAcceptanceData(acceptanceData)
|
||||
return proto.Marshal(dbAcceptanceData)
|
||||
}
|
||||
|
||||
func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes []byte) (model.AcceptanceData, error) {
|
||||
func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes []byte) (externalapi.AcceptanceData, error) {
|
||||
dbAcceptanceData := &serialization.DbAcceptanceData{}
|
||||
err := proto.Unmarshal(acceptanceDataBytes, dbAcceptanceData)
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,4 @@
|
||||
package model
|
||||
|
||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
package externalapi
|
||||
|
||||
// AcceptanceData stores data about which transactions were accepted by a block.
|
||||
// It's ordered in the same way as the block merge set blues.
|
||||
@ -42,7 +40,7 @@ func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData {
|
||||
// TransactionAcceptanceData stores a transaction together with an indication
|
||||
// if it was accepted or not by some block
|
||||
type TransactionAcceptanceData struct {
|
||||
Transaction *externalapi.DomainTransaction
|
||||
Transaction *DomainTransaction
|
||||
Fee uint64
|
||||
IsAccepted bool
|
||||
}
|
@ -9,6 +9,7 @@ type Consensus interface {
|
||||
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
|
||||
GetBlockHeader(blockHash *DomainHash) (*DomainBlockHeader, error)
|
||||
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)
|
||||
GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error)
|
||||
|
||||
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
|
||||
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
|
||||
|
@ -5,4 +5,5 @@ type VirtualInfo struct {
|
||||
ParentHashes []*DomainHash
|
||||
Bits uint32
|
||||
PastMedianTime int64
|
||||
BlueScore uint64
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
// AcceptanceDataStore represents a store of AcceptanceData
|
||||
type AcceptanceDataStore interface {
|
||||
Store
|
||||
Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData)
|
||||
Stage(blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData)
|
||||
IsStaged() bool
|
||||
Get(dbContext DBReader, blockHash *externalapi.DomainHash) (AcceptanceData, error)
|
||||
Get(dbContext DBReader, blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error)
|
||||
Delete(blockHash *externalapi.DomainHash)
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ type ConsensusStateManager interface {
|
||||
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
|
||||
UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
|
||||
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
|
||||
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error)
|
||||
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, externalapi.AcceptanceData, Multiset, error)
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ func (bb *blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash,
|
||||
return bb.calculateAcceptedIDMerkleRoot(newBlockAcceptanceData)
|
||||
}
|
||||
|
||||
func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) {
|
||||
func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData externalapi.AcceptanceData) (*externalapi.DomainHash, error) {
|
||||
var acceptedTransactions []*externalapi.DomainTransaction
|
||||
for _, blockAcceptanceData := range acceptanceData {
|
||||
for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData {
|
||||
|
@ -40,7 +40,7 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do
|
||||
}
|
||||
|
||||
func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash,
|
||||
transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) (
|
||||
transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) (
|
||||
*externalapi.DomainBlockHeader, error) {
|
||||
|
||||
timeInMilliseconds, err := bb.minBlockTime(tempBlockHash)
|
||||
|
@ -65,7 +65,7 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom
|
||||
// coinbaseOutputForBlueBlock calculates the output that should go into the coinbase transaction of blueBlock
|
||||
// If blueBlock gets no fee - returns nil for txOut
|
||||
func (c *coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.DomainHash,
|
||||
blockAcceptanceData *model.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) {
|
||||
blockAcceptanceData *externalapi.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) {
|
||||
|
||||
totalFees := uint64(0)
|
||||
for _, txAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (
|
||||
model.UTXODiff, model.AcceptanceData, model.Multiset, error) {
|
||||
model.UTXODiff, externalapi.AcceptanceData, model.Multiset, error) {
|
||||
|
||||
log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash)
|
||||
defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash)
|
||||
@ -21,7 +21,7 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *
|
||||
if *blockHash == *csm.genesisHash {
|
||||
log.Tracef("Block %s is the genesis. By definition, "+
|
||||
"it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash)
|
||||
return utxo.NewUTXODiff(), model.AcceptanceData{}, multiset.New(), nil
|
||||
return utxo.NewUTXODiff(), externalapi.AcceptanceData{}, multiset.New(), nil
|
||||
}
|
||||
|
||||
blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash)
|
||||
@ -109,7 +109,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH
|
||||
|
||||
func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash,
|
||||
selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) (
|
||||
model.AcceptanceData, model.MutableUTXODiff, error) {
|
||||
externalapi.AcceptanceData, model.MutableUTXODiff, error) {
|
||||
|
||||
log.Tracef("applyBlueBlocks start for block %s", blockHash)
|
||||
defer log.Tracef("applyBlueBlocks end for block %s", blockHash)
|
||||
@ -125,15 +125,15 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
|
||||
}
|
||||
log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime)
|
||||
|
||||
multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks))
|
||||
multiblockAcceptanceData := make(externalapi.AcceptanceData, len(blueBlocks))
|
||||
accumulatedUTXODiff := selectedParentPastUTXODiff
|
||||
accumulatedMass := uint64(0)
|
||||
|
||||
for i, blueBlock := range blueBlocks {
|
||||
blueBlockHash := consensushashing.BlockHash(blueBlock)
|
||||
log.Tracef("Applying blue block %s", blueBlockHash)
|
||||
blockAcceptanceData := &model.BlockAcceptanceData{
|
||||
TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)),
|
||||
blockAcceptanceData := &externalapi.BlockAcceptanceData{
|
||||
TransactionAcceptanceData: make([]*externalapi.TransactionAcceptanceData, len(blueBlock.Transactions)),
|
||||
}
|
||||
isSelectedParent := i == 0
|
||||
log.Tracef("Is blue block %s the selected parent: %t", blueBlockHash, isSelectedParent)
|
||||
@ -153,7 +153,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH
|
||||
log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d",
|
||||
transactionID, blueBlockHash, isAccepted, transaction.Fee)
|
||||
|
||||
blockAcceptanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{
|
||||
blockAcceptanceData.TransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{
|
||||
Transaction: transaction,
|
||||
Fee: transaction.Fee,
|
||||
IsAccepted: isAccepted,
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (csm *consensusStateManager) calculateMultiset(
|
||||
acceptanceData model.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) {
|
||||
acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) {
|
||||
|
||||
log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
|
||||
defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent())
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash,
|
||||
pastUTXODiff model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error {
|
||||
pastUTXODiff model.UTXODiff, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) error {
|
||||
|
||||
log.Tracef("verifyUTXO start for block %s", blockHash)
|
||||
defer log.Tracef("verifyUTXO end for block %s", blockHash)
|
||||
@ -97,7 +97,7 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalapi.DomainBlock,
|
||||
blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error {
|
||||
blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData) error {
|
||||
|
||||
log.Tracef("validateAcceptedIDMerkleRoot start for block %s", blockHash)
|
||||
defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash)
|
||||
@ -127,7 +127,7 @@ func (csm *consensusStateManager) validateUTXOCommitment(
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData) *externalapi.DomainHash {
|
||||
func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData externalapi.AcceptanceData) *externalapi.DomainHash {
|
||||
log.Tracef("calculateAcceptedIDMerkleRoot start")
|
||||
defer log.Tracef("calculateAcceptedIDMerkleRoot end")
|
||||
|
||||
|
11
domain/utxoindex/log.go
Normal file
11
domain/utxoindex/log.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package utxoindex
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.INDX)
|
33
domain/utxoindex/model.go
Normal file
33
domain/utxoindex/model.go
Normal file
@ -0,0 +1,33 @@
|
||||
package utxoindex
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
)
|
||||
|
||||
// ScriptPublicKeyString is a script public key represented as a string
|
||||
// We use this type rather than just a byte slice because Go maps don't
|
||||
// support slices as keys. See: UTXOChanges
|
||||
type ScriptPublicKeyString string
|
||||
|
||||
// UTXOOutpointEntryPairs is a map between UTXO outpoints to UTXO entries
|
||||
type UTXOOutpointEntryPairs map[externalapi.DomainOutpoint]externalapi.UTXOEntry
|
||||
|
||||
// UTXOOutpoints is a set of UTXO outpoints
|
||||
type UTXOOutpoints map[externalapi.DomainOutpoint]interface{}
|
||||
|
||||
// UTXOChanges is the set of changes made to the UTXO index after
|
||||
// a successful update
|
||||
type UTXOChanges struct {
|
||||
Added map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
Removed map[ScriptPublicKeyString]UTXOOutpoints
|
||||
}
|
||||
|
||||
// ConvertScriptPublicKeyToString converts the given scriptPublicKey to a string
|
||||
func ConvertScriptPublicKeyToString(scriptPublicKey []byte) ScriptPublicKeyString {
|
||||
return ScriptPublicKeyString(scriptPublicKey)
|
||||
}
|
||||
|
||||
// ConvertStringToScriptPublicKey converts the given string to a scriptPublicKey byte slice
|
||||
func ConvertStringToScriptPublicKey(string ScriptPublicKeyString) []byte {
|
||||
return []byte(string)
|
||||
}
|
255
domain/utxoindex/store.go
Normal file
255
domain/utxoindex/store.go
Normal file
@ -0,0 +1,255 @@
|
||||
package utxoindex
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var utxoIndexBucket = database.MakeBucket([]byte("utxo-index"))
|
||||
|
||||
type utxoIndexStore struct {
|
||||
database database.Database
|
||||
toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpoints
|
||||
}
|
||||
|
||||
func newUTXOIndexStore(database database.Database) *utxoIndexStore {
|
||||
return &utxoIndexStore{
|
||||
database: database,
|
||||
toAdd: make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs),
|
||||
toRemove: make(map[ScriptPublicKeyString]UTXOOutpoints),
|
||||
}
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry) error {
|
||||
key := ConvertScriptPublicKeyToString(scriptPublicKey)
|
||||
log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
|
||||
// If the outpoint exists in `toRemove` simply remove it from there and return
|
||||
if toRemoveOutpointsOfKey, ok := uis.toRemove[key]; ok {
|
||||
if _, ok := toRemoveOutpointsOfKey[*outpoint]; ok {
|
||||
log.Tracef("Outpoint %s:%d exists in `toRemove`. Deleting it from there",
|
||||
outpoint.TransactionID, outpoint.Index)
|
||||
delete(toRemoveOutpointsOfKey, *outpoint)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Create a UTXOOutpointEntryPairs entry in `toAdd` if it doesn't exist
|
||||
if _, ok := uis.toAdd[key]; !ok {
|
||||
log.Tracef("Creating key %s in `toAdd`", key)
|
||||
uis.toAdd[key] = make(UTXOOutpointEntryPairs)
|
||||
}
|
||||
|
||||
// Return an error if the outpoint already exists in `toAdd`
|
||||
toAddPairsOfKey := uis.toAdd[key]
|
||||
if _, ok := toAddPairsOfKey[*outpoint]; ok {
|
||||
return errors.Errorf("cannot add outpoint %s because it's being added already", outpoint)
|
||||
}
|
||||
|
||||
toAddPairsOfKey[*outpoint] = *utxoEntry
|
||||
|
||||
log.Tracef("Added outpoint %s:%d to scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) remove(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint) error {
|
||||
key := ConvertScriptPublicKeyToString(scriptPublicKey)
|
||||
log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
|
||||
// If the outpoint exists in `toAdd` simply remove it from there and return
|
||||
if toAddPairsOfKey, ok := uis.toAdd[key]; ok {
|
||||
if _, ok := toAddPairsOfKey[*outpoint]; ok {
|
||||
log.Tracef("Outpoint %s:%d exists in `toAdd`. Deleting it from there",
|
||||
outpoint.TransactionID, outpoint.Index)
|
||||
delete(toAddPairsOfKey, *outpoint)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Create a UTXOOutpoints entry 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)
|
||||
}
|
||||
|
||||
// Return an error if the outpoint already exists in `toRemove`
|
||||
toRemoveOutpointsOfKey := uis.toRemove[key]
|
||||
if _, ok := toRemoveOutpointsOfKey[*outpoint]; ok {
|
||||
return errors.Errorf("cannot remove outpoint %s because it's being removed already", outpoint)
|
||||
}
|
||||
|
||||
toRemoveOutpointsOfKey[*outpoint] = struct{}{}
|
||||
|
||||
log.Tracef("Removed outpoint %s:%d from scriptPublicKey %s",
|
||||
outpoint.TransactionID, outpoint.Index, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) discard() {
|
||||
uis.toAdd = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs)
|
||||
uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpoints)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) commit() error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.commit")
|
||||
defer onEnd()
|
||||
|
||||
dbTransaction, err := uis.database.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTransaction.RollbackUnlessClosed()
|
||||
|
||||
for scriptPublicKeyString, toRemoveOutpointsOfKey := range uis.toRemove {
|
||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||
for outpointToRemove := range toRemoveOutpointsOfKey {
|
||||
key, err := uis.convertOutpointToKey(bucket, &outpointToRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTransaction.Delete(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd {
|
||||
scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString)
|
||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||
for outpointToAdd, utxoEntryToAdd := range toAddUTXOOutpointEntryPairs {
|
||||
key, err := uis.convertOutpointToKey(bucket, &outpointToAdd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serializedUTXOEntry, err := uis.serializeUTXOEntry(utxoEntryToAdd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTransaction.Put(key, serializedUTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = dbTransaction.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uis.discard()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) bucketForScriptPublicKey(scriptPublicKey []byte) *database.Bucket {
|
||||
return utxoIndexBucket.Bucket(scriptPublicKey)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) convertOutpointToKey(bucket *database.Bucket, outpoint *externalapi.DomainOutpoint) (*database.Key, error) {
|
||||
serializedOutpoint, err := uis.serializeOutpoint(outpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bucket.Key(serializedOutpoint), nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) convertKeyToOutpoint(key *database.Key) (*externalapi.DomainOutpoint, error) {
|
||||
serializedOutpoint := key.Suffix()
|
||||
return uis.deserializeOutpoint(serializedOutpoint)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) serializeOutpoint(outpoint *externalapi.DomainOutpoint) ([]byte, error) {
|
||||
dbOutpoint := serialization.DomainOutpointToDbOutpoint(outpoint)
|
||||
return proto.Marshal(dbOutpoint)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) deserializeOutpoint(serializedOutpoint []byte) (*externalapi.DomainOutpoint, error) {
|
||||
var dbOutpoint serialization.DbOutpoint
|
||||
err := proto.Unmarshal(serializedOutpoint, &dbOutpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serialization.DbOutpointToDomainOutpoint(&dbOutpoint)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) serializeUTXOEntry(utxoEntry externalapi.UTXOEntry) ([]byte, error) {
|
||||
dbUTXOEntry := serialization.UTXOEntryToDBUTXOEntry(utxoEntry)
|
||||
return proto.Marshal(dbUTXOEntry)
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) deserializeUTXOEntry(serializedUTXOEntry []byte) (externalapi.UTXOEntry, error) {
|
||||
var dbUTXOEntry serialization.DbUtxoEntry
|
||||
err := proto.Unmarshal(serializedUTXOEntry, &dbUTXOEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serialization.DBUTXOEntryToUTXOEntry(&dbUTXOEntry), nil
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) stagedData() (
|
||||
toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs,
|
||||
toRemove map[ScriptPublicKeyString]UTXOOutpoints) {
|
||||
|
||||
toAddClone := make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs, len(uis.toAdd))
|
||||
for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd {
|
||||
toAddUTXOOutpointEntryPairsClone := make(UTXOOutpointEntryPairs, len(toAddUTXOOutpointEntryPairs))
|
||||
for outpoint, utxoEntry := range toAddUTXOOutpointEntryPairs {
|
||||
toAddUTXOOutpointEntryPairsClone[outpoint] = utxoEntry
|
||||
}
|
||||
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[scriptPublicKeyString] = toRemoveOutpointsClone
|
||||
}
|
||||
|
||||
return toAddClone, toRemoveClone
|
||||
}
|
||||
|
||||
func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) {
|
||||
if len(uis.toAdd) > 0 || len(uis.toRemove) > 0 {
|
||||
return nil, errors.Errorf("cannot get utxo outpoint entry pairs while staging isn't empty")
|
||||
}
|
||||
|
||||
bucket := uis.bucketForScriptPublicKey(scriptPublicKey)
|
||||
cursor, err := uis.database.Cursor(bucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utxoOutpointEntryPairs := make(UTXOOutpointEntryPairs)
|
||||
for cursor.Next() {
|
||||
key, err := cursor.Key()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outpoint, err := uis.convertKeyToOutpoint(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serializedUTXOEntry, err := cursor.Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utxoEntry, err := uis.deserializeUTXOEntry(serializedUTXOEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utxoOutpointEntryPairs[*outpoint] = utxoEntry
|
||||
}
|
||||
return utxoOutpointEntryPairs, nil
|
||||
}
|
168
domain/utxoindex/utxoindex.go
Normal file
168
domain/utxoindex/utxoindex.go
Normal file
@ -0,0 +1,168 @@
|
||||
package utxoindex
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// UTXOIndex maintains an index between transaction scriptPublicKeys
|
||||
// and UTXOs
|
||||
type UTXOIndex struct {
|
||||
consensus externalapi.Consensus
|
||||
store *utxoIndexStore
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// New creates a new UTXO index
|
||||
func New(consensus externalapi.Consensus, database database.Database) *UTXOIndex {
|
||||
store := newUTXOIndexStore(database)
|
||||
return &UTXOIndex{
|
||||
consensus: consensus,
|
||||
store: store,
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the UTXO index with the given DAG selected parent chain changes
|
||||
func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedParentChainChanges) (*UTXOChanges, error) {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.Update")
|
||||
defer onEnd()
|
||||
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
|
||||
log.Tracef("Updating UTXO index with chainChanges: %+v", chainChanges)
|
||||
for _, removedBlockHash := range chainChanges.Removed {
|
||||
err := ui.removeBlock(removedBlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, addedBlockHash := range chainChanges.Added {
|
||||
err := ui.addBlock(addedBlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
added, removed := ui.store.stagedData()
|
||||
utxoIndexChanges := &UTXOChanges{
|
||||
Added: added,
|
||||
Removed: removed,
|
||||
}
|
||||
|
||||
err := ui.store.commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Tracef("UTXO index updated with the UTXOChanged: %+v", utxoIndexChanges)
|
||||
return utxoIndexChanges, nil
|
||||
}
|
||||
|
||||
func (ui *UTXOIndex) addBlock(blockHash *externalapi.DomainHash) error {
|
||||
log.Tracef("Adding block %s to UTXO index", blockHash)
|
||||
acceptanceData, err := ui.consensus.GetBlockAcceptanceData(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blockInfo, err := ui.consensus.GetBlockInfo(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, blockAcceptanceData := range acceptanceData {
|
||||
for _, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
|
||||
if !transactionAcceptanceData.IsAccepted {
|
||||
continue
|
||||
}
|
||||
err := ui.addTransaction(transactionAcceptanceData.Transaction, blockInfo.BlueScore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *UTXOIndex) removeBlock(blockHash *externalapi.DomainHash) error {
|
||||
log.Tracef("Removing block %s from UTXO index", blockHash)
|
||||
acceptanceData, err := ui.consensus.GetBlockAcceptanceData(blockHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, blockAcceptanceData := range acceptanceData {
|
||||
for _, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData {
|
||||
if !transactionAcceptanceData.IsAccepted {
|
||||
continue
|
||||
}
|
||||
err := ui.removeTransaction(transactionAcceptanceData.Transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, blockBlueScore uint64) error {
|
||||
transactionID := consensushashing.TransactionID(transaction)
|
||||
log.Tracef("Adding transaction %s to UTXO index", transactionID)
|
||||
|
||||
isCoinbase := transactionhelper.IsCoinBase(transaction)
|
||||
for _, transactionInput := range transaction.Inputs {
|
||||
log.Tracef("Removing outpoint %s:%d from UTXO index",
|
||||
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
|
||||
err := ui.store.remove(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for index, transactionOutput := range transaction.Outputs {
|
||||
log.Tracef("Adding outpoint %s:%d to UTXO index", transactionID, index)
|
||||
outpoint := externalapi.NewDomainOutpoint(transactionID, uint32(index))
|
||||
utxoEntry := utxo.NewUTXOEntry(transactionOutput.Value, transactionOutput.ScriptPublicKey, isCoinbase, blockBlueScore)
|
||||
err := ui.store.add(transactionOutput.ScriptPublicKey, outpoint, &utxoEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransaction) error {
|
||||
transactionID := consensushashing.TransactionID(transaction)
|
||||
log.Tracef("Removing transaction %s from UTXO index", transactionID)
|
||||
for index, transactionOutput := range transaction.Outputs {
|
||||
log.Tracef("Removing outpoint %s:%d from UTXO index", transactionID, index)
|
||||
outpoint := externalapi.NewDomainOutpoint(transactionID, uint32(index))
|
||||
err := ui.store.remove(transactionOutput.ScriptPublicKey, outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, transactionInput := range transaction.Inputs {
|
||||
log.Tracef("Adding outpoint %s:%d to UTXO index",
|
||||
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
|
||||
err := ui.store.add(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, &transactionInput.UTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UTXOs returns all the UTXOs for the given scriptPublicKey
|
||||
func (ui *UTXOIndex) UTXOs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.UTXOs")
|
||||
defer onEnd()
|
||||
|
||||
ui.mutex.Lock()
|
||||
defer ui.mutex.Unlock()
|
||||
|
||||
return ui.store.getUTXOOutpointEntryPairs(scriptPublicKey)
|
||||
}
|
@ -123,6 +123,7 @@ type Flags struct {
|
||||
RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
|
||||
ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."`
|
||||
MaxUTXOCacheSize uint64 `long:"maxutxocachesize" description:"Max size of loaded UTXO into ram from the disk in bytes"`
|
||||
UTXOIndex bool `long:"utxoindex" description:"Enable the UTXO index"`
|
||||
NetworkFlags
|
||||
ServiceOptions *ServiceOptions
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -77,8 +77,18 @@ message KaspadMessage {
|
||||
GetMempoolEntriesResponseMessage getMempoolEntriesResponse = 1044;
|
||||
ShutDownRequestMessage shutDownRequest = 1045;
|
||||
ShutDownResponseMessage shutDownResponse = 1046;
|
||||
GetHeadersRequestMessage getHeadersRequest = 10347;
|
||||
GetHeadersRequestMessage getHeadersRequest = 1047;
|
||||
GetHeadersResponseMessage getHeadersResponse = 1048;
|
||||
NotifyUtxosChangedRequestMessage notifyUtxosChangedRequest = 1049;
|
||||
NotifyUtxosChangedResponseMessage notifyUtxosChangedResponse = 1050;
|
||||
UtxosChangedNotificationMessage utxosChangedNotification = 1051;
|
||||
GetUtxosByAddressesRequestMessage getUtxosByAddressesRequest = 1052;
|
||||
GetUtxosByAddressesResponseMessage getUtxosByAddressesResponse = 1053;
|
||||
GetVirtualSelectedParentBlueScoreRequestMessage getVirtualSelectedParentBlueScoreRequest = 1054;
|
||||
GetVirtualSelectedParentBlueScoreResponseMessage getVirtualSelectedParentBlueScoreResponse = 1055;
|
||||
NotifyVirtualSelectedParentBlueScoreChangedRequestMessage notifyVirtualSelectedParentBlueScoreChangedRequest = 1056;
|
||||
NotifyVirtualSelectedParentBlueScoreChangedResponseMessage notifyVirtualSelectedParentBlueScoreChangedResponse = 1057;
|
||||
VirtualSelectedParentBlueScoreChangedNotificationMessage virtualSelectedParentBlueScoreChangedNotification = 1058;
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,11 +422,12 @@ message AddPeerResponseMessage{
|
||||
}
|
||||
|
||||
message SubmitTransactionRequestMessage{
|
||||
TransactionMessage transaction = 1;
|
||||
RpcTransaction transaction = 1;
|
||||
}
|
||||
|
||||
message SubmitTransactionResponseMessage{
|
||||
string txId = 1;
|
||||
string transactionId = 1;
|
||||
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
@ -612,6 +623,89 @@ message GetHeadersResponseMessage{
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message NotifyUtxosChangedRequestMessage {
|
||||
repeated string addresses = 1;
|
||||
}
|
||||
|
||||
message NotifyUtxosChangedResponseMessage {
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message UtxosChangedNotificationMessage {
|
||||
repeated UtxosByAddressesEntry added = 1;
|
||||
repeated UtxosByAddressesEntry removed = 2;
|
||||
}
|
||||
|
||||
message UtxosByAddressesEntry {
|
||||
string address = 1;
|
||||
RpcOutpoint outpoint = 2;
|
||||
RpcUtxoEntry utxoEntry = 3;
|
||||
}
|
||||
|
||||
message RpcTransaction {
|
||||
int32 version = 1;
|
||||
repeated RpcTransactionInput inputs = 2;
|
||||
repeated RpcTransactionOutput outputs = 3;
|
||||
uint64 lockTime = 4;
|
||||
string subnetworkId = 5;
|
||||
uint64 gas = 6;
|
||||
string payloadHash = 7;
|
||||
string payload = 8;
|
||||
}
|
||||
|
||||
message RpcTransactionInput {
|
||||
RpcOutpoint previousOutpoint = 1;
|
||||
string signatureScript = 2;
|
||||
uint64 sequence = 3;
|
||||
}
|
||||
|
||||
message RpcTransactionOutput {
|
||||
uint64 amount = 1;
|
||||
string scriptPubKey = 2;
|
||||
}
|
||||
|
||||
message RpcOutpoint {
|
||||
string transactionId = 1;
|
||||
uint32 index = 2;
|
||||
}
|
||||
|
||||
message RpcUtxoEntry {
|
||||
uint64 amount = 1;
|
||||
string scriptPubKey = 2;
|
||||
uint64 blockBlueScore = 3;
|
||||
bool isCoinbase = 4;
|
||||
}
|
||||
|
||||
message GetUtxosByAddressesRequestMessage {
|
||||
repeated string addresses = 1;
|
||||
}
|
||||
|
||||
message GetUtxosByAddressesResponseMessage {
|
||||
repeated UtxosByAddressesEntry entries = 1;
|
||||
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message GetVirtualSelectedParentBlueScoreRequestMessage {
|
||||
}
|
||||
|
||||
message GetVirtualSelectedParentBlueScoreResponseMessage {
|
||||
uint64 blueScore = 1;
|
||||
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message NotifyVirtualSelectedParentBlueScoreChangedRequestMessage {
|
||||
}
|
||||
|
||||
message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage {
|
||||
RPCError error = 1000;
|
||||
}
|
||||
|
||||
message VirtualSelectedParentBlueScoreChangedNotificationMessage {
|
||||
uint64 virtualSelectedParentBlueScore = 1;
|
||||
}
|
||||
|
||||
service RPC {
|
||||
rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
package protowire
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
func (x *KaspadMessage_GetUtxosByAddressesRequest) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.GetUTXOsByAddressesRequestMessage{
|
||||
Addresses: x.GetUtxosByAddressesRequest.Addresses,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetUtxosByAddressesRequest) fromAppMessage(message *appmessage.GetUTXOsByAddressesRequestMessage) error {
|
||||
x.GetUtxosByAddressesRequest = &GetUtxosByAddressesRequestMessage{
|
||||
Addresses: message.Addresses,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetUtxosByAddressesResponse) toAppMessage() (appmessage.Message, error) {
|
||||
var err *appmessage.RPCError
|
||||
if x.GetUtxosByAddressesResponse.Error != nil {
|
||||
err = &appmessage.RPCError{Message: x.GetUtxosByAddressesResponse.Error.Message}
|
||||
}
|
||||
entries := make([]*appmessage.UTXOsByAddressesEntry, len(x.GetUtxosByAddressesResponse.Entries))
|
||||
for i, entry := range x.GetUtxosByAddressesResponse.Entries {
|
||||
entries[i] = entry.toAppMessage()
|
||||
}
|
||||
return &appmessage.GetUTXOsByAddressesResponseMessage{
|
||||
Entries: entries,
|
||||
Error: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetUtxosByAddressesResponse) fromAppMessage(message *appmessage.GetUTXOsByAddressesResponseMessage) error {
|
||||
var err *RPCError
|
||||
if message.Error != nil {
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
entries := make([]*UtxosByAddressesEntry, len(message.Entries))
|
||||
for i, entry := range message.Entries {
|
||||
entries[i] = &UtxosByAddressesEntry{}
|
||||
entries[i].fromAppMessage(entry)
|
||||
}
|
||||
x.GetUtxosByAddressesResponse = &GetUtxosByAddressesResponseMessage{
|
||||
Entries: entries,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package protowire
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
)
|
||||
|
||||
func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.GetVirtualSelectedParentBlueScoreRequestMessage{}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) fromAppMessage(message *appmessage.GetVirtualSelectedParentBlueScoreRequestMessage) error {
|
||||
x.GetVirtualSelectedParentBlueScoreRequest = &GetVirtualSelectedParentBlueScoreRequestMessage{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) toAppMessage() (appmessage.Message, error) {
|
||||
var err *appmessage.RPCError
|
||||
if x.GetVirtualSelectedParentBlueScoreResponse.Error != nil {
|
||||
err = &appmessage.RPCError{Message: x.GetVirtualSelectedParentBlueScoreResponse.Error.Message}
|
||||
}
|
||||
return &appmessage.GetVirtualSelectedParentBlueScoreResponseMessage{
|
||||
BlueScore: x.GetVirtualSelectedParentBlueScoreResponse.BlueScore,
|
||||
Error: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) fromAppMessage(message *appmessage.GetVirtualSelectedParentBlueScoreResponseMessage) error {
|
||||
var err *RPCError
|
||||
if message.Error != nil {
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
x.GetVirtualSelectedParentBlueScoreResponse = &GetVirtualSelectedParentBlueScoreResponseMessage{
|
||||
BlueScore: message.BlueScore,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package protowire
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
)
|
||||
|
||||
func (x *KaspadMessage_NotifyUtxosChangedRequest) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.NotifyUTXOsChangedRequestMessage{
|
||||
Addresses: x.NotifyUtxosChangedRequest.Addresses,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyUtxosChangedRequest) fromAppMessage(message *appmessage.NotifyUTXOsChangedRequestMessage) error {
|
||||
x.NotifyUtxosChangedRequest = &NotifyUtxosChangedRequestMessage{
|
||||
Addresses: message.Addresses,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyUtxosChangedResponse) toAppMessage() (appmessage.Message, error) {
|
||||
var err *appmessage.RPCError
|
||||
if x.NotifyUtxosChangedResponse.Error != nil {
|
||||
err = &appmessage.RPCError{Message: x.NotifyUtxosChangedResponse.Error.Message}
|
||||
}
|
||||
return &appmessage.NotifyUTXOsChangedResponseMessage{
|
||||
Error: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyUtxosChangedResponse) fromAppMessage(message *appmessage.NotifyUTXOsChangedResponseMessage) error {
|
||||
var err *RPCError
|
||||
if message.Error != nil {
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
x.NotifyUtxosChangedResponse = &NotifyUtxosChangedResponseMessage{
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_UtxosChangedNotification) toAppMessage() (appmessage.Message, error) {
|
||||
added := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Added))
|
||||
for i, entry := range x.UtxosChangedNotification.Added {
|
||||
added[i] = entry.toAppMessage()
|
||||
}
|
||||
|
||||
removed := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Removed))
|
||||
for i, entry := range x.UtxosChangedNotification.Removed {
|
||||
removed[i] = entry.toAppMessage()
|
||||
}
|
||||
|
||||
return &appmessage.UTXOsChangedNotificationMessage{
|
||||
Added: added,
|
||||
Removed: removed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_UtxosChangedNotification) fromAppMessage(message *appmessage.UTXOsChangedNotificationMessage) error {
|
||||
added := make([]*UtxosByAddressesEntry, len(message.Added))
|
||||
for i, entry := range message.Added {
|
||||
added[i] = &UtxosByAddressesEntry{}
|
||||
added[i].fromAppMessage(entry)
|
||||
}
|
||||
|
||||
removed := make([]*UtxosByAddressesEntry, len(message.Removed))
|
||||
for i, entry := range message.Removed {
|
||||
removed[i] = &UtxosByAddressesEntry{}
|
||||
removed[i].fromAppMessage(entry)
|
||||
}
|
||||
|
||||
x.UtxosChangedNotification = &UtxosChangedNotificationMessage{
|
||||
Added: added,
|
||||
Removed: removed,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UtxosByAddressesEntry) toAppMessage() *appmessage.UTXOsByAddressesEntry {
|
||||
outpoint := &appmessage.RPCOutpoint{
|
||||
TransactionID: x.Outpoint.TransactionId,
|
||||
Index: x.Outpoint.Index,
|
||||
}
|
||||
var utxoEntry *appmessage.RPCUTXOEntry
|
||||
if x.UtxoEntry != nil {
|
||||
utxoEntry = &appmessage.RPCUTXOEntry{
|
||||
Amount: x.UtxoEntry.Amount,
|
||||
ScriptPubKey: x.UtxoEntry.ScriptPubKey,
|
||||
BlockBlueScore: x.UtxoEntry.BlockBlueScore,
|
||||
IsCoinbase: x.UtxoEntry.IsCoinbase,
|
||||
}
|
||||
}
|
||||
return &appmessage.UTXOsByAddressesEntry{
|
||||
Address: x.Address,
|
||||
Outpoint: outpoint,
|
||||
UTXOEntry: utxoEntry,
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UtxosByAddressesEntry) fromAppMessage(entry *appmessage.UTXOsByAddressesEntry) {
|
||||
outpoint := &RpcOutpoint{
|
||||
TransactionId: entry.Outpoint.TransactionID,
|
||||
Index: entry.Outpoint.Index,
|
||||
}
|
||||
var utxoEntry *RpcUtxoEntry
|
||||
if entry.UTXOEntry != nil {
|
||||
utxoEntry = &RpcUtxoEntry{
|
||||
Amount: entry.UTXOEntry.Amount,
|
||||
ScriptPubKey: entry.UTXOEntry.ScriptPubKey,
|
||||
BlockBlueScore: entry.UTXOEntry.BlockBlueScore,
|
||||
IsCoinbase: entry.UTXOEntry.IsCoinbase,
|
||||
}
|
||||
}
|
||||
*x = UtxosByAddressesEntry{
|
||||
Address: entry.Address,
|
||||
Outpoint: outpoint,
|
||||
UtxoEntry: utxoEntry,
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package protowire
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) fromAppMessage(_ *appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) error {
|
||||
x.NotifyVirtualSelectedParentBlueScoreChangedRequest = &NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) toAppMessage() (appmessage.Message, error) {
|
||||
var err *appmessage.RPCError
|
||||
if x.NotifyVirtualSelectedParentBlueScoreChangedResponse.Error != nil {
|
||||
err = &appmessage.RPCError{Message: x.NotifyVirtualSelectedParentBlueScoreChangedResponse.Error.Message}
|
||||
}
|
||||
return &appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{
|
||||
Error: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) fromAppMessage(message *appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) error {
|
||||
var err *RPCError
|
||||
if message.Error != nil {
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
x.NotifyVirtualSelectedParentBlueScoreChangedResponse = &NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) toAppMessage() (appmessage.Message, error) {
|
||||
return &appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage{
|
||||
VirtualSelectedParentBlueScore: x.VirtualSelectedParentBlueScoreChangedNotification.VirtualSelectedParentBlueScore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) fromAppMessage(message *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) error {
|
||||
x.VirtualSelectedParentBlueScoreChangedNotification = &VirtualSelectedParentBlueScoreChangedNotificationMessage{
|
||||
VirtualSelectedParentBlueScore: message.VirtualSelectedParentBlueScore,
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
package protowire
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
)
|
||||
|
||||
func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) {
|
||||
msgTx, err := x.SubmitTransactionRequest.Transaction.toAppMessage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rpcTransaction := x.SubmitTransactionRequest.Transaction.toAppMessage()
|
||||
return &appmessage.SubmitTransactionRequestMessage{
|
||||
Transaction: msgTx.(*appmessage.MsgTx),
|
||||
Transaction: rpcTransaction,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (x *KaspadMessage_SubmitTransactionRequest) fromAppMessage(message *appmessage.SubmitTransactionRequestMessage) error {
|
||||
x.SubmitTransactionRequest = &SubmitTransactionRequestMessage{
|
||||
Transaction: &TransactionMessage{},
|
||||
Transaction: &RpcTransaction{},
|
||||
}
|
||||
x.SubmitTransactionRequest.Transaction.fromAppMessage(message.Transaction)
|
||||
return nil
|
||||
@ -26,8 +25,8 @@ func (x *KaspadMessage_SubmitTransactionResponse) toAppMessage() (appmessage.Mes
|
||||
err = &appmessage.RPCError{Message: x.SubmitTransactionResponse.Error.Message}
|
||||
}
|
||||
return &appmessage.SubmitTransactionResponseMessage{
|
||||
TxID: x.SubmitTransactionResponse.TxId,
|
||||
Error: err,
|
||||
TransactionID: x.SubmitTransactionResponse.TransactionId,
|
||||
Error: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -37,8 +36,72 @@ func (x *KaspadMessage_SubmitTransactionResponse) fromAppMessage(message *appmes
|
||||
err = &RPCError{Message: message.Error.Message}
|
||||
}
|
||||
x.SubmitTransactionResponse = &SubmitTransactionResponseMessage{
|
||||
TxId: message.TxID,
|
||||
Error: err,
|
||||
TransactionId: message.TransactionID,
|
||||
Error: err,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RpcTransaction) toAppMessage() *appmessage.RPCTransaction {
|
||||
inputs := make([]*appmessage.RPCTransactionInput, len(x.Inputs))
|
||||
for i, input := range x.Inputs {
|
||||
previousOutpoint := &appmessage.RPCOutpoint{
|
||||
TransactionID: input.PreviousOutpoint.TransactionId,
|
||||
Index: input.PreviousOutpoint.Index,
|
||||
}
|
||||
inputs[i] = &appmessage.RPCTransactionInput{
|
||||
PreviousOutpoint: previousOutpoint,
|
||||
SignatureScript: input.SignatureScript,
|
||||
Sequence: input.Sequence,
|
||||
}
|
||||
}
|
||||
outputs := make([]*appmessage.RPCTransactionOutput, len(x.Outputs))
|
||||
for i, output := range x.Outputs {
|
||||
outputs[i] = &appmessage.RPCTransactionOutput{
|
||||
Amount: output.Amount,
|
||||
ScriptPubKey: output.ScriptPubKey,
|
||||
}
|
||||
}
|
||||
return &appmessage.RPCTransaction{
|
||||
Version: x.Version,
|
||||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
LockTime: x.LockTime,
|
||||
SubnetworkID: x.SubnetworkId,
|
||||
Gas: x.Gas,
|
||||
PayloadHash: x.PayloadHash,
|
||||
Payload: x.Payload,
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RpcTransaction) fromAppMessage(transaction *appmessage.RPCTransaction) {
|
||||
inputs := make([]*RpcTransactionInput, len(transaction.Inputs))
|
||||
for i, input := range transaction.Inputs {
|
||||
previousOutpoint := &RpcOutpoint{
|
||||
TransactionId: input.PreviousOutpoint.TransactionID,
|
||||
Index: input.PreviousOutpoint.Index,
|
||||
}
|
||||
inputs[i] = &RpcTransactionInput{
|
||||
PreviousOutpoint: previousOutpoint,
|
||||
SignatureScript: input.SignatureScript,
|
||||
Sequence: input.Sequence,
|
||||
}
|
||||
}
|
||||
outputs := make([]*RpcTransactionOutput, len(transaction.Outputs))
|
||||
for i, output := range transaction.Outputs {
|
||||
outputs[i] = &RpcTransactionOutput{
|
||||
Amount: output.Amount,
|
||||
ScriptPubKey: output.ScriptPubKey,
|
||||
}
|
||||
}
|
||||
*x = RpcTransaction{
|
||||
Version: transaction.Version,
|
||||
Inputs: inputs,
|
||||
Outputs: outputs,
|
||||
LockTime: transaction.LockTime,
|
||||
SubnetworkId: transaction.SubnetworkID,
|
||||
Gas: transaction.Gas,
|
||||
PayloadHash: transaction.PayloadHash,
|
||||
Payload: transaction.Payload,
|
||||
}
|
||||
}
|
||||
|
@ -575,6 +575,76 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.NotifyUTXOsChangedRequestMessage:
|
||||
payload := new(KaspadMessage_NotifyUtxosChangedRequest)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.NotifyUTXOsChangedResponseMessage:
|
||||
payload := new(KaspadMessage_NotifyUtxosChangedResponse)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.UTXOsChangedNotificationMessage:
|
||||
payload := new(KaspadMessage_UtxosChangedNotification)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetUTXOsByAddressesRequestMessage:
|
||||
payload := new(KaspadMessage_GetUtxosByAddressesRequest)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetUTXOsByAddressesResponseMessage:
|
||||
payload := new(KaspadMessage_GetUtxosByAddressesResponse)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetVirtualSelectedParentBlueScoreRequestMessage:
|
||||
payload := new(KaspadMessage_GetVirtualSelectedParentBlueScoreRequest)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.GetVirtualSelectedParentBlueScoreResponseMessage:
|
||||
payload := new(KaspadMessage_GetVirtualSelectedParentBlueScoreResponse)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage:
|
||||
payload := new(KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage:
|
||||
payload := new(KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
case *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage:
|
||||
payload := new(KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification)
|
||||
err := payload.fromAppMessage(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package rpcclient
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
// GetUTXOsByAddresses sends an RPC request respective to the function's name and returns the RPC server's response
|
||||
func (c *RPCClient) GetUTXOsByAddresses(addresses []string) (*appmessage.GetUTXOsByAddressesResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetUTXOsByAddressesRequestMessage(addresses))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdGetUTXOsByAddressesResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getUTXOsByAddressesResponse := response.(*appmessage.GetUTXOsByAddressesResponseMessage)
|
||||
if getUTXOsByAddressesResponse.Error != nil {
|
||||
return nil, c.convertRPCError(getUTXOsByAddressesResponse.Error)
|
||||
}
|
||||
return getUTXOsByAddressesResponse, nil
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package rpcclient
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
// GetVirtualSelectedParentBlueScore sends an RPC request respective to the function's name and returns the RPC server's response
|
||||
func (c *RPCClient) GetVirtualSelectedParentBlueScore() (*appmessage.GetVirtualSelectedParentBlueScoreResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetVirtualSelectedParentBlueScoreRequestMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdGetVirtualSelectedParentBlueScoreResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getVirtualSelectedParentBlueScoreResponse := response.(*appmessage.GetVirtualSelectedParentBlueScoreResponseMessage)
|
||||
if getVirtualSelectedParentBlueScoreResponse.Error != nil {
|
||||
return nil, c.convertRPCError(getVirtualSelectedParentBlueScoreResponse.Error)
|
||||
}
|
||||
return getVirtualSelectedParentBlueScoreResponse, nil
|
||||
}
|
40
infrastructure/network/rpcclient/rpc_on_utxos_changed.go
Normal file
40
infrastructure/network/rpcclient/rpc_on_utxos_changed.go
Normal file
@ -0,0 +1,40 @@
|
||||
package rpcclient
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RegisterForUTXOsChangedNotifications sends an RPC request respective to the function's name and returns the RPC server's response.
|
||||
// Additionally, it starts listening for the appropriate notification using the given handler function
|
||||
func (c *RPCClient) RegisterForUTXOsChangedNotifications(addresses []string,
|
||||
onUTXOsChanged func(notification *appmessage.UTXOsChangedNotificationMessage)) error {
|
||||
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyUTXOsChangedRequestMessage(addresses))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdNotifyUTXOsChangedResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notifyUTXOsChangedResponse := response.(*appmessage.NotifyUTXOsChangedResponseMessage)
|
||||
if notifyUTXOsChangedResponse.Error != nil {
|
||||
return c.convertRPCError(notifyUTXOsChangedResponse.Error)
|
||||
}
|
||||
spawn("RegisterForUTXOsChangedNotifications", func() {
|
||||
for {
|
||||
notification, err := c.route(appmessage.CmdUTXOsChangedNotificationMessage).Dequeue()
|
||||
if err != nil {
|
||||
if errors.Is(err, routerpkg.ErrRouteClosed) {
|
||||
break
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
UTXOsChangedNotification := notification.(*appmessage.UTXOsChangedNotificationMessage)
|
||||
onUTXOsChanged(UTXOsChangedNotification)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package rpcclient
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RegisterForVirtualSelectedParentBlueScoreChangedNotifications sends an RPC request respective to the function's
|
||||
// name and returns the RPC server's response. Additionally, it starts listening for the appropriate notification
|
||||
// using the given handler function
|
||||
func (c *RPCClient) RegisterForVirtualSelectedParentBlueScoreChangedNotifications(
|
||||
onVirtualSelectedParentBlueScoreChanged func(notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage)) error {
|
||||
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notifyVirtualSelectedParentBlueScoreChangedResponse := response.(*appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)
|
||||
if notifyVirtualSelectedParentBlueScoreChangedResponse.Error != nil {
|
||||
return c.convertRPCError(notifyVirtualSelectedParentBlueScoreChangedResponse.Error)
|
||||
}
|
||||
spawn("RegisterForVirtualSelectedParentBlueScoreChangedNotifications", func() {
|
||||
for {
|
||||
notification, err := c.route(appmessage.CmdVirtualSelectedParentBlueScoreChangedNotificationMessage).Dequeue()
|
||||
if err != nil {
|
||||
if errors.Is(err, routerpkg.ErrRouteClosed) {
|
||||
break
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
VirtualSelectedParentBlueScoreChangedNotification := notification.(*appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage)
|
||||
onVirtualSelectedParentBlueScoreChanged(VirtualSelectedParentBlueScoreChangedNotification)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
@ -5,8 +5,8 @@ import (
|
||||
)
|
||||
|
||||
// SubmitTransaction sends an RPC request respective to the function's name and returns the RPC server's response
|
||||
func (c *RPCClient) SubmitTransaction(msgTx *appmessage.MsgTx) (*appmessage.SubmitTransactionResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(msgTx))
|
||||
func (c *RPCClient) SubmitTransaction(transaction *appmessage.RPCTransaction) (*appmessage.SubmitTransactionResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(transaction))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ func setConfig(t *testing.T, harness *appHarness) {
|
||||
harness.config.DataDir = randomDirectory(t)
|
||||
harness.config.Listeners = []string{harness.p2pAddress}
|
||||
harness.config.RPCListeners = []string{harness.rpcAddress}
|
||||
harness.config.UTXOIndex = harness.utxoIndex
|
||||
}
|
||||
|
||||
func commonConfig() *config.Config {
|
||||
|
@ -21,6 +21,7 @@ type appHarness struct {
|
||||
miningAddressPrivateKey string
|
||||
config *config.Config
|
||||
database database.Database
|
||||
utxoIndex bool
|
||||
}
|
||||
|
||||
type harnessParams struct {
|
||||
@ -28,6 +29,7 @@ type harnessParams struct {
|
||||
rpcAddress string
|
||||
miningAddress string
|
||||
miningAddressPrivateKey string
|
||||
utxoIndex bool
|
||||
}
|
||||
|
||||
// setupHarness creates a single appHarness with given parameters
|
||||
@ -37,6 +39,7 @@ func setupHarness(t *testing.T, params *harnessParams) (harness *appHarness, tea
|
||||
rpcAddress: params.rpcAddress,
|
||||
miningAddress: params.miningAddress,
|
||||
miningAddressPrivateKey: params.miningAddressPrivateKey,
|
||||
utxoIndex: params.utxoIndex,
|
||||
}
|
||||
|
||||
setConfig(t, harness)
|
||||
|
@ -42,12 +42,14 @@ func TestTxRelay(t *testing.T) {
|
||||
waitForPayeeToReceiveBlock(t, payeeBlockAddedChan)
|
||||
}
|
||||
|
||||
tx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee)
|
||||
response, err := payer.rpcClient.SubmitTransaction(tx)
|
||||
msgTx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee)
|
||||
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(domainTransaction)
|
||||
response, err := payer.rpcClient.SubmitTransaction(rpcTransaction)
|
||||
if err != nil {
|
||||
t.Fatalf("Error submitting transaction: %+v", err)
|
||||
}
|
||||
txID := response.TxID
|
||||
txID := response.TransactionID
|
||||
|
||||
txAddedToMempoolChan := make(chan struct{})
|
||||
|
||||
|
192
testing/integration/utxo_index_test.go
Normal file
192
testing/integration/utxo_index_test.go
Normal file
@ -0,0 +1,192 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/go-secp256k1"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUTXOIndex(t *testing.T) {
|
||||
// Setup a single kaspad instance
|
||||
harnessParams := &harnessParams{
|
||||
p2pAddress: p2pAddress1,
|
||||
rpcAddress: rpcAddress1,
|
||||
miningAddress: miningAddress1,
|
||||
miningAddressPrivateKey: miningAddress1PrivateKey,
|
||||
utxoIndex: true,
|
||||
}
|
||||
kaspad, teardown := setupHarness(t, harnessParams)
|
||||
defer teardown()
|
||||
|
||||
// skip the first block because it's paying to genesis script,
|
||||
// which contains no outputs
|
||||
mineNextBlock(t, kaspad)
|
||||
|
||||
// Register for UTXO changes
|
||||
const blockAmountToMine = 100
|
||||
onUTXOsChangedChan := make(chan *appmessage.UTXOsChangedNotificationMessage, blockAmountToMine)
|
||||
err := kaspad.rpcClient.RegisterForUTXOsChangedNotifications([]string{miningAddress1}, func(
|
||||
notification *appmessage.UTXOsChangedNotificationMessage) {
|
||||
|
||||
onUTXOsChangedChan <- notification
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to register for UTXO change notifications: %s", err)
|
||||
}
|
||||
|
||||
// Mine some blocks
|
||||
for i := 0; i < blockAmountToMine; i++ {
|
||||
mineNextBlock(t, kaspad)
|
||||
}
|
||||
|
||||
// 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
|
||||
// mined
|
||||
var notificationEntries []*appmessage.UTXOsByAddressesEntry
|
||||
for i := 0; i < blockAmountToMine-1; i++ {
|
||||
notification := <-onUTXOsChangedChan
|
||||
if len(notification.Removed) > 0 {
|
||||
t.Fatalf("Unexpectedly received that a UTXO has been removed")
|
||||
}
|
||||
for _, added := range notification.Added {
|
||||
notificationEntries = append(notificationEntries, added)
|
||||
}
|
||||
}
|
||||
|
||||
// Submit a few transactions that spends some UTXOs
|
||||
const transactionAmountToSpend = 5
|
||||
for i := 0; i < transactionAmountToSpend; i++ {
|
||||
rpcTransaction := buildTransactionForUTXOIndexTest(t, notificationEntries[i])
|
||||
_, err = kaspad.rpcClient.SubmitTransaction(rpcTransaction)
|
||||
if err != nil {
|
||||
t.Fatalf("Error submitting transaction: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Mine a block to include the above transaction
|
||||
mineNextBlock(t, kaspad)
|
||||
notification := <-onUTXOsChangedChan
|
||||
if len(notification.Removed) > 0 {
|
||||
t.Fatalf("Unexpectedly received that a UTXO has been removed")
|
||||
}
|
||||
for _, added := range notification.Added {
|
||||
notificationEntries = append(notificationEntries, added)
|
||||
}
|
||||
|
||||
// Mine another block to accept the above block
|
||||
mineNextBlock(t, kaspad)
|
||||
|
||||
// Make sure this block removed the UTXOs we spent
|
||||
notification = <-onUTXOsChangedChan
|
||||
if len(notification.Removed) != transactionAmountToSpend {
|
||||
t.Fatalf("Unexpected amount of removed UTXOs. Want: %d, got: %d",
|
||||
transactionAmountToSpend, len(notification.Removed))
|
||||
}
|
||||
for i := 0; i < transactionAmountToSpend; i++ {
|
||||
entry := notificationEntries[i]
|
||||
|
||||
found := false
|
||||
for _, removed := range notification.Removed {
|
||||
if *removed.Outpoint == *entry.Outpoint {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("Missing entry amongst removed UTXOs: %s:%d",
|
||||
entry.Outpoint.TransactionID, entry.Outpoint.Index)
|
||||
}
|
||||
}
|
||||
for _, added := range notification.Added {
|
||||
notificationEntries = append(notificationEntries, added)
|
||||
}
|
||||
|
||||
// Remove the UTXOs we spent from `notificationEntries`
|
||||
notificationEntries = notificationEntries[transactionAmountToSpend:]
|
||||
|
||||
// Get all the UTXOs and make sure the response is equivalent
|
||||
// to the data collected via notifications
|
||||
utxosByAddressesResponse, err := kaspad.rpcClient.GetUTXOsByAddresses([]string{miningAddress1})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get UTXOs: %s", err)
|
||||
}
|
||||
if len(notificationEntries) != len(utxosByAddressesResponse.Entries) {
|
||||
t.Fatalf("Unexpected amount of UTXOs. Want: %d, got: %d",
|
||||
len(notificationEntries), len(utxosByAddressesResponse.Entries))
|
||||
}
|
||||
for _, notificationEntry := range notificationEntries {
|
||||
var foundResponseEntry *appmessage.UTXOsByAddressesEntry
|
||||
for _, responseEntry := range utxosByAddressesResponse.Entries {
|
||||
if *notificationEntry.Outpoint == *responseEntry.Outpoint {
|
||||
foundResponseEntry = responseEntry
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundResponseEntry == nil {
|
||||
t.Fatalf("Missing entry in UTXOs response: %s:%d",
|
||||
notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index)
|
||||
}
|
||||
if *notificationEntry.UTXOEntry != *foundResponseEntry.UTXOEntry {
|
||||
t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v",
|
||||
notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index,
|
||||
notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAddressesEntry) *appmessage.RPCTransaction {
|
||||
transactionIDBytes, err := hex.DecodeString(entry.Outpoint.TransactionID)
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding transaction ID: %s", err)
|
||||
}
|
||||
transactionID, err := transactionid.FromBytes(transactionIDBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding transaction ID: %s", err)
|
||||
}
|
||||
|
||||
txIns := make([]*appmessage.TxIn, 1)
|
||||
txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{})
|
||||
|
||||
payeeAddress, err := util.DecodeAddress(miningAddress1, util.Bech32PrefixKaspaSim)
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding payeeAddress: %+v", err)
|
||||
}
|
||||
toScript, err := txscript.PayToAddrScript(payeeAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("Error generating script: %+v", err)
|
||||
}
|
||||
|
||||
txOuts := []*appmessage.TxOut{appmessage.NewTxOut(entry.UTXOEntry.Amount-1000, toScript)}
|
||||
|
||||
fromScript, err := hex.DecodeString(entry.UTXOEntry.ScriptPubKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding script public key: %s", err)
|
||||
}
|
||||
|
||||
msgTx := appmessage.NewNativeMsgTx(constants.TransactionVersion, txIns, txOuts)
|
||||
|
||||
privateKeyBytes, err := hex.DecodeString(miningAddress1PrivateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Error decoding private key: %+v", err)
|
||||
}
|
||||
privateKey, err := secp256k1.DeserializePrivateKeyFromSlice(privateKeyBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Error deserializing private key: %+v", err)
|
||||
}
|
||||
|
||||
signatureScript, err := txscript.SignatureScript(appmessage.MsgTxToDomainTransaction(msgTx), 0,
|
||||
fromScript, txscript.SigHashAll, privateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Error signing transaction: %+v", err)
|
||||
}
|
||||
msgTx.TxIn[0].SignatureScript = signatureScript
|
||||
|
||||
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
||||
return appmessage.DomainTransactionToRPCTransaction(domainTransaction)
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVirtualSelectedParentBlueScore(t *testing.T) {
|
||||
// Setup a single kaspad instance
|
||||
harnessParams := &harnessParams{
|
||||
p2pAddress: p2pAddress1,
|
||||
rpcAddress: rpcAddress1,
|
||||
miningAddress: miningAddress1,
|
||||
miningAddressPrivateKey: miningAddress1PrivateKey,
|
||||
utxoIndex: true,
|
||||
}
|
||||
kaspad, teardown := setupHarness(t, harnessParams)
|
||||
defer teardown()
|
||||
|
||||
// Make sure that the initial blue score is 1
|
||||
response, err := kaspad.rpcClient.GetVirtualSelectedParentBlueScore()
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting virtual selected parent blue score: %s", err)
|
||||
}
|
||||
if response.BlueScore != 1 {
|
||||
t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d",
|
||||
1, response.BlueScore)
|
||||
}
|
||||
|
||||
// Register to virtual selected parent blue score changes
|
||||
onVirtualSelectedParentBlueScoreChangedChan := make(chan *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage)
|
||||
err = kaspad.rpcClient.RegisterForVirtualSelectedParentBlueScoreChangedNotifications(
|
||||
func(notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) {
|
||||
onVirtualSelectedParentBlueScoreChangedChan <- notification
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to register for virtual selected parent "+
|
||||
"blue score change notifications: %s", err)
|
||||
}
|
||||
|
||||
// Mine some blocks and make sure that the notifications
|
||||
// report correct blue score values
|
||||
const blockAmountToMine = 100
|
||||
for i := 0; i < blockAmountToMine; i++ {
|
||||
mineNextBlock(t, kaspad)
|
||||
notification := <-onVirtualSelectedParentBlueScoreChangedChan
|
||||
if notification.VirtualSelectedParentBlueScore != 2+uint64(i) {
|
||||
t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d",
|
||||
2+uint64(i), notification.VirtualSelectedParentBlueScore)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the blue score after all that mining is as expected
|
||||
response, err = kaspad.rpcClient.GetVirtualSelectedParentBlueScore()
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting virtual selected parent blue score: %s", err)
|
||||
}
|
||||
if response.BlueScore != 1+blockAmountToMine {
|
||||
t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d",
|
||||
1+blockAmountToMine, response.BlueScore)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user