In RPC, use RPCTransactions and RPCBlocks instead of TransactionMessages and BlockMessages (#1609)

* Replace BlockMessage with RpcBlock in rpc.proto.

* Convert everything in kaspad to use RPCBlocks and fix tests.

* Fix compilation errors in stability tests and the miner.

* Update TransactionVerboseData in rpc.proto.

* Update TransactionVerboseData in the rest of kaspad.

* Make golint happy.

* Include RpcTransactionVerboseData in RpcTransaction instead of the other way around.

* Regenerate rpc.pb.go after merge.

* Update appmessage types.

* Update appmessage request and response types.

* Reimplement conversion functions between appmessage.RPCTransaction and protowire.RpcTransaction.

* Extract RpcBlockHeader toAppMessage/fromAppMessage out of RpcBlock.

* Fix compilation errors in getBlock, getBlocks, and submitBlock.

* Fix compilation errors in getMempoolEntry.

* Fix compilation errors in notifyBlockAdded.

* Update verbosedata.go.

* Fix compilation errors in getBlock and getBlocks.

* Fix compilation errors in getBlocks tests.

* Fix conversions between getBlocks message types.

* Fix integration tests.

* Fix a comment.

* Add selectedParent to the verbose block response.
This commit is contained in:
stasatdaglabs 2021-03-30 17:43:02 +03:00 committed by GitHub
parent 9266d179a9
commit c5b0394bbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 3368 additions and 3589 deletions

View File

@ -3,6 +3,7 @@ package appmessage
import (
"encoding/hex"
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
@ -294,3 +295,70 @@ func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(
}
return domainOutpointAndUTXOEntryPairs
}
// DomainBlockToRPCBlock converts DomainBlocks to RPCBlocks
func DomainBlockToRPCBlock(block *externalapi.DomainBlock) *RPCBlock {
header := &RPCBlockHeader{
Version: uint32(block.Header.Version()),
ParentHashes: hashes.ToStrings(block.Header.ParentHashes()),
HashMerkleRoot: block.Header.HashMerkleRoot().String(),
AcceptedIDMerkleRoot: block.Header.AcceptedIDMerkleRoot().String(),
UTXOCommitment: block.Header.UTXOCommitment().String(),
Timestamp: block.Header.TimeInMilliseconds(),
Bits: block.Header.Bits(),
Nonce: block.Header.Nonce(),
}
transactions := make([]*RPCTransaction, len(block.Transactions))
for i, transaction := range block.Transactions {
transactions[i] = DomainTransactionToRPCTransaction(transaction)
}
return &RPCBlock{
Header: header,
Transactions: transactions,
}
}
// RPCBlockToDomainBlock converts `block` into a DomainBlock
func RPCBlockToDomainBlock(block *RPCBlock) (*externalapi.DomainBlock, error) {
parentHashes := make([]*externalapi.DomainHash, len(block.Header.ParentHashes))
for i, parentHash := range block.Header.ParentHashes {
domainParentHashes, err := externalapi.NewDomainHashFromString(parentHash)
if err != nil {
return nil, err
}
parentHashes[i] = domainParentHashes
}
hashMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.HashMerkleRoot)
if err != nil {
return nil, err
}
acceptedIDMerkleRoot, err := externalapi.NewDomainHashFromString(block.Header.AcceptedIDMerkleRoot)
if err != nil {
return nil, err
}
utxoCommitment, err := externalapi.NewDomainHashFromString(block.Header.UTXOCommitment)
if err != nil {
return nil, err
}
header := blockheader.NewImmutableBlockHeader(
uint16(block.Header.Version),
parentHashes,
hashMerkleRoot,
acceptedIDMerkleRoot,
utxoCommitment,
block.Header.Timestamp,
block.Header.Bits,
block.Header.Nonce)
transactions := make([]*externalapi.DomainTransaction, len(block.Transactions))
for i, transaction := range block.Transactions {
domainTransaction, err := RPCTransactionToDomainTransaction(transaction)
if err != nil {
return nil, err
}
transactions[i] = domainTransaction
}
return &externalapi.DomainBlock{
Header: header,
Transactions: transactions,
}, nil
}

View File

@ -25,7 +25,7 @@ func NewGetBlockRequestMessage(hash string, includeTransactionVerboseData bool)
// its respective RPC message
type GetBlockResponseMessage struct {
baseMessage
BlockVerboseData *BlockVerboseData
Block *RPCBlock
Error *RPCError
}
@ -39,70 +39,3 @@ func (msg *GetBlockResponseMessage) Command() MessageCommand {
func NewGetBlockResponseMessage() *GetBlockResponseMessage {
return &GetBlockResponseMessage{}
}
// BlockVerboseData holds verbose data about a block
type BlockVerboseData struct {
Hash string
Version uint16
VersionHex string
HashMerkleRoot string
AcceptedIDMerkleRoot string
UTXOCommitment string
TxIDs []string
TransactionVerboseData []*TransactionVerboseData
Time int64
Nonce uint64
Bits string
Difficulty float64
ParentHashes []string
ChildrenHashes []string
SelectedParentHash string
BlueScore uint64
IsHeaderOnly bool
}
// TransactionVerboseData holds verbose data about a transaction
type TransactionVerboseData struct {
TxID string
Hash string
Size uint64
Version uint16
LockTime uint64
SubnetworkID string
Gas uint64
Payload string
TransactionVerboseInputs []*TransactionVerboseInput
TransactionVerboseOutputs []*TransactionVerboseOutput
BlockHash string
Time uint64
BlockTime uint64
}
// TransactionVerboseInput holds data about a transaction input
type TransactionVerboseInput struct {
TxID string
OutputIndex uint32
ScriptSig *ScriptSig
Sequence uint64
}
// ScriptSig holds data about a script signature
type ScriptSig struct {
Asm string
Hex string
}
// TransactionVerboseOutput holds data about a transaction output
type TransactionVerboseOutput struct {
Value uint64
Index uint32
ScriptPubKey *ScriptPubKeyResult
}
// ScriptPubKeyResult holds data about a script public key
type ScriptPubKeyResult struct {
Hex string
Type string
Address string
Version uint16
}

View File

@ -23,7 +23,7 @@ func NewGetBlockTemplateRequestMessage(payAddress string) *GetBlockTemplateReque
// its respective RPC message
type GetBlockTemplateResponseMessage struct {
baseMessage
MsgBlock *MsgBlock
Block *RPCBlock
IsSynced bool
Error *RPCError
@ -35,9 +35,9 @@ func (msg *GetBlockTemplateResponseMessage) Command() MessageCommand {
}
// NewGetBlockTemplateResponseMessage returns a instance of the message
func NewGetBlockTemplateResponseMessage(msgBlock *MsgBlock, isSynced bool) *GetBlockTemplateResponseMessage {
func NewGetBlockTemplateResponseMessage(block *RPCBlock, isSynced bool) *GetBlockTemplateResponseMessage {
return &GetBlockTemplateResponseMessage{
MsgBlock: msgBlock,
Block: block,
IsSynced: isSynced,
}
}

View File

@ -5,7 +5,7 @@ package appmessage
type GetBlocksRequestMessage struct {
baseMessage
LowHash string
IncludeBlockVerboseData bool
IncludeBlocks bool
IncludeTransactionVerboseData bool
}
@ -15,11 +15,11 @@ func (msg *GetBlocksRequestMessage) Command() MessageCommand {
}
// NewGetBlocksRequestMessage returns a instance of the message
func NewGetBlocksRequestMessage(lowHash string, includeBlockVerboseData bool,
func NewGetBlocksRequestMessage(lowHash string, includeBlocks bool,
includeTransactionVerboseData bool) *GetBlocksRequestMessage {
return &GetBlocksRequestMessage{
LowHash: lowHash,
IncludeBlockVerboseData: includeBlockVerboseData,
IncludeBlocks: includeBlocks,
IncludeTransactionVerboseData: includeTransactionVerboseData,
}
}
@ -28,8 +28,8 @@ func NewGetBlocksRequestMessage(lowHash string, includeBlockVerboseData bool,
// its respective RPC message
type GetBlocksResponseMessage struct {
baseMessage
BlockHashes []string
BlockVerboseData []*BlockVerboseData
BlockHashes []string
Blocks []*RPCBlock
Error *RPCError
}
@ -40,11 +40,6 @@ func (msg *GetBlocksResponseMessage) Command() MessageCommand {
}
// NewGetBlocksResponseMessage returns a instance of the message
func NewGetBlocksResponseMessage(blockHashes []string, blockHexes []string,
blockVerboseData []*BlockVerboseData) *GetBlocksResponseMessage {
return &GetBlocksResponseMessage{
BlockHashes: blockHashes,
BlockVerboseData: blockVerboseData,
}
func NewGetBlocksResponseMessage() *GetBlocksResponseMessage {
return &GetBlocksResponseMessage{}
}

View File

@ -28,8 +28,8 @@ type GetMempoolEntryResponseMessage struct {
// MempoolEntry represents a transaction in the mempool.
type MempoolEntry struct {
Fee uint64
TransactionVerboseData *TransactionVerboseData
Fee uint64
Transaction *RPCTransaction
}
// Command returns the protocol command string for the message
@ -38,11 +38,11 @@ func (msg *GetMempoolEntryResponseMessage) Command() MessageCommand {
}
// NewGetMempoolEntryResponseMessage returns a instance of the message
func NewGetMempoolEntryResponseMessage(fee uint64, transactionVerboseData *TransactionVerboseData) *GetMempoolEntryResponseMessage {
func NewGetMempoolEntryResponseMessage(fee uint64, transaction *RPCTransaction) *GetMempoolEntryResponseMessage {
return &GetMempoolEntryResponseMessage{
Entry: &MempoolEntry{
Fee: fee,
TransactionVerboseData: transactionVerboseData,
Fee: fee,
Transaction: transaction,
},
}
}

View File

@ -37,8 +37,7 @@ func NewNotifyBlockAddedResponseMessage() *NotifyBlockAddedResponseMessage {
// its respective RPC message
type BlockAddedNotificationMessage struct {
baseMessage
Block *MsgBlock
BlockVerboseData *BlockVerboseData
Block *RPCBlock
}
// Command returns the protocol command string for the message
@ -47,9 +46,8 @@ func (msg *BlockAddedNotificationMessage) Command() MessageCommand {
}
// NewBlockAddedNotificationMessage returns a instance of the message
func NewBlockAddedNotificationMessage(block *MsgBlock, blockVerboseData *BlockVerboseData) *BlockAddedNotificationMessage {
func NewBlockAddedNotificationMessage(block *RPCBlock) *BlockAddedNotificationMessage {
return &BlockAddedNotificationMessage{
Block: block,
BlockVerboseData: blockVerboseData,
Block: block,
}
}

View File

@ -4,7 +4,7 @@ package appmessage
// its respective RPC message
type SubmitBlockRequestMessage struct {
baseMessage
Block *MsgBlock
Block *RPCBlock
}
// Command returns the protocol command string for the message
@ -13,7 +13,7 @@ func (msg *SubmitBlockRequestMessage) Command() MessageCommand {
}
// NewSubmitBlockRequestMessage returns a instance of the message
func NewSubmitBlockRequestMessage(block *MsgBlock) *SubmitBlockRequestMessage {
func NewSubmitBlockRequestMessage(block *RPCBlock) *SubmitBlockRequestMessage {
return &SubmitBlockRequestMessage{
Block: block,
}
@ -57,3 +57,35 @@ func (msg *SubmitBlockResponseMessage) Command() MessageCommand {
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
return &SubmitBlockResponseMessage{}
}
// RPCBlock is a kaspad block representation meant to be
// used over RPC
type RPCBlock struct {
Header *RPCBlockHeader
Transactions []*RPCTransaction
VerboseData *RPCBlockVerboseData
}
// RPCBlockHeader is a kaspad block header representation meant to be
// used over RPC
type RPCBlockHeader struct {
Version uint32
ParentHashes []string
HashMerkleRoot string
AcceptedIDMerkleRoot string
UTXOCommitment string
Timestamp int64
Bits uint32
Nonce uint64
}
// RPCBlockVerboseData holds verbose data about a block
type RPCBlockVerboseData struct {
Hash string
Difficulty float64
SelectedParentHash string
TransactionIDs []string
IsHeaderOnly bool
BlueScore uint64
ChildrenHashes []string
}

View File

@ -50,6 +50,7 @@ type RPCTransaction struct {
SubnetworkID string
Gas uint64
Payload string
VerboseData *RPCTransactionVerboseData
}
// RPCTransactionInput is a kaspad transaction input representation
@ -58,6 +59,7 @@ type RPCTransactionInput struct {
PreviousOutpoint *RPCOutpoint
SignatureScript string
Sequence uint64
VerboseData *RPCTransactionInputVerboseData
}
// RPCScriptPublicKey is a kaspad ScriptPublicKey representation
@ -71,6 +73,7 @@ type RPCScriptPublicKey struct {
type RPCTransactionOutput struct {
Amount uint64
ScriptPublicKey *RPCScriptPublicKey
VerboseData *RPCTransactionOutputVerboseData
}
// RPCOutpoint is a kaspad outpoint representation meant to be used
@ -88,3 +91,22 @@ type RPCUTXOEntry struct {
BlockDAAScore uint64
IsCoinbase bool
}
// RPCTransactionVerboseData holds verbose data about a transaction
type RPCTransactionVerboseData struct {
TransactionID string
Hash string
Size uint64
BlockHash string
BlockTime uint64
}
// RPCTransactionInputVerboseData holds data about a transaction input
type RPCTransactionInputVerboseData struct {
}
// RPCTransactionOutputVerboseData holds data about a transaction output
type RPCTransactionOutputVerboseData struct {
ScriptPublicKeyType string
ScriptPublicKeyAddress string
}

View File

@ -129,7 +129,7 @@ type fakeRelayInvsContext struct {
rwLock sync.RWMutex
}
func (f *fakeRelayInvsContext) GetBlockChildren(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
func (f *fakeRelayInvsContext) GetBlockRelations(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, *externalapi.DomainHash, []*externalapi.DomainHash, error) {
panic(errors.Errorf("called unimplemented function from test '%s'", f.testName))
}

View File

@ -69,12 +69,12 @@ func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockIns
return err
}
msgBlock := appmessage.DomainBlockToMsgBlock(block)
blockVerboseData, err := m.context.BuildBlockVerboseData(block.Header, block, false)
rpcBlock := appmessage.DomainBlockToRPCBlock(block)
err = m.context.PopulateBlockWithVerboseData(rpcBlock, block.Header, block, false)
if err != nil {
return err
}
blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(msgBlock, blockVerboseData)
blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(rpcBlock)
return m.context.NotificationManager.NotifyBlockAdded(blockAddedNotification)
}

View File

@ -2,15 +2,10 @@ package rpccontext
import (
"encoding/hex"
"fmt"
difficultyPackage "github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
"math"
"math/big"
"strconv"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
@ -26,79 +21,6 @@ import (
// ErrBuildBlockVerboseDataInvalidBlock indicates that a block that was given to BuildBlockVerboseData is invalid.
var ErrBuildBlockVerboseDataInvalidBlock = errors.New("ErrBuildBlockVerboseDataInvalidBlock")
// BuildBlockVerboseData builds a BlockVerboseData from the given blockHeader.
// A block may optionally also be given if it's available in the calling context.
func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, block *externalapi.DomainBlock,
includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockVerboseData")
defer onEnd()
hash := consensushashing.HeaderHash(blockHeader)
blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(hash)
if err != nil {
return nil, err
}
if blockInfo.BlockStatus == externalapi.StatusInvalid {
return nil, errors.Wrap(ErrBuildBlockVerboseDataInvalidBlock, "cannot build verbose data for "+
"invalid block")
}
childrenHashes, err := ctx.Domain.Consensus().GetBlockChildren(hash)
if err != nil {
return nil, err
}
result := &appmessage.BlockVerboseData{
Hash: hash.String(),
Version: blockHeader.Version(),
VersionHex: fmt.Sprintf("%08x", blockHeader.Version()),
HashMerkleRoot: blockHeader.HashMerkleRoot().String(),
AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot().String(),
UTXOCommitment: blockHeader.UTXOCommitment().String(),
ParentHashes: hashes.ToStrings(blockHeader.ParentHashes()),
ChildrenHashes: hashes.ToStrings(childrenHashes),
Nonce: blockHeader.Nonce(),
Time: blockHeader.TimeInMilliseconds(),
Bits: strconv.FormatInt(int64(blockHeader.Bits()), 16),
Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits(), ctx.Config.ActiveNetParams),
BlueScore: blockInfo.BlueScore,
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
}
if blockInfo.BlockStatus != externalapi.StatusHeaderOnly {
if block == nil {
block, err = ctx.Domain.Consensus().GetBlock(hash)
if err != nil {
return nil, err
}
}
txIDs := make([]string, len(block.Transactions))
for i, tx := range block.Transactions {
txIDs[i] = consensushashing.TransactionID(tx).String()
}
result.TxIDs = txIDs
if includeTransactionVerboseData {
transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(block.Transactions))
for i, tx := range block.Transactions {
txID := consensushashing.TransactionID(tx).String()
data, err := ctx.BuildTransactionVerboseData(tx, txID, blockHeader, hash.String())
if err != nil {
return nil, err
}
transactionVerboseData[i] = data
}
result.TransactionVerboseData = transactionVerboseData
}
}
return result, nil
}
// GetDifficultyRatio returns the proof-of-work difficulty as a multiple of the
// minimum difficulty using the passed bits field from the header of a block.
func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) float64 {
@ -106,7 +28,7 @@ func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) fl
// converted back to a number. Note this is not the same as the proof of
// work limit directly because the block difficulty is encoded in a block
// with the compact form which loses precision.
target := difficulty.CompactToBig(bits)
target := difficultyPackage.CompactToBig(bits)
difficulty := new(big.Rat).SetFrac(params.PowMax, target)
diff, _ := difficulty.Float64()
@ -117,100 +39,125 @@ func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) fl
return diff
}
// BuildTransactionVerboseData builds a TransactionVerboseData from
// the given parameters
func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransaction, txID string,
blockHeader externalapi.BlockHeader, blockHash string) (
*appmessage.TransactionVerboseData, error) {
// PopulateBlockWithVerboseData populates the given `block` with verbose
// data from `domainBlockHeader` and optionally from `domainBlock`
func (ctx *Context) PopulateBlockWithVerboseData(block *appmessage.RPCBlock, domainBlockHeader externalapi.BlockHeader,
domainBlock *externalapi.DomainBlock, includeTransactionVerboseData bool) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildTransactionVerboseData")
defer onEnd()
blockHash := consensushashing.HeaderHash(domainBlockHeader)
txReply := &appmessage.TransactionVerboseData{
TxID: txID,
Hash: consensushashing.TransactionHash(tx).String(),
Size: estimatedsize.TransactionEstimatedSerializedSize(tx),
TransactionVerboseInputs: ctx.buildTransactionVerboseInputs(tx),
TransactionVerboseOutputs: ctx.buildTransactionVerboseOutputs(tx, nil),
Version: tx.Version,
LockTime: tx.LockTime,
SubnetworkID: tx.SubnetworkID.String(),
Gas: tx.Gas,
Payload: hex.EncodeToString(tx.Payload),
blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(blockHash)
if err != nil {
return err
}
if blockHeader != nil {
txReply.Time = uint64(blockHeader.TimeInMilliseconds())
txReply.BlockTime = uint64(blockHeader.TimeInMilliseconds())
txReply.BlockHash = blockHash
if blockInfo.BlockStatus == externalapi.StatusInvalid {
return errors.Wrap(ErrBuildBlockVerboseDataInvalidBlock, "cannot build verbose data for "+
"invalid block")
}
return txReply, nil
}
_, selectedParentHash, childrenHashes, err := ctx.Domain.Consensus().GetBlockRelations(blockHash)
if err != nil {
return err
}
func (ctx *Context) buildTransactionVerboseInputs(tx *externalapi.DomainTransaction) []*appmessage.TransactionVerboseInput {
inputs := make([]*appmessage.TransactionVerboseInput, len(tx.Inputs))
for i, transactionInput := range tx.Inputs {
// The disassembled string will contain [error] inline
// if the script doesn't fully parse, so ignore the
// error here.
disbuf, _ := txscript.DisasmString(constants.MaxScriptPublicKeyVersion, transactionInput.SignatureScript)
block.VerboseData = &appmessage.RPCBlockVerboseData{
Hash: blockHash.String(),
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
ChildrenHashes: hashes.ToStrings(childrenHashes),
SelectedParentHash: selectedParentHash.String(),
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
BlueScore: blockInfo.BlueScore,
}
input := &appmessage.TransactionVerboseInput{}
input.TxID = transactionInput.PreviousOutpoint.TransactionID.String()
input.OutputIndex = transactionInput.PreviousOutpoint.Index
input.Sequence = transactionInput.Sequence
input.ScriptSig = &appmessage.ScriptSig{
Asm: disbuf,
Hex: hex.EncodeToString(transactionInput.SignatureScript),
if blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
return nil
}
// Get the block if we didn't receive it previously
if domainBlock == nil {
domainBlock, err = ctx.Domain.Consensus().GetBlock(blockHash)
if err != nil {
return err
}
inputs[i] = input
}
return inputs
}
transactionIDs := make([]string, len(domainBlock.Transactions))
for i, transaction := range domainBlock.Transactions {
transactionIDs[i] = consensushashing.TransactionID(transaction).String()
}
block.VerboseData.TransactionIDs = transactionIDs
// buildTransactionVerboseOutputs returns a slice of JSON objects for the outputs of the passed
// transaction.
func (ctx *Context) buildTransactionVerboseOutputs(tx *externalapi.DomainTransaction, filterAddrMap map[string]struct{}) []*appmessage.TransactionVerboseOutput {
outputs := make([]*appmessage.TransactionVerboseOutput, len(tx.Outputs))
for i, transactionOutput := range tx.Outputs {
// Ignore the error here since an error means the script
// couldn't parse and there is no additional information about
// it anyways.
scriptClass, addr, _ := txscript.ExtractScriptPubKeyAddress(
transactionOutput.ScriptPublicKey, ctx.Config.ActiveNetParams)
// Encode the addresses while checking if the address passes the
// filter when needed.
passesFilter := len(filterAddrMap) == 0
var encodedAddr string
if addr != nil {
encodedAddr = addr.EncodeAddress()
// If the filter doesn't already pass, make it pass if
// the address exists in the filter.
if _, exists := filterAddrMap[encodedAddr]; exists {
passesFilter = true
if includeTransactionVerboseData {
for _, transaction := range block.Transactions {
err := ctx.PopulateTransactionWithVerboseData(transaction, domainBlockHeader)
if err != nil {
return err
}
}
if !passesFilter {
continue
}
output := &appmessage.TransactionVerboseOutput{}
output.Index = uint32(i)
output.Value = transactionOutput.Value
output.ScriptPubKey = &appmessage.ScriptPubKeyResult{
Version: transactionOutput.ScriptPublicKey.Version,
Address: encodedAddr,
Hex: hex.EncodeToString(transactionOutput.ScriptPublicKey.Script),
Type: scriptClass.String(),
}
outputs[i] = output
}
return outputs
return nil
}
// PopulateTransactionWithVerboseData populates the given `transaction` with
// verbose data from `domainTransaction`
func (ctx *Context) PopulateTransactionWithVerboseData(
transaction *appmessage.RPCTransaction, domainBlockHeader externalapi.BlockHeader) error {
domainTransaction, err := appmessage.RPCTransactionToDomainTransaction(transaction)
if err != nil {
return err
}
transaction.VerboseData = &appmessage.RPCTransactionVerboseData{
TransactionID: consensushashing.TransactionID(domainTransaction).String(),
Hash: consensushashing.TransactionHash(domainTransaction).String(),
Size: estimatedsize.TransactionEstimatedSerializedSize(domainTransaction),
}
if domainBlockHeader != nil {
transaction.VerboseData.BlockHash = consensushashing.HeaderHash(domainBlockHeader).String()
transaction.VerboseData.BlockTime = uint64(domainBlockHeader.TimeInMilliseconds())
}
for _, input := range transaction.Inputs {
ctx.populateTransactionInputWithVerboseData(input)
}
for _, output := range transaction.Outputs {
err := ctx.populateTransactionOutputWithVerboseData(output)
if err != nil {
return err
}
}
return nil
}
func (ctx *Context) populateTransactionInputWithVerboseData(transactionInput *appmessage.RPCTransactionInput) {
transactionInput.VerboseData = &appmessage.RPCTransactionInputVerboseData{}
}
func (ctx *Context) populateTransactionOutputWithVerboseData(transactionOutput *appmessage.RPCTransactionOutput) error {
scriptPublicKey, err := hex.DecodeString(transactionOutput.ScriptPublicKey.Script)
if err != nil {
return err
}
domainScriptPublicKey := &externalapi.ScriptPublicKey{
Script: scriptPublicKey,
Version: transactionOutput.ScriptPublicKey.Version,
}
// Ignore the error here since an error means the script
// couldn't be parsed and there's no additional information about
// it anyways
scriptPublicKeyType, scriptPublicKeyAddress, _ := txscript.ExtractScriptPubKeyAddress(
domainScriptPublicKey, ctx.Config.ActiveNetParams)
var encodedScriptPublicKeyAddress string
if scriptPublicKeyAddress != nil {
encodedScriptPublicKeyAddress = scriptPublicKeyAddress.EncodeAddress()
}
transactionOutput.VerboseData = &appmessage.RPCTransactionOutputVerboseData{
ScriptPublicKeyType: scriptPublicKeyType.String(),
ScriptPublicKeyAddress: encodedScriptPublicKeyAddress,
}
return nil
}

View File

@ -26,10 +26,12 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme
errorMessage.Error = appmessage.RPCErrorf("Block %s not found", hash)
return errorMessage, nil
}
block := &externalapi.DomainBlock{Header: header}
response := appmessage.NewGetBlockResponseMessage()
response.Block = appmessage.DomainBlockToRPCBlock(block)
blockVerboseData, err := context.BuildBlockVerboseData(header, nil, getBlockRequest.IncludeTransactionVerboseData)
err = context.PopulateBlockWithVerboseData(response.Block, header, nil, getBlockRequest.IncludeTransactionVerboseData)
if err != nil {
if errors.Is(err, rpccontext.ErrBuildBlockVerboseDataInvalidBlock) {
errorMessage := &appmessage.GetBlockResponseMessage{}
@ -39,7 +41,5 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme
return nil, err
}
response.BlockVerboseData = blockVerboseData
return response, nil
}

View File

@ -31,12 +31,12 @@ func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, reque
if err != nil {
return nil, err
}
msgBlock := appmessage.DomainBlockToMsgBlock(templateBlock)
rpcBlock := appmessage.DomainBlockToRPCBlock(templateBlock)
isSynced, err := context.ProtocolManager.ShouldMine()
if err != nil {
return nil, err
}
return appmessage.NewGetBlockTemplateResponseMessage(msgBlock, isSynced), nil
return appmessage.NewGetBlockTemplateResponseMessage(rpcBlock, isSynced), nil
}

View File

@ -18,8 +18,8 @@ const (
func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage)
// Validate that user didn't set IncludeTransactionVerboseData without setting IncludeBlockVerboseData
if !getBlocksRequest.IncludeBlockVerboseData && getBlocksRequest.IncludeTransactionVerboseData {
// Validate that user didn't set IncludeTransactionVerboseData without setting IncludeBlocks
if !getBlocksRequest.IncludeBlocks && getBlocksRequest.IncludeTransactionVerboseData {
return &appmessage.GetBlocksResponseMessage{
Error: appmessage.RPCErrorf(
"If includeTransactionVerboseData is set, then includeBlockVerboseData must be set as well"),
@ -81,26 +81,23 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm
}
// Prepare the response
response := &appmessage.GetBlocksResponseMessage{
BlockHashes: hashes.ToStrings(blockHashes),
}
// Retrieve all block data in case BlockVerboseData was requested
if getBlocksRequest.IncludeBlockVerboseData {
response.BlockVerboseData = make([]*appmessage.BlockVerboseData, len(blockHashes))
response := appmessage.NewGetBlocksResponseMessage()
response.BlockHashes = hashes.ToStrings(blockHashes)
if getBlocksRequest.IncludeBlocks {
blocks := make([]*appmessage.RPCBlock, len(blockHashes))
for i, blockHash := range blockHashes {
blockHeader, err := context.Domain.Consensus().GetBlockHeader(blockHash)
if err != nil {
return nil, err
}
blockVerboseData, err := context.BuildBlockVerboseData(blockHeader, nil,
getBlocksRequest.IncludeTransactionVerboseData)
block := &externalapi.DomainBlock{Header: blockHeader}
blocks[i] = appmessage.DomainBlockToRPCBlock(block)
err = context.PopulateBlockWithVerboseData(blocks[i], blockHeader, nil, getBlocksRequest.IncludeTransactionVerboseData)
if err != nil {
return nil, err
}
response.BlockVerboseData[i] = blockVerboseData
}
}
return response, nil
}

View File

@ -3,25 +3,22 @@ package rpchandlers
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
)
// HandleGetMempoolEntries handles the respectively named RPC command
func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
transactions := context.Domain.MiningManager().AllTransactions()
entries := make([]*appmessage.MempoolEntry, 0, len(transactions))
for _, tx := range transactions {
transactionVerboseData, err := context.BuildTransactionVerboseData(
tx, consensushashing.TransactionID(tx).String(), nil, "")
for _, transaction := range transactions {
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
err := context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
if err != nil {
return nil, err
}
entries = append(entries, &appmessage.MempoolEntry{
Fee: tx.Fee,
TransactionVerboseData: transactionVerboseData,
Fee: transaction.Fee,
Transaction: rpcTransaction,
})
}

View File

@ -24,12 +24,11 @@ func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, reques
errorMessage.Error = appmessage.RPCErrorf("Transaction %s was not found", transactionID)
return errorMessage, nil
}
transactionVerboseData, err := context.BuildTransactionVerboseData(
transaction, getMempoolEntryRequest.TxID, nil, "")
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
err = context.PopulateTransactionWithVerboseData(rpcTransaction, nil)
if err != nil {
return nil, err
}
return appmessage.NewGetMempoolEntryResponseMessage(transaction.Fee, transactionVerboseData), nil
return appmessage.NewGetMempoolEntryResponseMessage(transaction.Fee, rpcTransaction), nil
}

View File

@ -14,9 +14,6 @@ import (
func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
submitBlockRequest := request.(*appmessage.SubmitBlockRequestMessage)
msgBlock := submitBlockRequest.Block
domainBlock := appmessage.MsgBlockToDomainBlock(msgBlock)
if context.ProtocolManager.IsIBDRunning() {
return &appmessage.SubmitBlockResponseMessage{
Error: appmessage.RPCErrorf("Block not submitted - IBD is running"),
@ -24,7 +21,15 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap
}, nil
}
err := context.ProtocolManager.AddBlock(domainBlock)
domainBlock, err := appmessage.RPCBlockToDomainBlock(submitBlockRequest.Block)
if err != nil {
return &appmessage.SubmitBlockResponseMessage{
Error: appmessage.RPCErrorf("Could not parse block: %s", err),
RejectReason: appmessage.RejectReasonBlockInvalid,
}, nil
}
err = context.ProtocolManager.AddBlock(domainBlock)
if err != nil {
isProtocolOrRuleError := errors.As(err, &ruleerrors.RuleError{}) || errors.As(err, &protocolerrors.ProtocolError{})
if !isProtocolOrRuleError {

View File

@ -198,7 +198,11 @@ func templatesLoop(client *minerClient, miningAddr util.Address, errChan chan er
errChan <- errors.Wrapf(err, "Error getting block template from %s", client.safeRPCClient().Address())
return
}
templatemanager.Set(template)
err = templatemanager.Set(template)
if err != nil {
errChan <- errors.Wrapf(err, "Error setting block template from %s", client.safeRPCClient().Address())
return
}
}
getBlockTemplate()

View File

@ -23,10 +23,14 @@ func Get() (*externalapi.DomainBlock, bool) {
}
// Set sets the current template to work on
func Set(template *appmessage.GetBlockTemplateResponseMessage) {
block := appmessage.MsgBlockToDomainBlock(template.MsgBlock)
func Set(template *appmessage.GetBlockTemplateResponseMessage) error {
block, err := appmessage.RPCBlockToDomainBlock(template.Block)
if err != nil {
return err
}
lock.Lock()
defer lock.Unlock()
currentTemplate = block
isSynced = template.IsSynced
return nil
}

View File

@ -166,7 +166,10 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
return blockInfo, nil
}
func (s *consensus) GetBlockChildren(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
func (s *consensus) GetBlockRelations(blockHash *externalapi.DomainHash) (
parents []*externalapi.DomainHash, selectedParent *externalapi.DomainHash,
children []*externalapi.DomainHash, err error) {
s.lock.Lock()
defer s.lock.Unlock()
@ -174,10 +177,15 @@ func (s *consensus) GetBlockChildren(blockHash *externalapi.DomainHash) ([]*exte
blockRelation, err := s.blockRelationStore.BlockRelation(s.databaseContext, stagingArea, blockHash)
if err != nil {
return nil, err
return nil, nil, nil, err
}
return blockRelation.Children, nil
blockGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, stagingArea, blockHash)
if err != nil {
return nil, nil, nil, err
}
return blockRelation.Parents, blockGHOSTDAGData.SelectedParent(), blockRelation.Children, nil
}
func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) {

View File

@ -9,7 +9,7 @@ type Consensus interface {
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
GetBlockHeader(blockHash *DomainHash) (BlockHeader, error)
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)
GetBlockChildren(blockHash *DomainHash) ([]*DomainHash, error)
GetBlockRelations(blockHash *DomainHash) (parents []*DomainHash, selectedParent *DomainHash, children []*DomainHash, err error)
GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error)
GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) (hashes []*DomainHash, actualHighHash *DomainHash, err error)

View File

@ -4,30 +4,32 @@
## Table of Contents
- [rpc.proto](#rpc.proto)
- [RPCError](#protowire.RPCError)
- [GetCurrentNetworkRequestMessage](#protowire.GetCurrentNetworkRequestMessage)
- [GetCurrentNetworkResponseMessage](#protowire.GetCurrentNetworkResponseMessage)
- [SubmitBlockRequestMessage](#protowire.SubmitBlockRequestMessage)
- [SubmitBlockResponseMessage](#protowire.SubmitBlockResponseMessage)
- [GetBlockTemplateRequestMessage](#protowire.GetBlockTemplateRequestMessage)
- [GetBlockTemplateResponseMessage](#protowire.GetBlockTemplateResponseMessage)
- [NotifyBlockAddedRequestMessage](#protowire.NotifyBlockAddedRequestMessage)
- [NotifyBlockAddedResponseMessage](#protowire.NotifyBlockAddedResponseMessage)
- [BlockAddedNotificationMessage](#protowire.BlockAddedNotificationMessage)
- [GetPeerAddressesRequestMessage](#protowire.GetPeerAddressesRequestMessage)
- [GetPeerAddressesResponseMessage](#protowire.GetPeerAddressesResponseMessage)
- [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage)
- [GetSelectedTipHashRequestMessage](#protowire.GetSelectedTipHashRequestMessage)
- [GetSelectedTipHashResponseMessage](#protowire.GetSelectedTipHashResponseMessage)
- [GetMempoolEntryRequestMessage](#protowire.GetMempoolEntryRequestMessage)
- [GetMempoolEntryResponseMessage](#protowire.GetMempoolEntryResponseMessage)
- [GetMempoolEntriesRequestMessage](#protowire.GetMempoolEntriesRequestMessage)
- [GetMempoolEntriesResponseMessage](#protowire.GetMempoolEntriesResponseMessage)
- [MempoolEntry](#protowire.MempoolEntry)
- [GetConnectedPeerInfoRequestMessage](#protowire.GetConnectedPeerInfoRequestMessage)
- [GetConnectedPeerInfoResponseMessage](#protowire.GetConnectedPeerInfoResponseMessage)
- [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage)
- [AddPeerRequestMessage](#protowire.AddPeerRequestMessage)
- [RPCError](#protowire.RPCError)
- [GetCurrentNetworkRequestMessage](#protowire.GetCurrentNetworkRequestMessage)
- [GetCurrentNetworkResponseMessage](#protowire.GetCurrentNetworkResponseMessage)
- [SubmitBlockRequestMessage](#protowire.SubmitBlockRequestMessage)
- [RpcBlock](#protowire.RpcBlock)
- [RpcBlockHeader](#protowire.RpcBlockHeader)
- [SubmitBlockResponseMessage](#protowire.SubmitBlockResponseMessage)
- [GetBlockTemplateRequestMessage](#protowire.GetBlockTemplateRequestMessage)
- [GetBlockTemplateResponseMessage](#protowire.GetBlockTemplateResponseMessage)
- [NotifyBlockAddedRequestMessage](#protowire.NotifyBlockAddedRequestMessage)
- [NotifyBlockAddedResponseMessage](#protowire.NotifyBlockAddedResponseMessage)
- [BlockAddedNotificationMessage](#protowire.BlockAddedNotificationMessage)
- [GetPeerAddressesRequestMessage](#protowire.GetPeerAddressesRequestMessage)
- [GetPeerAddressesResponseMessage](#protowire.GetPeerAddressesResponseMessage)
- [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage)
- [GetSelectedTipHashRequestMessage](#protowire.GetSelectedTipHashRequestMessage)
- [GetSelectedTipHashResponseMessage](#protowire.GetSelectedTipHashResponseMessage)
- [GetMempoolEntryRequestMessage](#protowire.GetMempoolEntryRequestMessage)
- [GetMempoolEntryResponseMessage](#protowire.GetMempoolEntryResponseMessage)
- [GetMempoolEntriesRequestMessage](#protowire.GetMempoolEntriesRequestMessage)
- [GetMempoolEntriesResponseMessage](#protowire.GetMempoolEntriesResponseMessage)
- [MempoolEntry](#protowire.MempoolEntry)
- [GetConnectedPeerInfoRequestMessage](#protowire.GetConnectedPeerInfoRequestMessage)
- [GetConnectedPeerInfoResponseMessage](#protowire.GetConnectedPeerInfoResponseMessage)
- [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage)
- [AddPeerRequestMessage](#protowire.AddPeerRequestMessage)
- [AddPeerResponseMessage](#protowire.AddPeerResponseMessage)
- [SubmitTransactionRequestMessage](#protowire.SubmitTransactionRequestMessage)
- [SubmitTransactionResponseMessage](#protowire.SubmitTransactionResponseMessage)
@ -41,9 +43,7 @@
- [BlockVerboseData](#protowire.BlockVerboseData)
- [TransactionVerboseData](#protowire.TransactionVerboseData)
- [TransactionVerboseInput](#protowire.TransactionVerboseInput)
- [ScriptSig](#protowire.ScriptSig)
- [TransactionVerboseOutput](#protowire.TransactionVerboseOutput)
- [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult)
- [GetSubnetworkRequestMessage](#protowire.GetSubnetworkRequestMessage)
- [GetSubnetworkResponseMessage](#protowire.GetSubnetworkResponseMessage)
- [GetVirtualSelectedParentChainFromBlockRequestMessage](#protowire.GetVirtualSelectedParentChainFromBlockRequestMessage)
@ -163,27 +163,44 @@ Possible networks are: Mainnet, Testnet, Simnet, Devnet
<a name="protowire.SubmitBlockRequestMessage"></a>
### SubmitBlockRequestMessage
SubmitBlockRequestMessage requests to submit a block into the DAG.
Blocks are generally expected to have been generated using the getBlockTemplate call.
SubmitBlockRequestMessage requests to submit a block into the DAG. Blocks are generally expected to have been generated
using the getBlockTemplate call.
See: GetBlockTemplateRequestMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| block | [RpcBlock](#protowire.RpcBlock) | | |
<a name="protowire.RpcBlock"></a>
### RpcBlock
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| block | [BlockMessage](#protowire.BlockMessage) | | |
| header | [RpcBlockHeader](#protowire.RpcBlockHeader) | | |
| transactions | [RpcTransaction](#protowire.RpcTransaction) | repeated | |
<a name="protowire.RpcBlockHeader"></a>
### RpcBlockHeader
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| version | [uint32](#uint32) | | |
| parentHashes | [string](#string) | repeated | |
| hashMerkleRoot | [string](#string) | | |
| acceptedIdMerkleRoot | [string](#string) | | |
| utxoCommitment | [string](#string) | | |
| timestamp | [int64](#int64) | | |
| bits | [uint32](#uint32) | | |
| nonce | [uint64](#uint64) | | |
<a name="protowire.SubmitBlockResponseMessage"></a>
### SubmitBlockResponseMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| rejectReason | [SubmitBlockResponseMessage.RejectReason](#protowire.SubmitBlockResponseMessage.RejectReason) | | |
@ -220,7 +237,7 @@ See: SubmitBlockRequestMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| blockMessage | [BlockMessage](#protowire.BlockMessage) | | |
| block | [RpcBlock](#protowire.RpcBlock) | | |
| isSynced | [bool](#bool) | | Whether kaspad thinks that it&#39;s synced. Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. That is because when kaspad isn&#39;t in sync with the rest of the network there&#39;s a high chance the block will never be accepted, thus the solving effort would have been wasted. |
| error | [RPCError](#protowire.RPCError) | | |
@ -267,7 +284,6 @@ See: NotifyBlockAddedRequestMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| block | [BlockMessage](#protowire.BlockMessage) | | |
| blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | | |
@ -653,17 +669,9 @@ GetBlockRequestMessage requests information about a specific block
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| hash | [string](#string) | | |
| version | [uint32](#uint32) | | |
| versionHex | [string](#string) | | |
| hashMerkleRoot | [string](#string) | | |
| acceptedIDMerkleRoot | [string](#string) | | |
| utxoCommitment | [string](#string) | | |
| block | [RpcBlock](#protowire.RpcBlock) | | |
| transactionVerboseData | [TransactionVerboseData](#protowire.TransactionVerboseData) | repeated | |
| time | [int64](#int64) | | |
| nonce | [uint64](#uint64) | | |
| bits | [string](#string) | | |
| difficulty | [double](#double) | | |
| parentHashes | [string](#string) | repeated | |
| childrenHashes | [string](#string) | repeated | |
| selectedParentHash | [string](#string) | | |
| transactionIDs | [string](#string) | repeated | |
@ -686,16 +694,11 @@ GetBlockRequestMessage requests information about a specific block
| txId | [string](#string) | | |
| hash | [string](#string) | | |
| size | [uint64](#uint64) | | |
| version | [uint32](#uint32) | | |
| lockTime | [uint64](#uint64) | | |
| subnetworkId | [string](#string) | | |
| gas | [uint64](#uint64) | | |
| payload | [string](#string) | | |
| transactionVerboseInputs | [TransactionVerboseInput](#protowire.TransactionVerboseInput) | repeated | |
| transactionVerboseOutputs | [TransactionVerboseOutput](#protowire.TransactionVerboseOutput) | repeated | |
| blockHash | [string](#string) | | |
| time | [uint64](#uint64) | | |
| blockTime | [uint64](#uint64) | | |
| transaction | [RpcTransaction](#protowire.RpcTransaction) | | |
@ -708,30 +711,6 @@ GetBlockRequestMessage requests information about a specific block
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| txId | [string](#string) | | |
| outputIndex | [uint32](#uint32) | | |
| scriptSig | [ScriptSig](#protowire.ScriptSig) | | |
| sequence | [uint64](#uint64) | | |
<a name="protowire.ScriptSig"></a>
### ScriptSig
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| asm | [string](#string) | | |
| hex | [string](#string) | | |
@ -740,32 +719,10 @@ GetBlockRequestMessage requests information about a specific block
### TransactionVerboseOutput
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| value | [uint64](#uint64) | | |
| index | [uint32](#uint32) | | |
| scriptPublicKey | [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) | | |
<a name="protowire.ScriptPublicKeyResult"></a>
### ScriptPublicKeyResult
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| asm | [string](#string) | | |
| hex | [string](#string) | | |
| type | [string](#string) | | |
| address | [string](#string) | | |
| version | [uint32](#uint32) | | |
| scriptPublicKeyType | [string](#string) | | |
| scriptPublicKeyAddress | [string](#string) | | |

View File

@ -12,8 +12,6 @@ package protowire;
option go_package = "github.com/kaspanet/kaspad/protowire";
import "p2p.proto";
// RPCError represents a generic non-internal error.
//
// Receivers of any ResponseMessage are expected to check whether its error field is not null.
@ -21,6 +19,90 @@ message RPCError{
string message = 1;
}
message RpcBlock {
RpcBlockHeader header = 1;
repeated RpcTransaction transactions = 2;
RpcBlockVerboseData verboseData = 3;
}
message RpcBlockHeader {
uint32 version = 1;
repeated string parentHashes = 2;
string hashMerkleRoot = 3;
string acceptedIdMerkleRoot = 4;
string utxoCommitment = 5;
int64 timestamp = 6;
uint32 bits = 7;
uint64 nonce = 8;
}
message RpcBlockVerboseData{
string hash = 1;
double difficulty = 11;
string selectedParentHash = 13;
repeated string transactionIds = 14;
bool isHeaderOnly = 15;
uint64 blueScore = 16;
repeated string childrenHashes = 17;
}
message RpcTransaction {
uint32 version = 1;
repeated RpcTransactionInput inputs = 2;
repeated RpcTransactionOutput outputs = 3;
uint64 lockTime = 4;
string subnetworkId = 5;
uint64 gas = 6;
string payload = 8;
RpcTransactionVerboseData verboseData = 9;
}
message RpcTransactionInput {
RpcOutpoint previousOutpoint = 1;
string signatureScript = 2;
uint64 sequence = 3;
RpcTransactionInputVerboseData verboseData = 4;
}
message RpcScriptPublicKey {
uint32 version = 1;
string scriptPublicKey = 2;
}
message RpcTransactionOutput {
uint64 amount = 1;
RpcScriptPublicKey scriptPublicKey = 2;
RpcTransactionOutputVerboseData verboseData = 3;
}
message RpcOutpoint {
string transactionId = 1;
uint32 index = 2;
}
message RpcUtxoEntry {
uint64 amount = 1;
RpcScriptPublicKey scriptPublicKey = 2;
uint64 blockDaaScore = 3;
bool isCoinbase = 4;
}
message RpcTransactionVerboseData{
string transactionId = 1;
string hash = 2;
uint64 size = 3;
string blockHash = 12;
uint64 blockTime = 14;
}
message RpcTransactionInputVerboseData{
}
message RpcTransactionOutputVerboseData{
string scriptPublicKeyType = 5;
string scriptPublicKeyAddress = 6;
}
// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against.
//
// Possible networks are: Mainnet, Testnet, Simnet, Devnet
@ -37,7 +119,7 @@ message GetCurrentNetworkResponseMessage{
//
// See: GetBlockTemplateRequestMessage
message SubmitBlockRequestMessage{
BlockMessage block = 1;
RpcBlock block = 2;
}
message SubmitBlockResponseMessage{
@ -60,7 +142,7 @@ message GetBlockTemplateRequestMessage{
}
message GetBlockTemplateResponseMessage{
BlockMessage blockMessage = 1;
RpcBlock block = 3;
// Whether kaspad thinks that it's synced.
// Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced.
@ -86,8 +168,7 @@ message NotifyBlockAddedResponseMessage{
//
// See: NotifyBlockAddedRequestMessage
message BlockAddedNotificationMessage{
BlockMessage block = 1;
BlockVerboseData blockVerboseData = 2;
RpcBlock block = 3;
}
// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the
@ -141,7 +222,7 @@ message GetMempoolEntriesResponseMessage{
message MempoolEntry{
uint64 fee = 1;
TransactionVerboseData transactionVerboseData = 2;
RpcTransaction transaction = 3;
}
// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers
@ -243,73 +324,10 @@ message GetBlockRequestMessage{
}
message GetBlockResponseMessage{
string blockHash = 1;
BlockVerboseData blockVerboseData = 2;
RpcBlock block = 3;
RPCError error = 1000;
}
message BlockVerboseData{
string hash = 1;
uint32 version = 2;
string versionHex = 3;
string hashMerkleRoot = 4;
string acceptedIDMerkleRoot = 5;
string utxoCommitment = 6;
repeated TransactionVerboseData transactionVerboseData = 7;
int64 time = 8;
uint64 nonce = 9;
string bits = 10;
double difficulty = 11;
repeated string parentHashes = 12;
repeated string childrenHashes = 17;
string selectedParentHash = 13;
repeated string transactionIDs = 14;
bool isHeaderOnly = 15;
uint64 blueScore = 16;
}
message TransactionVerboseData{
string txId = 1;
string hash = 2;
uint64 size = 3;
uint32 version = 4;
uint64 lockTime = 5;
string subnetworkId = 6;
uint64 gas = 7;
string payload = 9;
repeated TransactionVerboseInput transactionVerboseInputs = 10;
repeated TransactionVerboseOutput transactionVerboseOutputs = 11;
string blockHash = 12;
uint64 time = 13;
uint64 blockTime = 14;
}
message TransactionVerboseInput{
string txId = 1;
uint32 outputIndex = 2;
ScriptSig scriptSig = 3;
uint64 sequence = 4;
}
message ScriptSig{
string asm = 1;
string hex = 2;
}
message TransactionVerboseOutput{
uint64 value = 1;
uint32 index = 2;
ScriptPublicKeyResult scriptPublicKey = 3;
}
message ScriptPublicKeyResult{
string asm = 1;
string hex = 2;
string type = 3;
string address = 4;
uint32 version = 5;
}
// GetSubnetworkRequestMessage requests information about a specific subnetwork
//
// Currently unimplemented
@ -342,13 +360,13 @@ message GetVirtualSelectedParentChainFromBlockResponseMessage{
// kaspad's current virtual.
message GetBlocksRequestMessage{
string lowHash = 1;
bool includeBlockVerboseData = 2;
bool includeBlocks = 2;
bool includeTransactionVerboseData = 3;
}
message GetBlocksResponseMessage{
repeated string blockHashes = 1;
repeated BlockVerboseData blockVerboseData = 2;
repeated string blockHashes = 4;
repeated RpcBlock blocks = 3;
RPCError error = 1000;
}
@ -466,44 +484,6 @@ message StopNotifyingUtxosChangedResponseMessage {
RPCError error = 1000;
}
message RpcTransaction {
uint32 version = 1;
repeated RpcTransactionInput inputs = 2;
repeated RpcTransactionOutput outputs = 3;
uint64 lockTime = 4;
string subnetworkId = 5;
uint64 gas = 6;
string payload = 8;
}
message RpcTransactionInput {
RpcOutpoint previousOutpoint = 1;
string signatureScript = 2;
uint64 sequence = 3;
}
message RpcScriptPublicKey {
uint32 version = 1;
string scriptPublicKey = 2;
}
message RpcTransactionOutput {
uint64 amount = 1;
RpcScriptPublicKey scriptPublicKey = 2;
}
message RpcOutpoint {
string transactionId = 1;
uint32 index = 2;
}
message RpcUtxoEntry {
uint64 amount = 1;
RpcScriptPublicKey scriptPublicKey = 2;
uint64 blockDaaScore = 3;
bool isCoinbase = 4;
}
// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses
//
// This call is only available when this kaspad was started with `--utxoindex`

View File

@ -1,8 +1,6 @@
package protowire
import (
"math"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/pkg/errors"
)
@ -48,20 +46,20 @@ func (x *GetBlockResponseMessage) toAppMessage() (appmessage.Message, error) {
if err != nil && !errors.Is(err, errorNil) {
return nil, err
}
var blockVerboseData *appmessage.BlockVerboseData
var block *appmessage.RPCBlock
// Return verbose data only if there's no error
if rpcErr != nil && x.BlockVerboseData != nil {
if rpcErr != nil && x.Block != nil {
return nil, errors.New("GetBlockResponseMessage contains both an error and a response")
}
if rpcErr == nil {
blockVerboseData, err = x.BlockVerboseData.toAppMessage()
block, err = x.Block.toAppMessage()
if err != nil {
return nil, err
}
}
return &appmessage.GetBlockResponseMessage{
BlockVerboseData: blockVerboseData,
Error: rpcErr,
Block: block,
Error: rpcErr,
}, nil
}
@ -70,228 +68,18 @@ func (x *KaspadMessage_GetBlockResponse) fromAppMessage(message *appmessage.GetB
if message.Error != nil {
err = &RPCError{Message: message.Error.Message}
}
var blockVerboseData *BlockVerboseData
if message.BlockVerboseData != nil {
protoBlockVerboseData := &BlockVerboseData{}
err := protoBlockVerboseData.fromAppMessage(message.BlockVerboseData)
var block *RpcBlock
if message.Block != nil {
protoBlock := &RpcBlock{}
err := protoBlock.fromAppMessage(message.Block)
if err != nil {
return err
}
blockVerboseData = protoBlockVerboseData
block = protoBlock
}
x.GetBlockResponse = &GetBlockResponseMessage{
BlockVerboseData: blockVerboseData,
Error: err,
Block: block,
Error: err,
}
return nil
}
func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "BlockVerboseData is nil")
}
transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(x.TransactionVerboseData))
for i, transactionVerboseDatum := range x.TransactionVerboseData {
appTransactionVerboseDatum, err := transactionVerboseDatum.toAppMessage()
if err != nil {
return nil, err
}
transactionVerboseData[i] = appTransactionVerboseDatum
}
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid block header version - bigger then uint16")
}
return &appmessage.BlockVerboseData{
Hash: x.Hash,
Version: uint16(x.Version),
VersionHex: x.VersionHex,
HashMerkleRoot: x.HashMerkleRoot,
AcceptedIDMerkleRoot: x.AcceptedIDMerkleRoot,
UTXOCommitment: x.UtxoCommitment,
TxIDs: x.TransactionIDs,
TransactionVerboseData: transactionVerboseData,
Time: x.Time,
Nonce: x.Nonce,
Bits: x.Bits,
Difficulty: x.Difficulty,
ParentHashes: x.ParentHashes,
ChildrenHashes: x.ChildrenHashes,
SelectedParentHash: x.SelectedParentHash,
IsHeaderOnly: x.IsHeaderOnly,
BlueScore: x.BlueScore,
}, nil
}
func (x *BlockVerboseData) fromAppMessage(message *appmessage.BlockVerboseData) error {
transactionVerboseData := make([]*TransactionVerboseData, len(message.TransactionVerboseData))
for i, transactionVerboseDatum := range message.TransactionVerboseData {
protoTransactionVerboseDatum := &TransactionVerboseData{}
err := protoTransactionVerboseDatum.fromAppMessage(transactionVerboseDatum)
if err != nil {
return err
}
transactionVerboseData[i] = protoTransactionVerboseDatum
}
*x = BlockVerboseData{
Hash: message.Hash,
Version: uint32(message.Version),
VersionHex: message.VersionHex,
HashMerkleRoot: message.HashMerkleRoot,
AcceptedIDMerkleRoot: message.AcceptedIDMerkleRoot,
UtxoCommitment: message.UTXOCommitment,
TransactionIDs: message.TxIDs,
TransactionVerboseData: transactionVerboseData,
Time: message.Time,
Nonce: message.Nonce,
Bits: message.Bits,
Difficulty: message.Difficulty,
ParentHashes: message.ParentHashes,
ChildrenHashes: message.ChildrenHashes,
SelectedParentHash: message.SelectedParentHash,
IsHeaderOnly: message.IsHeaderOnly,
BlueScore: message.BlueScore,
}
return nil
}
func (x *TransactionVerboseData) toAppMessage() (*appmessage.TransactionVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "TransactionVerboseData is nil")
}
inputs := make([]*appmessage.TransactionVerboseInput, len(x.TransactionVerboseInputs))
for j, item := range x.TransactionVerboseInputs {
input, err := item.toAppMessage()
if err != nil {
return nil, err
}
inputs[j] = input
}
outputs := make([]*appmessage.TransactionVerboseOutput, len(x.TransactionVerboseOutputs))
for j, item := range x.TransactionVerboseOutputs {
output, err := item.toAppMessage()
if err != nil {
return nil, err
}
outputs[j] = output
}
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid transaction version - bigger then uint16")
}
return &appmessage.TransactionVerboseData{
TxID: x.TxId,
Hash: x.Hash,
Size: x.Size,
Version: uint16(x.Version),
LockTime: x.LockTime,
SubnetworkID: x.SubnetworkId,
Gas: x.Gas,
Payload: x.Payload,
TransactionVerboseInputs: inputs,
TransactionVerboseOutputs: outputs,
BlockHash: x.BlockHash,
Time: x.Time,
BlockTime: x.BlockTime,
}, nil
}
func (x *TransactionVerboseData) fromAppMessage(message *appmessage.TransactionVerboseData) error {
inputs := make([]*TransactionVerboseInput, len(message.TransactionVerboseInputs))
for j, item := range message.TransactionVerboseInputs {
scriptSig := &ScriptSig{
Asm: item.ScriptSig.Asm,
Hex: item.ScriptSig.Hex,
}
inputs[j] = &TransactionVerboseInput{
TxId: item.TxID,
OutputIndex: item.OutputIndex,
ScriptSig: scriptSig,
Sequence: item.Sequence,
}
}
outputs := make([]*TransactionVerboseOutput, len(message.TransactionVerboseOutputs))
for j, item := range message.TransactionVerboseOutputs {
scriptPubKey := &ScriptPublicKeyResult{
Hex: item.ScriptPubKey.Hex,
Type: item.ScriptPubKey.Type,
Address: item.ScriptPubKey.Address,
Version: uint32(item.ScriptPubKey.Version),
}
outputs[j] = &TransactionVerboseOutput{
Value: item.Value,
Index: item.Index,
ScriptPublicKey: scriptPubKey,
}
}
*x = TransactionVerboseData{
TxId: message.TxID,
Hash: message.Hash,
Size: message.Size,
Version: uint32(message.Version),
LockTime: message.LockTime,
SubnetworkId: message.SubnetworkID,
Gas: message.Gas,
Payload: message.Payload,
TransactionVerboseInputs: inputs,
TransactionVerboseOutputs: outputs,
BlockHash: message.BlockHash,
Time: message.Time,
BlockTime: message.BlockTime,
}
return nil
}
func (x *TransactionVerboseInput) toAppMessage() (*appmessage.TransactionVerboseInput, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "TransactionVerboseInput is nil")
}
scriptSig, err := x.ScriptSig.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.TransactionVerboseInput{
TxID: x.TxId,
OutputIndex: x.OutputIndex,
ScriptSig: scriptSig,
Sequence: x.Sequence,
}, nil
}
func (x *TransactionVerboseOutput) toAppMessage() (*appmessage.TransactionVerboseOutput, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "TransactionVerboseOutput is nil")
}
scriptPubKey, err := x.ScriptPublicKey.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.TransactionVerboseOutput{
Value: x.Value,
Index: x.Index,
ScriptPubKey: scriptPubKey,
}, nil
}
func (x *ScriptSig) toAppMessage() (*appmessage.ScriptSig, error) {
if x == nil {
return nil, errors.Wrap(errorNil, "ScriptSig is nil")
}
return &appmessage.ScriptSig{
Asm: x.Asm,
Hex: x.Hex,
}, nil
}
func (x *ScriptPublicKeyResult) toAppMessage() (*appmessage.ScriptPubKeyResult, error) {
if x == nil {
return nil, errors.Wrap(errorNil, "ScriptPublicKeyResult is nil")
}
return &appmessage.ScriptPubKeyResult{
Hex: x.Hex,
Type: x.Type,
Address: x.Address,
Version: uint16(x.Version),
}, nil
}

View File

@ -37,17 +37,17 @@ func (x *KaspadMessage_GetBlockTemplateResponse) toAppMessage() (appmessage.Mess
func (x *KaspadMessage_GetBlockTemplateResponse) fromAppMessage(message *appmessage.GetBlockTemplateResponseMessage) error {
x.GetBlockTemplateResponse = &GetBlockTemplateResponseMessage{
BlockMessage: &BlockMessage{},
IsSynced: message.IsSynced,
Block: &RpcBlock{},
IsSynced: message.IsSynced,
}
return x.GetBlockTemplateResponse.BlockMessage.fromAppMessage(message.MsgBlock)
return x.GetBlockTemplateResponse.Block.fromAppMessage(message.Block)
}
func (x *GetBlockTemplateResponseMessage) toAppMessage() (appmessage.Message, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "GetBlockTemplateResponseMessage is nil")
}
msgBlock, err := x.BlockMessage.toAppMessage()
msgBlock, err := x.Block.toAppMessage()
if err != nil {
return nil, err
}

View File

@ -15,7 +15,7 @@ func (x *KaspadMessage_GetBlocksRequest) toAppMessage() (appmessage.Message, err
func (x *KaspadMessage_GetBlocksRequest) fromAppMessage(message *appmessage.GetBlocksRequestMessage) error {
x.GetBlocksRequest = &GetBlocksRequestMessage{
LowHash: message.LowHash,
IncludeBlockVerboseData: message.IncludeBlockVerboseData,
IncludeBlocks: message.IncludeBlocks,
IncludeTransactionVerboseData: message.IncludeTransactionVerboseData,
}
return nil
@ -27,7 +27,7 @@ func (x *GetBlocksRequestMessage) toAppMessage() (appmessage.Message, error) {
}
return &appmessage.GetBlocksRequestMessage{
LowHash: x.LowHash,
IncludeBlockVerboseData: x.IncludeBlockVerboseData,
IncludeBlocks: x.IncludeBlocks,
IncludeTransactionVerboseData: x.IncludeTransactionVerboseData,
}, nil
}
@ -45,19 +45,17 @@ func (x *KaspadMessage_GetBlocksResponse) fromAppMessage(message *appmessage.Get
err = &RPCError{Message: message.Error.Message}
}
x.GetBlocksResponse = &GetBlocksResponseMessage{
BlockHashes: message.BlockHashes,
Error: err,
Error: err,
}
if message.BlockVerboseData != nil {
x.GetBlocksResponse.BlockVerboseData = make([]*BlockVerboseData, len(message.BlockVerboseData))
for i, blockVerboseDatum := range message.BlockVerboseData {
protoBlockVerboseDatum := &BlockVerboseData{}
err := protoBlockVerboseDatum.fromAppMessage(blockVerboseDatum)
if err != nil {
return err
}
x.GetBlocksResponse.BlockVerboseData[i] = protoBlockVerboseDatum
x.GetBlocksResponse.BlockHashes = message.BlockHashes
x.GetBlocksResponse.Blocks = make([]*RpcBlock, len(message.Blocks))
for i, block := range message.Blocks {
protoBlock := &RpcBlock{}
err := protoBlock.fromAppMessage(block)
if err != nil {
return err
}
x.GetBlocksResponse.Blocks[i] = protoBlock
}
return nil
}
@ -71,21 +69,21 @@ func (x *GetBlocksResponseMessage) toAppMessage() (appmessage.Message, error) {
if err != nil && !errors.Is(err, errorNil) {
return nil, err
}
// Return verbose data only if there's no error
if rpcErr != nil && len(x.BlockVerboseData) != 0 {
// Return data only if there's no error
if rpcErr != nil && len(x.Blocks) != 0 {
return nil, errors.New("GetBlocksResponseMessage contains both an error and a response")
}
blocksVerboseData := make([]*appmessage.BlockVerboseData, len(x.BlockVerboseData))
for i, blockVerboseDatum := range x.BlockVerboseData {
appBlockVerboseDatum, err := blockVerboseDatum.toAppMessage()
blocks := make([]*appmessage.RPCBlock, len(x.Blocks))
for i, block := range x.Blocks {
appMessageBlock, err := block.toAppMessage()
if err != nil {
return nil, err
}
blocksVerboseData[i] = appBlockVerboseDatum
blocks[i] = appMessageBlock
}
return &appmessage.GetBlocksResponseMessage{
BlockVerboseData: blocksVerboseData,
BlockHashes: x.BlockHashes,
Error: rpcErr,
BlockHashes: x.BlockHashes,
Blocks: blocks,
Error: rpcErr,
}, nil
}

View File

@ -84,29 +84,25 @@ func (x *MempoolEntry) toAppMessage() (*appmessage.MempoolEntry, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "MempoolEntry is nil")
}
txVerboseData, err := x.TransactionVerboseData.toAppMessage()
// TransactionVerboseData is an optional field
if err != nil && !errors.Is(err, errorNil) {
transaction, err := x.Transaction.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.MempoolEntry{
Fee: x.Fee,
TransactionVerboseData: txVerboseData,
Fee: x.Fee,
Transaction: transaction,
}, nil
}
func (x *MempoolEntry) fromAppMessage(message *appmessage.MempoolEntry) error {
var txVerboseData *TransactionVerboseData
if message.TransactionVerboseData != nil {
txVerboseData = new(TransactionVerboseData)
err := txVerboseData.fromAppMessage(message.TransactionVerboseData)
if err != nil {
return err
}
var transaction *RpcTransaction
if message.Transaction != nil {
transaction = new(RpcTransaction)
transaction.fromAppMessage(message.Transaction)
}
*x = MempoolEntry{
Fee: message.Fee,
TransactionVerboseData: txVerboseData,
Fee: message.Fee,
Transaction: transaction,
}
return nil
}

View File

@ -54,19 +54,13 @@ func (x *KaspadMessage_BlockAddedNotification) toAppMessage() (appmessage.Messag
}
func (x *KaspadMessage_BlockAddedNotification) fromAppMessage(message *appmessage.BlockAddedNotificationMessage) error {
blockMessage := &BlockMessage{}
err := blockMessage.fromAppMessage(message.Block)
if err != nil {
return err
}
blockVerboseData := &BlockVerboseData{}
err = blockVerboseData.fromAppMessage(message.BlockVerboseData)
block := &RpcBlock{}
err := block.fromAppMessage(message.Block)
if err != nil {
return err
}
x.BlockAddedNotification = &BlockAddedNotificationMessage{
Block: blockMessage,
BlockVerboseData: blockVerboseData,
Block: block,
}
return nil
}
@ -79,12 +73,7 @@ func (x *BlockAddedNotificationMessage) toAppMessage() (appmessage.Message, erro
if err != nil {
return nil, err
}
blockVerboseData, err := x.BlockVerboseData.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.BlockAddedNotificationMessage{
Block: block,
BlockVerboseData: blockVerboseData,
Block: block,
}, nil
}

View File

@ -139,49 +139,17 @@ func (x *UtxosByAddressesEntry) toAppMessage() (*appmessage.UTXOsByAddressesEntr
}, nil
}
func (x *UtxosByAddressesEntry) fromAppMessage(entry *appmessage.UTXOsByAddressesEntry) {
outpoint := &RpcOutpoint{
TransactionId: entry.Outpoint.TransactionID,
Index: entry.Outpoint.Index,
}
func (x *UtxosByAddressesEntry) fromAppMessage(message *appmessage.UTXOsByAddressesEntry) {
outpoint := &RpcOutpoint{}
outpoint.fromAppMessage(message.Outpoint)
var utxoEntry *RpcUtxoEntry
if entry.UTXOEntry != nil {
utxoEntry = &RpcUtxoEntry{
Amount: entry.UTXOEntry.Amount,
ScriptPublicKey: ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(entry.UTXOEntry.ScriptPublicKey),
BlockDaaScore: entry.UTXOEntry.BlockDAAScore,
IsCoinbase: entry.UTXOEntry.IsCoinbase,
}
if message.UTXOEntry != nil {
utxoEntry = &RpcUtxoEntry{}
utxoEntry.fromAppMessage(message.UTXOEntry)
}
*x = UtxosByAddressesEntry{
Address: entry.Address,
Address: message.Address,
Outpoint: outpoint,
UtxoEntry: utxoEntry,
}
}
func (x *RpcOutpoint) toAppMessage() (*appmessage.RPCOutpoint, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcOutpoint is nil")
}
return &appmessage.RPCOutpoint{
TransactionID: x.TransactionId,
Index: x.Index,
}, nil
}
func (x *RpcUtxoEntry) toAppMessage() (*appmessage.RPCUTXOEntry, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcUtxoEntry is nil")
}
scriptPubKey, err := x.ScriptPublicKey.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.RPCUTXOEntry{
Amount: x.Amount,
ScriptPublicKey: scriptPubKey,
BlockDAAScore: x.BlockDaaScore,
IsCoinbase: x.IsCoinbase,
}, nil
}

View File

@ -3,6 +3,7 @@ package protowire
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/pkg/errors"
"math"
)
func (x *KaspadMessage_SubmitBlockRequest) toAppMessage() (appmessage.Message, error) {
@ -13,7 +14,7 @@ func (x *KaspadMessage_SubmitBlockRequest) toAppMessage() (appmessage.Message, e
}
func (x *KaspadMessage_SubmitBlockRequest) fromAppMessage(message *appmessage.SubmitBlockRequestMessage) error {
x.SubmitBlockRequest = &SubmitBlockRequestMessage{Block: &BlockMessage{}}
x.SubmitBlockRequest = &SubmitBlockRequestMessage{Block: &RpcBlock{}}
return x.SubmitBlockRequest.Block.fromAppMessage(message.Block)
}
@ -25,7 +26,6 @@ func (x *SubmitBlockRequestMessage) toAppMessage() (appmessage.Message, error) {
if err != nil {
return nil, err
}
return &appmessage.SubmitBlockRequestMessage{
Block: blockAppMessage,
}, nil
@ -64,3 +64,114 @@ func (x *SubmitBlockResponseMessage) toAppMessage() (appmessage.Message, error)
Error: rpcErr,
}, nil
}
func (x *RpcBlock) toAppMessage() (*appmessage.RPCBlock, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcBlock is nil")
}
header, err := x.Header.toAppMessage()
if err != nil {
return nil, err
}
transactions := make([]*appmessage.RPCTransaction, len(x.Transactions))
for i, transaction := range x.Transactions {
appTransaction, err := transaction.toAppMessage()
if err != nil {
return nil, err
}
transactions[i] = appTransaction
}
var verboseData *appmessage.RPCBlockVerboseData
if x.VerboseData != nil {
appMessageVerboseData, err := x.VerboseData.toAppMessage()
if err != nil {
return nil, err
}
verboseData = appMessageVerboseData
}
return &appmessage.RPCBlock{
Header: header,
Transactions: transactions,
VerboseData: verboseData,
}, nil
}
func (x *RpcBlock) fromAppMessage(message *appmessage.RPCBlock) error {
header := &RpcBlockHeader{}
header.fromAppMessage(message.Header)
transactions := make([]*RpcTransaction, len(message.Transactions))
for i, transaction := range message.Transactions {
rpcTransaction := &RpcTransaction{}
rpcTransaction.fromAppMessage(transaction)
transactions[i] = rpcTransaction
}
var verboseData *RpcBlockVerboseData
if message.VerboseData != nil {
verboseData = &RpcBlockVerboseData{}
verboseData.fromAppMessage(message.VerboseData)
}
*x = RpcBlock{
Header: header,
Transactions: transactions,
}
return nil
}
func (x *RpcBlockHeader) toAppMessage() (*appmessage.RPCBlockHeader, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcBlockHeader is nil")
}
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid block header version - bigger then uint16")
}
return &appmessage.RPCBlockHeader{
Version: x.Version,
ParentHashes: x.ParentHashes,
HashMerkleRoot: x.HashMerkleRoot,
AcceptedIDMerkleRoot: x.AcceptedIdMerkleRoot,
UTXOCommitment: x.UtxoCommitment,
Timestamp: x.Timestamp,
Bits: x.Bits,
Nonce: x.Nonce,
}, nil
}
func (x *RpcBlockHeader) fromAppMessage(message *appmessage.RPCBlockHeader) {
*x = RpcBlockHeader{
Version: message.Version,
ParentHashes: message.ParentHashes,
HashMerkleRoot: message.HashMerkleRoot,
AcceptedIdMerkleRoot: message.AcceptedIDMerkleRoot,
UtxoCommitment: message.UTXOCommitment,
Timestamp: message.Timestamp,
Bits: message.Bits,
Nonce: message.Nonce,
}
}
func (x *RpcBlockVerboseData) toAppMessage() (*appmessage.RPCBlockVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcBlockVerboseData is nil")
}
return &appmessage.RPCBlockVerboseData{
Hash: x.Hash,
Difficulty: x.Difficulty,
SelectedParentHash: x.SelectedParentHash,
TransactionIDs: x.TransactionIds,
IsHeaderOnly: x.IsHeaderOnly,
BlueScore: x.BlueScore,
ChildrenHashes: x.ChildrenHashes,
}, nil
}
func (x *RpcBlockVerboseData) fromAppMessage(message *appmessage.RPCBlockVerboseData) {
*x = RpcBlockVerboseData{
Hash: message.Hash,
Difficulty: message.Difficulty,
SelectedParentHash: message.SelectedParentHash,
TransactionIds: message.TransactionIDs,
IsHeaderOnly: message.IsHeaderOnly,
BlueScore: message.BlueScore,
ChildrenHashes: message.ChildrenHashes,
}
}

View File

@ -88,11 +88,17 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) {
}
outputs[i] = appOutput
}
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid RPC txn version - bigger then uint16")
return nil, errors.Errorf("Invalid RPC transaction version - bigger then uint16")
}
var verboseData *appmessage.RPCTransactionVerboseData
if x.VerboseData != nil {
appMessageVerboseData, err := x.VerboseData.toAppMessage()
if err != nil {
return nil, err
}
verboseData = appMessageVerboseData
}
return &appmessage.RPCTransaction{
Version: uint16(x.Version),
Inputs: inputs,
@ -101,28 +107,25 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) {
SubnetworkID: x.SubnetworkId,
Gas: x.Gas,
Payload: x.Payload,
VerboseData: verboseData,
}, nil
}
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,
}
inputs[i] = &RpcTransactionInput{}
inputs[i].fromAppMessage(input)
}
outputs := make([]*RpcTransactionOutput, len(transaction.Outputs))
for i, output := range transaction.Outputs {
outputs[i] = &RpcTransactionOutput{
Amount: output.Amount,
ScriptPublicKey: ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(output.ScriptPublicKey),
}
outputs[i] = &RpcTransactionOutput{}
outputs[i].fromAppMessage(output)
}
var verboseData *RpcTransactionVerboseData
if transaction.VerboseData != nil {
verboseData = &RpcTransactionVerboseData{}
verboseData.fromAppMessage(transaction.VerboseData)
}
*x = RpcTransaction{
Version: uint32(transaction.Version),
@ -132,6 +135,7 @@ func (x *RpcTransaction) fromAppMessage(transaction *appmessage.RPCTransaction)
SubnetworkId: transaction.SubnetworkID,
Gas: transaction.Gas,
Payload: transaction.Payload,
VerboseData: verboseData,
}
}
@ -143,27 +147,120 @@ func (x *RpcTransactionInput) toAppMessage() (*appmessage.RPCTransactionInput, e
if err != nil {
return nil, err
}
var verboseData *appmessage.RPCTransactionInputVerboseData
for x.VerboseData != nil {
appMessageVerboseData, err := x.VerboseData.toAppMessage()
if err != nil {
return nil, err
}
verboseData = appMessageVerboseData
}
return &appmessage.RPCTransactionInput{
PreviousOutpoint: outpoint,
SignatureScript: x.SignatureScript,
Sequence: x.Sequence,
VerboseData: verboseData,
}, nil
}
func (x *RpcTransactionInput) fromAppMessage(message *appmessage.RPCTransactionInput) {
previousOutpoint := &RpcOutpoint{}
previousOutpoint.fromAppMessage(message.PreviousOutpoint)
var verboseData *RpcTransactionInputVerboseData
if message.VerboseData != nil {
verboseData := &RpcTransactionInputVerboseData{}
verboseData.fromAppData(message.VerboseData)
}
*x = RpcTransactionInput{
PreviousOutpoint: previousOutpoint,
SignatureScript: message.SignatureScript,
Sequence: message.Sequence,
VerboseData: verboseData,
}
}
func (x *RpcTransactionOutput) toAppMessage() (*appmessage.RPCTransactionOutput, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcTransactionOutput is nil")
}
scriptPublicKey, err := x.ScriptPublicKey.toAppMessage()
if err != nil {
return nil, err
}
var verboseData *appmessage.RPCTransactionOutputVerboseData
if x.VerboseData != nil {
appMessageVerboseData, err := x.VerboseData.toAppMessage()
if err != nil {
return nil, err
}
verboseData = appMessageVerboseData
}
return &appmessage.RPCTransactionOutput{
Amount: x.Amount,
ScriptPublicKey: scriptPublicKey,
VerboseData: verboseData,
}, nil
}
func (x *RpcTransactionOutput) fromAppMessage(message *appmessage.RPCTransactionOutput) {
scriptPublicKey := &RpcScriptPublicKey{}
scriptPublicKey.fromAppMessage(message.ScriptPublicKey)
var verboseData *RpcTransactionOutputVerboseData
if message.VerboseData != nil {
verboseData = &RpcTransactionOutputVerboseData{}
verboseData.fromAppMessage(message.VerboseData)
}
*x = RpcTransactionOutput{
Amount: message.Amount,
ScriptPublicKey: scriptPublicKey,
VerboseData: verboseData,
}
}
func (x *RpcOutpoint) toAppMessage() (*appmessage.RPCOutpoint, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcOutpoint is nil")
}
return &appmessage.RPCOutpoint{
TransactionID: x.TransactionId,
Index: x.Index,
}, nil
}
func (x *RpcOutpoint) fromAppMessage(message *appmessage.RPCOutpoint) {
*x = RpcOutpoint{
TransactionId: message.TransactionID,
Index: message.Index,
}
}
func (x *RpcUtxoEntry) toAppMessage() (*appmessage.RPCUTXOEntry, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcUtxoEntry is nil")
}
scriptPubKey, err := x.ScriptPublicKey.toAppMessage()
if err != nil {
return nil, err
}
return &appmessage.RPCTransactionOutput{
return &appmessage.RPCUTXOEntry{
Amount: x.Amount,
ScriptPublicKey: scriptPubKey,
BlockDAAScore: x.BlockDaaScore,
IsCoinbase: x.IsCoinbase,
}, nil
}
func (x *RpcUtxoEntry) fromAppMessage(message *appmessage.RPCUTXOEntry) {
scriptPublicKey := &RpcScriptPublicKey{}
scriptPublicKey.fromAppMessage(message.ScriptPublicKey)
*x = RpcUtxoEntry{
Amount: message.Amount,
ScriptPublicKey: scriptPublicKey,
BlockDaaScore: message.BlockDAAScore,
IsCoinbase: message.IsCoinbase,
}
}
func (x *RpcScriptPublicKey) toAppMessage() (*appmessage.RPCScriptPublicKey, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcScriptPublicKey is nil")
@ -175,10 +272,62 @@ func (x *RpcScriptPublicKey) toAppMessage() (*appmessage.RPCScriptPublicKey, err
Version: uint16(x.Version),
Script: x.ScriptPublicKey,
}, nil
}
// ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey converts from RPCScriptPublicKey to RpcScriptPubKey.
func ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(toConvert *appmessage.RPCScriptPublicKey) *RpcScriptPublicKey {
return &RpcScriptPublicKey{Version: uint32(toConvert.Version), ScriptPublicKey: toConvert.Script}
func (x *RpcScriptPublicKey) fromAppMessage(message *appmessage.RPCScriptPublicKey) {
*x = RpcScriptPublicKey{
Version: uint32(message.Version),
ScriptPublicKey: message.Script,
}
}
func (x *RpcTransactionVerboseData) toAppMessage() (*appmessage.RPCTransactionVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcTransactionVerboseData is nil")
}
return &appmessage.RPCTransactionVerboseData{
TransactionID: x.TransactionId,
Hash: x.Hash,
Size: x.Size,
BlockHash: x.BlockHash,
BlockTime: x.BlockTime,
}, nil
}
func (x *RpcTransactionVerboseData) fromAppMessage(message *appmessage.RPCTransactionVerboseData) {
*x = RpcTransactionVerboseData{
TransactionId: message.TransactionID,
Hash: message.Hash,
Size: message.Size,
BlockHash: message.BlockHash,
BlockTime: message.BlockTime,
}
}
func (x *RpcTransactionInputVerboseData) toAppMessage() (*appmessage.RPCTransactionInputVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcTransactionInputVerboseData is nil")
}
return &appmessage.RPCTransactionInputVerboseData{}, nil
}
func (x *RpcTransactionInputVerboseData) fromAppData(message *appmessage.RPCTransactionInputVerboseData) {
*x = RpcTransactionInputVerboseData{}
}
func (x *RpcTransactionOutputVerboseData) toAppMessage() (*appmessage.RPCTransactionOutputVerboseData, error) {
if x == nil {
return nil, errors.Wrapf(errorNil, "RpcTransactionOutputVerboseData is nil")
}
return &appmessage.RPCTransactionOutputVerboseData{
ScriptPublicKeyType: x.ScriptPublicKeyType,
ScriptPublicKeyAddress: x.ScriptPublicKeyAddress,
}, nil
}
func (x *RpcTransactionOutputVerboseData) fromAppMessage(message *appmessage.RPCTransactionOutputVerboseData) {
*x = RpcTransactionOutputVerboseData{
ScriptPublicKeyType: message.ScriptPublicKeyType,
ScriptPublicKeyAddress: message.ScriptPublicKeyAddress,
}
}

View File

@ -3,11 +3,11 @@ package rpcclient
import "github.com/kaspanet/kaspad/app/appmessage"
// GetBlocks sends an RPC request respective to the function's name and returns the RPC server's response
func (c *RPCClient) GetBlocks(lowHash string, includeBlockVerboseData bool,
func (c *RPCClient) GetBlocks(lowHash string, includeBlocks bool,
includeTransactionVerboseData bool) (*appmessage.GetBlocksResponseMessage, error) {
err := c.rpcRouter.outgoingRoute().Enqueue(
appmessage.NewGetBlocksRequestMessage(lowHash, includeBlockVerboseData, includeTransactionVerboseData))
appmessage.NewGetBlocksRequestMessage(lowHash, includeBlocks, includeTransactionVerboseData))
if err != nil {
return nil, err
}

View File

@ -8,7 +8,7 @@ import (
// SubmitBlock sends an RPC request respective to the function's name and returns the RPC server's response
func (c *RPCClient) SubmitBlock(block *externalapi.DomainBlock) (appmessage.RejectReason, error) {
err := c.rpcRouter.outgoingRoute().Enqueue(
appmessage.NewSubmitBlockRequestMessage(appmessage.DomainBlockToMsgBlock(block)))
appmessage.NewSubmitBlockRequestMessage(appmessage.DomainBlockToRPCBlock(block)))
if err != nil {
return appmessage.RejectReasonNone, err
}

View File

@ -189,7 +189,10 @@ func mineOnTips(client *rpc.Client) (appmessage.RejectReason, error) {
return appmessage.RejectReasonNone, err
}
domainBlock := appmessage.MsgBlockToDomainBlock(template.MsgBlock)
domainBlock, err := appmessage.RPCBlockToDomainBlock(template.Block)
if err != nil {
return appmessage.RejectReasonNone, err
}
mine.SolveBlock(domainBlock)
return client.SubmitBlock(domainBlock)

View File

@ -18,38 +18,48 @@ func TestIntegrationBasicSync(t *testing.T) {
connect(t, appHarness1, appHarness2)
connect(t, appHarness2, appHarness3)
app2OnBlockAddedChan := make(chan *appmessage.MsgBlockHeader)
app2OnBlockAddedChan := make(chan *appmessage.RPCBlock)
setOnBlockAddedHandler(t, appHarness2, func(notification *appmessage.BlockAddedNotificationMessage) {
app2OnBlockAddedChan <- &notification.Block.Header
app2OnBlockAddedChan <- notification.Block
})
app3OnBlockAddedChan := make(chan *appmessage.MsgBlockHeader)
app3OnBlockAddedChan := make(chan *appmessage.RPCBlock)
setOnBlockAddedHandler(t, appHarness3, func(notification *appmessage.BlockAddedNotificationMessage) {
app3OnBlockAddedChan <- &notification.Block.Header
app3OnBlockAddedChan <- notification.Block
})
block := mineNextBlock(t, appHarness1)
var header *appmessage.MsgBlockHeader
var rpcBlock *appmessage.RPCBlock
select {
case header = <-app2OnBlockAddedChan:
case rpcBlock = <-app2OnBlockAddedChan:
case <-time.After(defaultTimeout):
t.Fatalf("Timeout waiting for block added notification on node directly connected to miner")
}
domainBlockFromRPC, err := appmessage.RPCBlockToDomainBlock(rpcBlock)
if err != nil {
t.Fatalf("Could not convert RPC block: %s", err)
}
rpcBlockHash := consensushashing.BlockHash(domainBlockFromRPC)
blockHash := consensushashing.BlockHash(block)
if !header.BlockHash().Equal(blockHash) {
t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash())
if !rpcBlockHash.Equal(blockHash) {
t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, rpcBlockHash)
}
select {
case header = <-app3OnBlockAddedChan:
case rpcBlock = <-app3OnBlockAddedChan:
case <-time.After(defaultTimeout):
t.Fatalf("Timeout waiting for block added notification on node indirectly connected to miner")
}
domainBlockFromRPC, err = appmessage.RPCBlockToDomainBlock(rpcBlock)
if err != nil {
t.Fatalf("Could not convert RPC block: %s", err)
}
rpcBlockHash = consensushashing.BlockHash(domainBlockFromRPC)
blockHash = consensushashing.BlockHash(block)
if !header.BlockHash().Equal(blockHash) {
t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash())
if !rpcBlockHash.Equal(blockHash) {
t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, rpcBlockHash)
}
}

View File

@ -31,7 +31,10 @@ func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
t.Fatalf("Error getting block template: %+v", err)
}
block := appmessage.MsgBlockToDomainBlock(blockTemplate.MsgBlock)
block, err := appmessage.RPCBlockToDomainBlock(blockTemplate.Block)
if err != nil {
t.Fatalf("Error converting block: %s", err)
}
solveBlock(block)

View File

@ -27,9 +27,9 @@ func TestTxRelay(t *testing.T) {
connect(t, payer, mediator)
connect(t, mediator, payee)
payeeBlockAddedChan := make(chan *appmessage.MsgBlockHeader)
payeeBlockAddedChan := make(chan *appmessage.RPCBlockHeader)
setOnBlockAddedHandler(t, payee, func(notification *appmessage.BlockAddedNotificationMessage) {
payeeBlockAddedChan <- &notification.Block.Header
payeeBlockAddedChan <- notification.Block.Header
})
// skip the first block because it's paying to genesis script
mineNextBlock(t, payer)
@ -80,7 +80,7 @@ func TestTxRelay(t *testing.T) {
}
}
func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessage.MsgBlockHeader) {
func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessage.RPCBlockHeader) {
select {
case <-payeeBlockAddedChan:
case <-time.After(defaultTimeout):