Add merge set and IsChainBlock to the RPC (#1961)

* Add merge set and IsChainBlock to the RPC

* Fix BlockInfo.Clone()
This commit is contained in:
Ori Newman 2022-02-25 16:22:00 +02:00 committed by GitHub
parent 9b23bbcdb5
commit 9f02a24e8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 877 additions and 707 deletions

View File

@ -92,11 +92,14 @@ type RPCBlockLevelParents struct {
// RPCBlockVerboseData holds verbose data about a block
type RPCBlockVerboseData struct {
Hash string
Difficulty float64
SelectedParentHash string
TransactionIDs []string
IsHeaderOnly bool
BlueScore uint64
ChildrenHashes []string
Hash string
Difficulty float64
SelectedParentHash string
TransactionIDs []string
IsHeaderOnly bool
BlueScore uint64
ChildrenHashes []string
MergeSetBluesHashes []string
MergeSetRedsHashes []string
IsChainBlock bool
}

View File

@ -56,21 +56,29 @@ func (ctx *Context) PopulateBlockWithVerboseData(block *appmessage.RPCBlock, dom
"invalid block")
}
_, selectedParentHash, childrenHashes, err := ctx.Domain.Consensus().GetBlockRelations(blockHash)
_, childrenHashes, err := ctx.Domain.Consensus().GetBlockRelations(blockHash)
if err != nil {
return err
}
isChainBlock, err := ctx.Domain.Consensus().IsChainBlock(blockHash)
if err != nil {
return err
}
block.VerboseData = &appmessage.RPCBlockVerboseData{
Hash: blockHash.String(),
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
ChildrenHashes: hashes.ToStrings(childrenHashes),
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
BlueScore: blockInfo.BlueScore,
Hash: blockHash.String(),
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
ChildrenHashes: hashes.ToStrings(childrenHashes),
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
BlueScore: blockInfo.BlueScore,
MergeSetBluesHashes: hashes.ToStrings(blockInfo.MergeSetBlues),
MergeSetRedsHashes: hashes.ToStrings(blockInfo.MergeSetReds),
IsChainBlock: isChainBlock,
}
// selectedParentHash will be nil in the genesis block
if selectedParentHash != nil {
block.VerboseData.SelectedParentHash = selectedParentHash.String()
if blockInfo.SelectedParent != nil {
block.VerboseData.SelectedParentHash = blockInfo.SelectedParent.String()
}
if blockInfo.BlockStatus == externalapi.StatusHeaderOnly {

View File

@ -286,13 +286,15 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
blockInfo.BlueScore = ghostdagData.BlueScore()
blockInfo.BlueWork = ghostdagData.BlueWork()
blockInfo.SelectedParent = ghostdagData.SelectedParent()
blockInfo.MergeSetBlues = ghostdagData.MergeSetBlues()
blockInfo.MergeSetReds = ghostdagData.MergeSetReds()
return blockInfo, nil
}
func (s *consensus) GetBlockRelations(blockHash *externalapi.DomainHash) (
parents []*externalapi.DomainHash, selectedParent *externalapi.DomainHash,
children []*externalapi.DomainHash, err error) {
parents []*externalapi.DomainHash, children []*externalapi.DomainHash, err error) {
s.lock.Lock()
defer s.lock.Unlock()
@ -301,15 +303,10 @@ func (s *consensus) GetBlockRelations(blockHash *externalapi.DomainHash) (
blockRelation, err := s.blockRelationStores[0].BlockRelation(s.databaseContext, stagingArea, blockHash)
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}
blockGHOSTDAGData, err := s.ghostdagDataStores[0].Get(s.databaseContext, stagingArea, blockHash, false)
if err != nil {
return nil, nil, nil, err
}
return blockRelation.Parents, blockGHOSTDAGData.SelectedParent(), blockRelation.Children, nil
return blockRelation.Parents, blockRelation.Children, nil
}
func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) {
@ -824,3 +821,16 @@ func (s *consensus) TrustedGHOSTDAGData(blockHash *externalapi.DomainHash) (*ext
return ghostdagData, nil
}
func (s *consensus) IsChainBlock(blockHash *externalapi.DomainHash) (bool, error) {
s.lock.Lock()
defer s.lock.Unlock()
stagingArea := model.NewStagingArea()
virtualGHOSTDAGData, err := s.ghostdagDataStores[0].Get(s.databaseContext, stagingArea, model.VirtualBlockHash, false)
if err != nil {
return false, err
}
return s.dagTopologyManagers[0].IsInSelectedParentChainOf(stagingArea, blockHash, virtualGHOSTDAGData.SelectedParent())
}

View File

@ -4,18 +4,24 @@ import "math/big"
// BlockInfo contains various information about a specific block
type BlockInfo struct {
Exists bool
BlockStatus BlockStatus
BlueScore uint64
BlueWork *big.Int
Exists bool
BlockStatus BlockStatus
BlueScore uint64
BlueWork *big.Int
SelectedParent *DomainHash
MergeSetBlues []*DomainHash
MergeSetReds []*DomainHash
}
// Clone returns a clone of BlockInfo
func (bi *BlockInfo) Clone() *BlockInfo {
return &BlockInfo{
Exists: bi.Exists,
BlockStatus: bi.BlockStatus.Clone(),
BlueScore: bi.BlueScore,
BlueWork: new(big.Int).Set(bi.BlueWork),
Exists: bi.Exists,
BlockStatus: bi.BlockStatus.Clone(),
BlueScore: bi.BlueScore,
BlueWork: new(big.Int).Set(bi.BlueWork),
SelectedParent: bi.SelectedParent,
MergeSetBlues: CloneHashes(bi.MergeSetBlues),
MergeSetReds: CloneHashes(bi.MergeSetReds),
}
}

View File

@ -14,31 +14,83 @@ func initTestBlockInfoStructsForClone() []*BlockInfo {
BlockStatus(0x01),
0,
big.NewInt(0),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
true,
BlockStatus(0x02),
0,
big.NewInt(0),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
true,
1,
1,
big.NewInt(0),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
true,
255,
2,
big.NewInt(0),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
true,
0,
3,
big.NewInt(0),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
true,
BlockStatus(0x01),
0,
big.NewInt(1),
nil,
[]*DomainHash{},
[]*DomainHash{},
}, {
false,
BlockStatus(0x01),
0,
big.NewInt(1),
NewDomainHashFromByteArray(&[DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
[]*DomainHash{
NewDomainHashFromByteArray(&[DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}),
NewDomainHashFromByteArray(&[DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}),
},
[]*DomainHash{
NewDomainHashFromByteArray(&[DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}),
NewDomainHashFromByteArray(&[DomainHashSize]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05}),
},
},
}
return tests

View File

@ -16,7 +16,7 @@ type Consensus interface {
GetBlockEvenIfHeaderOnly(blockHash *DomainHash) (*DomainBlock, error)
GetBlockHeader(blockHash *DomainHash) (BlockHeader, error)
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)
GetBlockRelations(blockHash *DomainHash) (parents []*DomainHash, selectedParent *DomainHash, children []*DomainHash, err error)
GetBlockRelations(blockHash *DomainHash) (parents []*DomainHash, children []*DomainHash, err error)
GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error)
GetHashesBetween(lowHash, highHash *DomainHash, maxBlocks uint64) (hashes []*DomainHash, actualHighHash *DomainHash, err error)
@ -50,4 +50,5 @@ type Consensus interface {
TrustedDataDataDAAHeader(trustedBlockHash, daaBlockHash *DomainHash, daaBlockWindowIndex uint64) (*TrustedDataDataDAAHeader, error)
TrustedBlockAssociatedGHOSTDAGDataBlockHashes(blockHash *DomainHash) ([]*DomainHash, error)
TrustedGHOSTDAGData(blockHash *DomainHash) (*BlockGHOSTDAGData, error)
IsChainBlock(blockHash *DomainHash) (bool, error)
}

View File

@ -1,12 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: messages.proto
package protowire
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@ -20,6 +21,10 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type KaspadMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -11,8 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const _ = grpc.SupportPackageIsVersion6
// P2PClient is the client API for P2P service.
//
@ -30,7 +29,7 @@ func NewP2PClient(cc grpc.ClientConnInterface) P2PClient {
}
func (c *p2PClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (P2P_MessageStreamClient, error) {
stream, err := c.cc.NewStream(ctx, &P2P_ServiceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...)
stream, err := c.cc.NewStream(ctx, &_P2P_serviceDesc.Streams[0], "/protowire.P2P/MessageStream", opts...)
if err != nil {
return nil, err
}
@ -72,20 +71,13 @@ type P2PServer interface {
type UnimplementedP2PServer struct {
}
func (UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error {
func (*UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error {
return status.Errorf(codes.Unimplemented, "method MessageStream not implemented")
}
func (UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {}
func (*UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {}
// UnsafeP2PServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to P2PServer will
// result in compilation errors.
type UnsafeP2PServer interface {
mustEmbedUnimplementedP2PServer()
}
func RegisterP2PServer(s grpc.ServiceRegistrar, srv P2PServer) {
s.RegisterService(&P2P_ServiceDesc, srv)
func RegisterP2PServer(s *grpc.Server, srv P2PServer) {
s.RegisterService(&_P2P_serviceDesc, srv)
}
func _P2P_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error {
@ -114,10 +106,7 @@ func (x *p2PMessageStreamServer) Recv() (*KaspadMessage, error) {
return m, nil
}
// P2P_ServiceDesc is the grpc.ServiceDesc for P2P service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var P2P_ServiceDesc = grpc.ServiceDesc{
var _P2P_serviceDesc = grpc.ServiceDesc{
ServiceName: "protowire.P2P",
HandlerType: (*P2PServer)(nil),
Methods: []grpc.MethodDesc{},
@ -148,7 +137,7 @@ func NewRPCClient(cc grpc.ClientConnInterface) RPCClient {
}
func (c *rPCClient) MessageStream(ctx context.Context, opts ...grpc.CallOption) (RPC_MessageStreamClient, error) {
stream, err := c.cc.NewStream(ctx, &RPC_ServiceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...)
stream, err := c.cc.NewStream(ctx, &_RPC_serviceDesc.Streams[0], "/protowire.RPC/MessageStream", opts...)
if err != nil {
return nil, err
}
@ -190,20 +179,13 @@ type RPCServer interface {
type UnimplementedRPCServer struct {
}
func (UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error {
func (*UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error {
return status.Errorf(codes.Unimplemented, "method MessageStream not implemented")
}
func (UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {}
func (*UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {}
// UnsafeRPCServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RPCServer will
// result in compilation errors.
type UnsafeRPCServer interface {
mustEmbedUnimplementedRPCServer()
}
func RegisterRPCServer(s grpc.ServiceRegistrar, srv RPCServer) {
s.RegisterService(&RPC_ServiceDesc, srv)
func RegisterRPCServer(s *grpc.Server, srv RPCServer) {
s.RegisterService(&_RPC_serviceDesc, srv)
}
func _RPC_MessageStream_Handler(srv interface{}, stream grpc.ServerStream) error {
@ -232,10 +214,7 @@ func (x *rPCMessageStreamServer) Recv() (*KaspadMessage, error) {
return m, nil
}
// RPC_ServiceDesc is the grpc.ServiceDesc for RPC service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var RPC_ServiceDesc = grpc.ServiceDesc{
var _RPC_serviceDesc = grpc.ServiceDesc{
ServiceName: "protowire.RPC",
HandlerType: (*RPCServer)(nil),
Methods: []grpc.MethodDesc{},

View File

@ -1,12 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: p2p.proto
package protowire
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
@ -20,6 +21,10 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type RequestAddressesMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -79,6 +79,9 @@
- [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage)
- [GetBalanceByAddressRequestMessage](#protowire.GetBalanceByAddressRequestMessage)
- [GetBalanceByAddressResponseMessage](#protowire.GetBalanceByAddressResponseMessage)
- [GetBalancesByAddressesRequestMessage](#protowire.GetBalancesByAddressesRequestMessage)
- [BalancesByAddressEntry](#protowire.BalancesByAddressEntry)
- [GetBalancesByAddressesResponseMessage](#protowire.GetBalancesByAddressesResponseMessage)
- [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage)
- [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage)
- [NotifyVirtualSelectedParentBlueScoreChangedRequestMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)
@ -211,6 +214,9 @@ Receivers of any ResponseMessage are expected to check whether its error field i
| isHeaderOnly | [bool](#bool) | | |
| blueScore | [uint64](#uint64) | | |
| childrenHashes | [string](#string) | repeated | |
| mergeSetBluesHashes | [string](#string) | repeated | |
| mergeSetRedsHashes | [string](#string) | repeated | |
| isChainBlock | [bool](#bool) | | |
@ -410,6 +416,7 @@ See: GetBlockTemplateRequestMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| block | [RpcBlock](#protowire.RpcBlock) | | |
| allowNonDAABlocks | [bool](#bool) | | |
@ -1328,6 +1335,54 @@ This call is only available when this kaspad was started with `--utxoindex`
<a name="protowire.GetBalancesByAddressesRequestMessage"></a>
### GetBalancesByAddressesRequestMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| addresses | [string](#string) | repeated | |
<a name="protowire.BalancesByAddressEntry"></a>
### BalancesByAddressEntry
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| address | [string](#string) | | |
| balance | [uint64](#uint64) | | |
| error | [RPCError](#protowire.RPCError) | | |
<a name="protowire.GetBalancesByAddressesResponseMessage"></a>
### GetBalancesByAddressesResponseMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| entries | [BalancesByAddressEntry](#protowire.BalancesByAddressEntry) | repeated | |
| error | [RPCError](#protowire.RPCError) | | |
<a name="protowire.GetVirtualSelectedParentBlueScoreRequestMessage"></a>
### GetVirtualSelectedParentBlueScoreRequestMessage

View File

@ -52,6 +52,9 @@ message RpcBlockVerboseData{
bool isHeaderOnly = 15;
uint64 blueScore = 16;
repeated string childrenHashes = 17;
repeated string mergeSetBluesHashes = 18;
repeated string mergeSetRedsHashes = 19;
bool isChainBlock = 20;
}
message RpcTransaction {

View File

@ -193,24 +193,30 @@ func (x *RpcBlockVerboseData) toAppMessage() (*appmessage.RPCBlockVerboseData, e
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,
Hash: x.Hash,
Difficulty: x.Difficulty,
SelectedParentHash: x.SelectedParentHash,
TransactionIDs: x.TransactionIds,
IsHeaderOnly: x.IsHeaderOnly,
BlueScore: x.BlueScore,
ChildrenHashes: x.ChildrenHashes,
MergeSetBluesHashes: x.MergeSetBluesHashes,
MergeSetRedsHashes: x.MergeSetRedsHashes,
IsChainBlock: x.IsChainBlock,
}, 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,
Hash: message.Hash,
Difficulty: message.Difficulty,
SelectedParentHash: message.SelectedParentHash,
TransactionIds: message.TransactionIDs,
IsHeaderOnly: message.IsHeaderOnly,
BlueScore: message.BlueScore,
ChildrenHashes: message.ChildrenHashes,
MergeSetBluesHashes: message.MergeSetBluesHashes,
MergeSetRedsHashes: message.MergeSetRedsHashes,
IsChainBlock: message.IsChainBlock,
}
}