diff --git a/modules/network/keeper/grpc_query.go b/modules/network/keeper/grpc_query.go index 3c9f91e4..763f3896 100644 --- a/modules/network/keeper/grpc_query.go +++ b/modules/network/keeper/grpc_query.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "sort" "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" @@ -237,6 +238,33 @@ func (q *queryServer) LastAttestedHeight(c context.Context, req *types.QueryLast }, nil } +// AttesterSet queries the full ordered attester set +func (q *queryServer) AttesterSet(goCtx context.Context, req *types.QueryAttesterSetRequest) (*types.QueryAttesterSetResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + entries := []types.AttesterSetEntry{} + if err := q.keeper.ValidatorIndex.Walk(ctx, nil, func(addr string, idx uint16) (bool, error) { + info, err := q.keeper.GetAttesterInfo(ctx, addr) + if err != nil { + return false, err + } + entries = append(entries, types.AttesterSetEntry{ + Authority: info.Authority, + ConsensusAddress: addr, + Index: uint32(idx), + Pubkey: info.Pubkey, + }) + return false, nil + }); err != nil { + return nil, err + } + sort.Slice(entries, func(i, j int) bool { return entries[i].Index < entries[j].Index }) + return &types.QueryAttesterSetResponse{Entries: entries}, nil +} + // AttesterInfo queries the attester information including public key func (q *queryServer) AttesterInfo(c context.Context, req *types.QueryAttesterInfoRequest) (*types.QueryAttesterInfoResponse, error) { if req == nil { diff --git a/modules/network/types/query.pb.go b/modules/network/types/query.pb.go index 3b389163..7c788d82 100644 --- a/modules/network/types/query.pb.go +++ b/modules/network/types/query.pb.go @@ -6,6 +6,8 @@ package types import ( context "context" fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" _ "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" @@ -852,6 +854,129 @@ func (m *QueryAttesterInfoResponse) GetAttesterInfo() *AttesterInfo { return nil } +// QueryAttesterSetRequest is the request type for the Query/AttesterSet RPC method. +type QueryAttesterSetRequest struct { +} + +func (m *QueryAttesterSetRequest) Reset() { *m = QueryAttesterSetRequest{} } +func (m *QueryAttesterSetRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAttesterSetRequest) ProtoMessage() {} +func (*QueryAttesterSetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_faab6bfc228a74e1, []int{17} +} +func (m *QueryAttesterSetRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAttesterSetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAttesterSetRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAttesterSetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAttesterSetRequest.Merge(m, src) +} +func (m *QueryAttesterSetRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAttesterSetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAttesterSetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAttesterSetRequest proto.InternalMessageInfo + +// AttesterSetEntry is a single entry in the attester set, ordered by index. +type AttesterSetEntry struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + ConsensusAddress string `protobuf:"bytes,2,opt,name=consensus_address,json=consensusAddress,proto3" json:"consensus_address,omitempty"` + Index uint32 `protobuf:"varint,3,opt,name=index,proto3" json:"index,omitempty"` + Pubkey *types.Any `protobuf:"bytes,4,opt,name=pubkey,proto3" json:"pubkey,omitempty"` +} + +func (m *AttesterSetEntry) Reset() { *m = AttesterSetEntry{} } +func (m *AttesterSetEntry) String() string { return proto.CompactTextString(m) } +func (*AttesterSetEntry) ProtoMessage() {} +func (*AttesterSetEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_faab6bfc228a74e1, []int{18} +} +func (m *AttesterSetEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AttesterSetEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AttesterSetEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AttesterSetEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_AttesterSetEntry.Merge(m, src) +} +func (m *AttesterSetEntry) XXX_Size() int { + return m.Size() +} +func (m *AttesterSetEntry) XXX_DiscardUnknown() { + xxx_messageInfo_AttesterSetEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_AttesterSetEntry proto.InternalMessageInfo + +// QueryAttesterSetResponse is the response type for the Query/AttesterSet RPC method. +type QueryAttesterSetResponse struct { + Entries []AttesterSetEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries"` +} + +func (m *QueryAttesterSetResponse) Reset() { *m = QueryAttesterSetResponse{} } +func (m *QueryAttesterSetResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAttesterSetResponse) ProtoMessage() {} +func (*QueryAttesterSetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_faab6bfc228a74e1, []int{19} +} +func (m *QueryAttesterSetResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAttesterSetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAttesterSetResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAttesterSetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAttesterSetResponse.Merge(m, src) +} +func (m *QueryAttesterSetResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAttesterSetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAttesterSetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAttesterSetResponse proto.InternalMessageInfo + +func (m *QueryAttesterSetResponse) GetEntries() []AttesterSetEntry { + if m != nil { + return m.Entries + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "evabci.network.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "evabci.network.v1.QueryParamsResponse") @@ -870,77 +995,94 @@ func init() { proto.RegisterType((*QueryLastAttestedHeightResponse)(nil), "evabci.network.v1.QueryLastAttestedHeightResponse") proto.RegisterType((*QueryAttesterInfoRequest)(nil), "evabci.network.v1.QueryAttesterInfoRequest") proto.RegisterType((*QueryAttesterInfoResponse)(nil), "evabci.network.v1.QueryAttesterInfoResponse") + proto.RegisterType((*QueryAttesterSetRequest)(nil), "evabci.network.v1.QueryAttesterSetRequest") + proto.RegisterType((*AttesterSetEntry)(nil), "evabci.network.v1.AttesterSetEntry") + proto.RegisterType((*QueryAttesterSetResponse)(nil), "evabci.network.v1.QueryAttesterSetResponse") } func init() { proto.RegisterFile("evabci/network/v1/query.proto", fileDescriptor_faab6bfc228a74e1) } var fileDescriptor_faab6bfc228a74e1 = []byte{ - // 1040 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xce, 0x36, 0x89, 0x21, 0x2f, 0xa1, 0x6d, 0xa6, 0x21, 0x24, 0x6e, 0xe3, 0x38, 0x0b, 0xb4, - 0x6e, 0x8b, 0x3d, 0x75, 0x50, 0x1b, 0x2a, 0xf5, 0xd2, 0xf0, 0xb3, 0x08, 0xa1, 0xb2, 0x91, 0x7a, - 0xe0, 0x80, 0x35, 0xf6, 0x8e, 0x37, 0xab, 0xda, 0x3b, 0x9b, 0x9d, 0xb1, 0x4b, 0x89, 0x72, 0xe1, - 0x08, 0x17, 0x24, 0xfe, 0x00, 0x04, 0x37, 0x04, 0x7f, 0x02, 0xe2, 0xdc, 0x63, 0x25, 0x2e, 0x9c, - 0x10, 0x4a, 0xf8, 0x43, 0xd0, 0xbe, 0x19, 0xaf, 0xd7, 0xf1, 0xae, 0x9d, 0x9c, 0x92, 0x7d, 0xef, - 0xfb, 0xde, 0xfb, 0xe6, 0xcd, 0xcc, 0x37, 0x86, 0x0d, 0xde, 0x67, 0xcd, 0x96, 0x4f, 0x03, 0xae, - 0x9e, 0x89, 0xe8, 0x29, 0xed, 0xd7, 0xe9, 0x41, 0x8f, 0x47, 0xcf, 0x6b, 0x61, 0x24, 0x94, 0x20, - 0xcb, 0x3a, 0x5d, 0x33, 0xe9, 0x5a, 0xbf, 0x5e, 0x5c, 0xf1, 0x84, 0x27, 0x30, 0x4b, 0xe3, 0xff, - 0x34, 0xb0, 0x78, 0xcd, 0x13, 0xc2, 0xeb, 0x70, 0xca, 0x42, 0x9f, 0xb2, 0x20, 0x10, 0x8a, 0x29, - 0x5f, 0x04, 0xd2, 0x64, 0x6f, 0xb5, 0x84, 0xec, 0x0a, 0x49, 0x9b, 0x4c, 0x72, 0x5d, 0x9f, 0xf6, - 0xeb, 0x4d, 0xae, 0x58, 0x9d, 0x86, 0xcc, 0xf3, 0x03, 0x04, 0x1b, 0x6c, 0x86, 0x22, 0xf5, 0x3c, - 0xe4, 0x83, 0x52, 0xe5, 0xf1, 0x34, 0x53, 0x8a, 0x4b, 0xc5, 0x23, 0x8d, 0xb0, 0x57, 0x80, 0x7c, - 0x11, 0xb7, 0x78, 0xcc, 0x22, 0xd6, 0x95, 0x0e, 0x3f, 0xe8, 0x71, 0xa9, 0xec, 0xcf, 0xe1, 0xca, - 0x48, 0x54, 0x86, 0x22, 0x90, 0x9c, 0xec, 0x40, 0x21, 0xc4, 0xc8, 0x9a, 0x55, 0xb6, 0x2a, 0x8b, - 0xdb, 0xeb, 0xb5, 0xb1, 0x15, 0xd7, 0x34, 0x65, 0x77, 0xee, 0xc5, 0x3f, 0x9b, 0x33, 0x8e, 0x81, - 0xdb, 0x3b, 0xb0, 0x81, 0xf5, 0x1e, 0x62, 0x73, 0x5c, 0xc0, 0xae, 0xaf, 0xba, 0x2c, 0x34, 0x0d, - 0xc9, 0x2a, 0x14, 0xf6, 0xb9, 0xef, 0xed, 0x2b, 0xac, 0x3c, 0xeb, 0x98, 0x2f, 0xfb, 0x2b, 0x28, - 0xe5, 0x11, 0x8d, 0xa6, 0x07, 0x50, 0x68, 0x62, 0xc4, 0x68, 0x7a, 0x2b, 0x43, 0xd3, 0x38, 0xdb, - 0x70, 0xec, 0x2a, 0xbc, 0x8e, 0xf5, 0x3f, 0x0c, 0x45, 0x6b, 0xff, 0x51, 0xd0, 0x16, 0x03, 0x41, - 0x2b, 0x30, 0xcf, 0xe3, 0x18, 0x56, 0x9d, 0x73, 0xf4, 0x87, 0xfd, 0xfd, 0x05, 0x58, 0x3d, 0x8d, - 0x37, 0x3a, 0x32, 0x09, 0x64, 0x0b, 0x96, 0xa4, 0x62, 0x91, 0x6a, 0x98, 0xd5, 0x5d, 0xc0, 0xd5, - 0x2d, 0x62, 0xec, 0x13, 0x0c, 0x91, 0x0d, 0x00, 0x1e, 0xb8, 0x03, 0xc0, 0x2c, 0x02, 0x16, 0x78, - 0xe0, 0x9a, 0x74, 0x1d, 0x56, 0x42, 0x16, 0x29, 0xbf, 0xe5, 0x87, 0xb8, 0x80, 0x86, 0x59, 0xed, - 0x5c, 0xd9, 0xaa, 0x2c, 0x39, 0x57, 0x46, 0x72, 0x7a, 0x71, 0xe4, 0x36, 0x2c, 0xb3, 0x96, 0xf2, - 0xfb, 0xbc, 0xd1, 0x67, 0x1d, 0xdf, 0x65, 0x4a, 0x44, 0x72, 0x6d, 0x1e, 0x65, 0x5d, 0xd6, 0x89, - 0x27, 0x49, 0x9c, 0xdc, 0x87, 0xb5, 0x54, 0x8d, 0xc0, 0x4b, 0x73, 0x0a, 0xc8, 0x79, 0x63, 0x24, - 0x3f, 0xa4, 0xda, 0xf7, 0xa0, 0x88, 0xc3, 0x48, 0x42, 0x8f, 0x02, 0x97, 0x7f, 0x3d, 0x98, 0xe0, - 0x1a, 0xbc, 0xc2, 0x5c, 0x37, 0xe2, 0x52, 0x9f, 0x96, 0x05, 0x67, 0xf0, 0x69, 0x3f, 0x81, 0xab, - 0x99, 0xbc, 0xe4, 0x94, 0xcd, 0xfb, 0x71, 0xc0, 0x6c, 0xe8, 0x56, 0xc6, 0x86, 0x9e, 0x62, 0x6a, - 0xbc, 0xfd, 0x00, 0x6c, 0xac, 0xbb, 0x27, 0xda, 0xea, 0x7d, 0x11, 0xb4, 0xfd, 0xa8, 0x8b, 0x63, - 0xd9, 0x53, 0x4c, 0xf5, 0xe4, 0xb4, 0xa3, 0xf6, 0x87, 0x05, 0x6f, 0x4e, 0xa4, 0x1b, 0x79, 0xb7, - 0x60, 0xd9, 0x97, 0x0d, 0x29, 0xda, 0xaa, 0xd1, 0xd2, 0x28, 0xee, 0x62, 0xa9, 0x57, 0x9d, 0x4b, - 0xbe, 0x4c, 0x91, 0xb9, 0x4b, 0x36, 0x61, 0xb1, 0x2f, 0x14, 0x77, 0x1b, 0xa1, 0x78, 0xc6, 0x23, - 0xdc, 0xfd, 0x39, 0x07, 0x30, 0xf4, 0x38, 0x8e, 0xc4, 0x00, 0x25, 0x14, 0xeb, 0x18, 0xc0, 0xac, - 0x06, 0x60, 0x48, 0x03, 0x6e, 0xc0, 0xa5, 0x83, 0x9e, 0x88, 0x7a, 0xdd, 0x46, 0x3b, 0x8a, 0xf7, - 0x4e, 0x04, 0xb8, 0xf3, 0x0b, 0xce, 0x45, 0x1d, 0xfe, 0xc8, 0x44, 0xed, 0xf7, 0x46, 0x6e, 0x0a, - 0x8f, 0xf6, 0x7c, 0x2f, 0x60, 0xaa, 0x17, 0x71, 0x39, 0xfd, 0x8e, 0x2d, 0x8f, 0x91, 0xe2, 0x33, - 0x94, 0x1c, 0x84, 0xc6, 0xe8, 0x3e, 0x5e, 0x4e, 0x12, 0x0f, 0x75, 0x9c, 0x5c, 0x83, 0x05, 0x39, - 0x60, 0xe2, 0x22, 0x97, 0x9c, 0x61, 0xc0, 0xf6, 0x60, 0x33, 0x57, 0x99, 0x99, 0xe9, 0x07, 0x00, - 0x09, 0x3e, 0x6e, 0x33, 0x3b, 0xf1, 0x22, 0xa7, 0x4a, 0x38, 0x29, 0x9e, 0x5d, 0x36, 0x23, 0xf8, - 0x8c, 0x49, 0x65, 0x90, 0xe6, 0x16, 0x0d, 0x7c, 0xed, 0xbe, 0x91, 0x92, 0x85, 0x30, 0x52, 0xf2, - 0xa6, 0xf4, 0x31, 0xac, 0x8d, 0xac, 0x22, 0x6d, 0x16, 0xe7, 0x19, 0x96, 0xcd, 0x60, 0x3d, 0xa3, - 0x50, 0x32, 0x88, 0xd7, 0x06, 0x06, 0xdd, 0xf0, 0x83, 0xb6, 0x30, 0x77, 0x60, 0x73, 0xc2, 0x2c, - 0x90, 0xbf, 0xc4, 0x52, 0x5f, 0xdb, 0x3f, 0x03, 0xcc, 0x63, 0x0f, 0xf2, 0x0d, 0x14, 0xb4, 0x21, - 0x93, 0xb7, 0x33, 0x4a, 0x8c, 0x3b, 0x7f, 0xf1, 0xfa, 0x34, 0x98, 0x16, 0x6a, 0x6f, 0x7d, 0xfb, - 0xd7, 0x7f, 0x3f, 0x5e, 0xb8, 0x4a, 0xd6, 0xe9, 0xf8, 0x13, 0xa3, 0x4d, 0x9f, 0xfc, 0x6a, 0x0d, - 0x0e, 0x56, 0xda, 0x9c, 0xee, 0xe4, 0x35, 0xc8, 0x7b, 0x1b, 0x8a, 0xf5, 0x73, 0x30, 0x8c, 0x3a, - 0x8a, 0xea, 0x6e, 0x92, 0x1b, 0x34, 0xef, 0x01, 0x44, 0x16, 0x3d, 0xd4, 0x9b, 0x7b, 0x44, 0xbe, - 0xb3, 0x60, 0x21, 0xf1, 0x74, 0x52, 0xc9, 0xeb, 0x78, 0xfa, 0x99, 0x28, 0xde, 0x3c, 0x03, 0xd2, - 0x68, 0xaa, 0xa0, 0x26, 0x9b, 0x94, 0x33, 0x34, 0xe1, 0x63, 0x41, 0x0f, 0xf1, 0xcf, 0x11, 0xf9, - 0xc9, 0x82, 0x8b, 0xa3, 0x0e, 0x47, 0xaa, 0x79, 0x7d, 0x32, 0xbd, 0xb7, 0x58, 0x3b, 0x2b, 0xdc, - 0x68, 0xab, 0xa1, 0xb6, 0x0a, 0xb9, 0x9e, 0xa1, 0x2d, 0x39, 0xc0, 0xf4, 0xd0, 0x1c, 0xed, 0x23, - 0xf2, 0xa7, 0x05, 0xab, 0xd9, 0x36, 0x49, 0xee, 0xe6, 0xb5, 0x9e, 0xe8, 0xca, 0xc5, 0x7b, 0xe7, - 0xa5, 0x19, 0xe5, 0x77, 0x51, 0x39, 0x25, 0xd5, 0x0c, 0xe5, 0xb1, 0x47, 0x57, 0x5b, 0x29, 0xee, - 0x70, 0xbf, 0x7f, 0xb3, 0x80, 0x8c, 0xfb, 0x11, 0x99, 0x72, 0xd4, 0x32, 0x5c, 0xb5, 0xb8, 0x7d, - 0x1e, 0xca, 0x19, 0xc6, 0x3d, 0xf4, 0xb3, 0xa1, 0xda, 0xdf, 0x2d, 0x20, 0xe3, 0x96, 0x95, 0xaf, - 0x36, 0xd7, 0x00, 0xf3, 0xd5, 0xe6, 0x3b, 0xe2, 0xc4, 0xcb, 0xd4, 0x61, 0x52, 0x55, 0x8d, 0xf7, - 0xb8, 0x55, 0xad, 0x97, 0xfc, 0x62, 0xc1, 0x52, 0xda, 0x9d, 0xc8, 0xed, 0x69, 0x33, 0x4a, 0x5f, - 0xa9, 0x77, 0xce, 0x06, 0x36, 0xe2, 0x76, 0x50, 0x5c, 0x9d, 0x50, 0x9a, 0xff, 0x53, 0x97, 0x1e, - 0x8e, 0xb9, 0xf3, 0xd1, 0xee, 0xa7, 0x2f, 0x8e, 0x4b, 0xd6, 0xcb, 0xe3, 0x92, 0xf5, 0xef, 0x71, - 0xc9, 0xfa, 0xe1, 0xa4, 0x34, 0xf3, 0xf2, 0xa4, 0x34, 0xf3, 0xf7, 0x49, 0x69, 0xe6, 0xcb, 0x3b, - 0x9e, 0xaf, 0xf6, 0x7b, 0xcd, 0x5a, 0x4b, 0x74, 0x29, 0xef, 0x4b, 0xc5, 0x5a, 0x4f, 0x29, 0xef, - 0x57, 0xb1, 0x7a, 0x57, 0xb8, 0xbd, 0x0e, 0x97, 0x49, 0x17, 0xfc, 0xb1, 0xdd, 0x2c, 0xe0, 0x6f, - 0xe9, 0x77, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3d, 0xe0, 0x17, 0xeb, 0x20, 0x0c, 0x00, 0x00, + // 1253 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, + 0x17, 0xf7, 0xe6, 0x87, 0x5b, 0x3f, 0xa7, 0x6d, 0x32, 0xf5, 0xb7, 0x75, 0xdc, 0xd6, 0x4e, 0xb6, + 0x5f, 0xda, 0xb4, 0xc5, 0xbb, 0x75, 0x50, 0x5b, 0x8a, 0x7a, 0x69, 0x4a, 0x0b, 0x05, 0x84, 0xca, + 0x46, 0xea, 0x81, 0x03, 0xab, 0xb1, 0x3d, 0x76, 0x56, 0x8d, 0x77, 0xb6, 0x3b, 0xb3, 0x2e, 0x26, + 0xca, 0x85, 0x13, 0x82, 0x03, 0x48, 0xfc, 0x01, 0x54, 0xdc, 0x10, 0xdc, 0xe0, 0x88, 0x38, 0x57, + 0x9c, 0x2a, 0xb8, 0x70, 0x42, 0x28, 0xe1, 0xc0, 0xbf, 0xc0, 0x0d, 0xed, 0xcc, 0xec, 0x7a, 0x1d, + 0xef, 0xda, 0xc9, 0xa9, 0x9d, 0xf7, 0x3e, 0x9f, 0x37, 0x9f, 0x79, 0x33, 0x6f, 0x3f, 0x31, 0x5c, + 0x20, 0x7d, 0xdc, 0x6c, 0x39, 0xa6, 0x4b, 0xf8, 0x33, 0xea, 0x3f, 0x31, 0xfb, 0x0d, 0xf3, 0x69, + 0x40, 0xfc, 0x81, 0xe1, 0xf9, 0x94, 0x53, 0xb4, 0x24, 0xd3, 0x86, 0x4a, 0x1b, 0xfd, 0x46, 0xa5, + 0xd4, 0xa5, 0x5d, 0x2a, 0xb2, 0x66, 0xf8, 0x3f, 0x09, 0xac, 0x9c, 0xef, 0x52, 0xda, 0xdd, 0x26, + 0x26, 0xf6, 0x1c, 0x13, 0xbb, 0x2e, 0xe5, 0x98, 0x3b, 0xd4, 0x65, 0x2a, 0xbb, 0xac, 0xb2, 0x62, + 0xd5, 0x0c, 0x3a, 0x26, 0x76, 0x07, 0x51, 0xaa, 0x45, 0x59, 0x8f, 0x32, 0x5b, 0x56, 0x94, 0x0b, + 0x95, 0xba, 0x2a, 0x57, 0x66, 0x13, 0x33, 0x22, 0x55, 0x99, 0xfd, 0x46, 0x93, 0x70, 0xdc, 0x30, + 0x3d, 0xdc, 0x75, 0x5c, 0xb1, 0x85, 0xc2, 0xa6, 0x9c, 0x83, 0x0f, 0x3c, 0x12, 0x95, 0x5a, 0x19, + 0x4f, 0x63, 0xce, 0x09, 0xe3, 0xc4, 0x97, 0x08, 0xbd, 0x04, 0xe8, 0x83, 0x70, 0x8b, 0x47, 0xd8, + 0xc7, 0x3d, 0x66, 0x91, 0xa7, 0x01, 0x61, 0x5c, 0x7f, 0x1f, 0x4e, 0x8f, 0x44, 0x99, 0x47, 0x5d, + 0x46, 0xd0, 0x2d, 0xc8, 0x7b, 0x22, 0x52, 0xd6, 0x56, 0xb4, 0xb5, 0xe2, 0xfa, 0xb2, 0x31, 0xd6, + 0x27, 0x43, 0x52, 0x36, 0xe6, 0x5e, 0xfc, 0x59, 0xcb, 0x59, 0x0a, 0xae, 0xdf, 0x82, 0x0b, 0xa2, + 0xde, 0x5d, 0xb1, 0xb9, 0x38, 0xc0, 0x86, 0xc3, 0x7b, 0xd8, 0x53, 0x1b, 0xa2, 0x33, 0x90, 0xdf, + 0x22, 0x4e, 0x77, 0x8b, 0x8b, 0xca, 0xb3, 0x96, 0x5a, 0xe9, 0x1f, 0x41, 0x35, 0x8b, 0xa8, 0x34, + 0xdd, 0x81, 0x7c, 0x53, 0x44, 0x94, 0xa6, 0xff, 0xa7, 0x68, 0x1a, 0x67, 0x2b, 0x8e, 0x5e, 0x87, + 0xff, 0x89, 0xfa, 0xf7, 0x3d, 0xda, 0xda, 0x7a, 0xe8, 0x76, 0x68, 0x24, 0xa8, 0x04, 0xf3, 0x24, + 0x8c, 0x89, 0xaa, 0x73, 0x96, 0x5c, 0xe8, 0x5f, 0xcc, 0xc0, 0x99, 0x83, 0x78, 0xa5, 0x23, 0x95, + 0x80, 0x56, 0x61, 0x81, 0x71, 0xec, 0x73, 0x5b, 0x9d, 0x6e, 0x46, 0x9c, 0xae, 0x28, 0x62, 0x6f, + 0x8b, 0x10, 0xba, 0x00, 0x40, 0xdc, 0x76, 0x04, 0x98, 0x15, 0x80, 0x02, 0x71, 0xdb, 0x2a, 0xdd, + 0x80, 0x92, 0x87, 0x7d, 0xee, 0xb4, 0x1c, 0x4f, 0x1c, 0xc0, 0x56, 0xa7, 0x9d, 0x5b, 0xd1, 0xd6, + 0x16, 0xac, 0xd3, 0x23, 0x39, 0x79, 0x38, 0x74, 0x0d, 0x96, 0x70, 0x8b, 0x3b, 0x7d, 0x62, 0xf7, + 0xf1, 0xb6, 0xd3, 0xc6, 0x9c, 0xfa, 0xac, 0x3c, 0x2f, 0x64, 0x2d, 0xca, 0xc4, 0xe3, 0x38, 0x8e, + 0x6e, 0x43, 0x39, 0x51, 0xc3, 0xed, 0x26, 0x39, 0x79, 0xc1, 0x39, 0x3b, 0x92, 0x1f, 0x52, 0xf5, + 0x9b, 0x50, 0x11, 0xcd, 0x88, 0x43, 0x0f, 0xdd, 0x36, 0xf9, 0x38, 0xea, 0x60, 0x19, 0x8e, 0xe1, + 0x76, 0xdb, 0x27, 0x4c, 0xbe, 0x96, 0x82, 0x15, 0x2d, 0xf5, 0xc7, 0x70, 0x2e, 0x95, 0x17, 0xbf, + 0xb2, 0x79, 0x27, 0x0c, 0xa8, 0x0b, 0x5d, 0x4d, 0xb9, 0xd0, 0x03, 0x4c, 0x89, 0xd7, 0xef, 0x80, + 0x2e, 0xea, 0x6e, 0xd2, 0x0e, 0xbf, 0x47, 0xdd, 0x8e, 0xe3, 0xf7, 0x44, 0x5b, 0x36, 0x39, 0xe6, + 0x01, 0x9b, 0xf6, 0xd4, 0x7e, 0xd6, 0xe0, 0xe2, 0x44, 0xba, 0x92, 0x77, 0x15, 0x96, 0x1c, 0x66, + 0x33, 0xda, 0xe1, 0x76, 0x4b, 0xa2, 0x48, 0x5b, 0x94, 0x3a, 0x6e, 0x9d, 0x72, 0x58, 0x82, 0x4c, + 0xda, 0xa8, 0x06, 0xc5, 0x3e, 0xe5, 0xa4, 0x6d, 0x7b, 0xf4, 0x19, 0xf1, 0xc5, 0xed, 0xcf, 0x59, + 0x20, 0x42, 0x8f, 0xc2, 0x48, 0x08, 0xe0, 0x94, 0xe3, 0x6d, 0x05, 0x98, 0x95, 0x00, 0x11, 0x92, + 0x80, 0xcb, 0x70, 0xea, 0x69, 0x40, 0xfd, 0xa0, 0x67, 0x77, 0xfc, 0xf0, 0xee, 0xa8, 0x2b, 0x6e, + 0xbe, 0x60, 0x9d, 0x94, 0xe1, 0x07, 0x2a, 0xaa, 0xbf, 0x3e, 0x32, 0x29, 0xc4, 0xdf, 0x74, 0xba, + 0x2e, 0xe6, 0x81, 0x4f, 0xd8, 0xf4, 0x19, 0x5b, 0x1a, 0x23, 0x85, 0x6f, 0x28, 0x7e, 0x08, 0xf6, + 0xe8, 0x3d, 0x2e, 0xc6, 0x89, 0xbb, 0x32, 0x8e, 0xce, 0x43, 0x81, 0x45, 0x4c, 0x71, 0xc8, 0x05, + 0x6b, 0x18, 0xd0, 0xbb, 0x50, 0xcb, 0x54, 0xa6, 0x7a, 0xfa, 0x26, 0x40, 0x8c, 0x0f, 0xb7, 0x99, + 0x9d, 0x38, 0xc8, 0x89, 0x12, 0x56, 0x82, 0xa7, 0xaf, 0xa8, 0x16, 0xbc, 0x87, 0x19, 0x57, 0x48, + 0x35, 0x45, 0xd1, 0x77, 0xed, 0xb6, 0x92, 0x92, 0x86, 0x50, 0x52, 0xb2, 0xba, 0xf4, 0x16, 0x94, + 0x47, 0x4e, 0x91, 0xfc, 0x58, 0x1c, 0xa5, 0x59, 0x3a, 0x86, 0xe5, 0x94, 0x42, 0x71, 0x23, 0x4e, + 0x44, 0x1f, 0x68, 0xdb, 0x71, 0x3b, 0x54, 0xcd, 0x40, 0x6d, 0x42, 0x2f, 0x04, 0x7f, 0x01, 0x27, + 0x56, 0xfa, 0x32, 0x9c, 0x1d, 0xed, 0x38, 0x89, 0x3b, 0xf0, 0xaf, 0x06, 0x8b, 0x89, 0xf0, 0x7d, + 0x97, 0xfb, 0x03, 0x74, 0x13, 0x0a, 0x38, 0xe0, 0x5b, 0xd4, 0x77, 0xf8, 0x40, 0xea, 0xde, 0x28, + 0xff, 0xf6, 0x53, 0xbd, 0xa4, 0x6c, 0x49, 0x29, 0xdf, 0xe4, 0xbe, 0xe3, 0x76, 0xad, 0x21, 0x14, + 0xdd, 0x87, 0xa5, 0x56, 0x28, 0xdb, 0x65, 0x01, 0x8b, 0xcf, 0x3d, 0x33, 0x85, 0xbf, 0x18, 0x53, + 0xa2, 0xe7, 0x53, 0x8a, 0x06, 0x3e, 0x7c, 0xfe, 0x27, 0xd4, 0x34, 0xa3, 0x07, 0x90, 0xf7, 0x82, + 0xe6, 0x13, 0x32, 0x10, 0x0f, 0xbe, 0xb8, 0x5e, 0x32, 0xa4, 0x9b, 0x1a, 0x91, 0x9b, 0x1a, 0x77, + 0xdd, 0xc1, 0x46, 0xf9, 0xd7, 0xe1, 0x3e, 0x2d, 0x7f, 0xe0, 0x71, 0x6a, 0x3c, 0x0a, 0x9a, 0xef, + 0x92, 0x81, 0xa5, 0xd8, 0x6f, 0x1c, 0xff, 0xec, 0x79, 0x2d, 0xf7, 0xcf, 0xf3, 0x5a, 0x4e, 0xb7, + 0x0f, 0x5c, 0xa1, 0x68, 0x8b, 0x6a, 0xfc, 0x3d, 0x38, 0x46, 0x5c, 0xee, 0x3b, 0xf1, 0xf3, 0xbb, + 0x38, 0xe9, 0xf9, 0xa9, 0xc6, 0x29, 0x97, 0x8b, 0x98, 0xeb, 0x3f, 0x16, 0x61, 0x5e, 0xec, 0x80, + 0x3e, 0x81, 0xbc, 0x34, 0x42, 0xf4, 0x4a, 0x4a, 0x9d, 0x71, 0xc7, 0xad, 0x5c, 0x9a, 0x06, 0x93, + 0x3a, 0xf5, 0xd5, 0x4f, 0x7f, 0xff, 0xfb, 0xeb, 0x99, 0x73, 0x68, 0xd9, 0x1c, 0xb7, 0x76, 0x69, + 0xb6, 0xe8, 0x3b, 0x2d, 0x1a, 0xe8, 0xa4, 0x29, 0x5c, 0xcf, 0xda, 0x20, 0xcb, 0x93, 0x2b, 0x8d, + 0x23, 0x30, 0x94, 0x3a, 0x53, 0xa8, 0xbb, 0x82, 0x2e, 0x9b, 0x59, 0x7f, 0x78, 0x08, 0x96, 0xb9, + 0x23, 0x87, 0x6a, 0x17, 0x7d, 0xae, 0x41, 0x21, 0xf6, 0x52, 0xb4, 0x96, 0xb5, 0xe3, 0x41, 0x7b, + 0xae, 0x5c, 0x39, 0x04, 0x52, 0x69, 0x5a, 0x13, 0x9a, 0x74, 0xb4, 0x92, 0xa2, 0x49, 0x98, 0xb4, + 0xb9, 0x23, 0xfe, 0xd9, 0x45, 0xdf, 0x68, 0x70, 0x72, 0xd4, 0x59, 0x50, 0x3d, 0x6b, 0x9f, 0x54, + 0xcf, 0xab, 0x18, 0x87, 0x85, 0x2b, 0x6d, 0x86, 0xd0, 0xb6, 0x86, 0x2e, 0xa5, 0x68, 0x8b, 0x3f, + 0x1c, 0xe6, 0x8e, 0x1a, 0xad, 0x5d, 0xf4, 0x8b, 0x06, 0x67, 0xd2, 0xed, 0x09, 0xdd, 0xc8, 0xda, + 0x7a, 0xa2, 0x1b, 0x56, 0x6e, 0x1e, 0x95, 0xa6, 0x94, 0xdf, 0x10, 0xca, 0x4d, 0x54, 0x4f, 0x51, + 0x1e, 0x7a, 0x63, 0xbd, 0x95, 0xe0, 0x0e, 0xef, 0xfb, 0x7b, 0x0d, 0xd0, 0xb8, 0x0f, 0xa0, 0x29, + 0x4f, 0x2d, 0xc5, 0xcd, 0x2a, 0xeb, 0x47, 0xa1, 0x1c, 0xa2, 0xdd, 0x43, 0x1f, 0x19, 0xaa, 0xfd, + 0x41, 0x03, 0x34, 0x6e, 0x15, 0xd9, 0x6a, 0x33, 0x8d, 0x27, 0x5b, 0x6d, 0xb6, 0x13, 0x4d, 0x1c, + 0xa6, 0x6d, 0xcc, 0x78, 0x5d, 0x7d, 0xf3, 0xdb, 0x75, 0xa9, 0x17, 0x7d, 0xab, 0xc1, 0x42, 0xd2, + 0x15, 0xd0, 0xb5, 0x69, 0x3d, 0x4a, 0x8e, 0xd4, 0xab, 0x87, 0x03, 0x2b, 0x71, 0xb7, 0x84, 0xb8, + 0x06, 0x32, 0xcd, 0xec, 0x9f, 0x18, 0xe6, 0xce, 0x98, 0x2b, 0xee, 0xa2, 0x2f, 0x35, 0x28, 0x26, + 0xbe, 0xa3, 0xe8, 0xea, 0xd4, 0x7b, 0x8c, 0xcd, 0xab, 0x72, 0xed, 0x50, 0x58, 0xa5, 0xf0, 0xb2, + 0x50, 0xb8, 0x8a, 0x6a, 0x13, 0x14, 0xda, 0x8c, 0xf0, 0x8d, 0x77, 0x5e, 0xec, 0x55, 0xb5, 0x97, + 0x7b, 0x55, 0xed, 0xaf, 0xbd, 0xaa, 0xf6, 0xd5, 0x7e, 0x35, 0xf7, 0x72, 0xbf, 0x9a, 0xfb, 0x63, + 0xbf, 0x9a, 0xfb, 0xf0, 0x7a, 0xd7, 0xe1, 0x5b, 0x41, 0xd3, 0x68, 0xd1, 0x9e, 0x49, 0xfa, 0x8c, + 0xe3, 0xd6, 0x13, 0x93, 0xf4, 0xeb, 0xa2, 0x5a, 0x8f, 0xb6, 0x83, 0x6d, 0xc2, 0xe2, 0xaa, 0xe2, + 0x67, 0x57, 0x33, 0x2f, 0xcc, 0xe9, 0xb5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x10, 0xfd, 0x50, + 0xd7, 0x60, 0x0e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -971,6 +1113,8 @@ type QueryClient interface { LastAttestedHeight(ctx context.Context, in *QueryLastAttestedHeightRequest, opts ...grpc.CallOption) (*QueryLastAttestedHeightResponse, error) // AttesterInfo queries the attester information including public key AttesterInfo(ctx context.Context, in *QueryAttesterInfoRequest, opts ...grpc.CallOption) (*QueryAttesterInfoResponse, error) + // AttesterSet queries the full ordered attester set + AttesterSet(ctx context.Context, in *QueryAttesterSetRequest, opts ...grpc.CallOption) (*QueryAttesterSetResponse, error) } type queryClient struct { @@ -1053,6 +1197,15 @@ func (c *queryClient) AttesterInfo(ctx context.Context, in *QueryAttesterInfoReq return out, nil } +func (c *queryClient) AttesterSet(ctx context.Context, in *QueryAttesterSetRequest, opts ...grpc.CallOption) (*QueryAttesterSetResponse, error) { + out := new(QueryAttesterSetResponse) + err := c.cc.Invoke(ctx, "/evabci.network.v1.Query/AttesterSet", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params queries the module parameters @@ -1071,6 +1224,8 @@ type QueryServer interface { LastAttestedHeight(context.Context, *QueryLastAttestedHeightRequest) (*QueryLastAttestedHeightResponse, error) // AttesterInfo queries the attester information including public key AttesterInfo(context.Context, *QueryAttesterInfoRequest) (*QueryAttesterInfoResponse, error) + // AttesterSet queries the full ordered attester set + AttesterSet(context.Context, *QueryAttesterSetRequest) (*QueryAttesterSetResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1101,6 +1256,9 @@ func (*UnimplementedQueryServer) LastAttestedHeight(ctx context.Context, req *Qu func (*UnimplementedQueryServer) AttesterInfo(ctx context.Context, req *QueryAttesterInfoRequest) (*QueryAttesterInfoResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AttesterInfo not implemented") } +func (*UnimplementedQueryServer) AttesterSet(ctx context.Context, req *QueryAttesterSetRequest) (*QueryAttesterSetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AttesterSet not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1250,6 +1408,24 @@ func _Query_AttesterInfo_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Query_AttesterSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAttesterSetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AttesterSet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/evabci.network.v1.Query/AttesterSet", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AttesterSet(ctx, req.(*QueryAttesterSetRequest)) + } + return interceptor(ctx, in, info, handler) +} + var Query_serviceDesc = _Query_serviceDesc var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "evabci.network.v1.Query", @@ -1287,6 +1463,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "AttesterInfo", Handler: _Query_AttesterInfo_Handler, }, + { + MethodName: "AttesterSet", + Handler: _Query_AttesterSet_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evabci/network/v1/query.proto", @@ -1855,6 +2035,120 @@ func (m *QueryAttesterInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *QueryAttesterSetRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAttesterSetRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAttesterSetRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *AttesterSetEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AttesterSetEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AttesterSetEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pubkey != nil { + { + size, err := m.Pubkey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.Index != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x18 + } + if len(m.ConsensusAddress) > 0 { + i -= len(m.ConsensusAddress) + copy(dAtA[i:], m.ConsensusAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsensusAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAttesterSetResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAttesterSetResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAttesterSetResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -2102,6 +2396,54 @@ func (m *QueryAttesterInfoResponse) Size() (n int) { return n } +func (m *QueryAttesterSetRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *AttesterSetEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConsensusAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Index != 0 { + n += 1 + sovQuery(uint64(m.Index)) + } + if m.Pubkey != nil { + l = m.Pubkey.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAttesterSetResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3577,6 +3919,309 @@ func (m *QueryAttesterInfoResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryAttesterSetRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAttesterSetRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAttesterSetRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AttesterSetEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AttesterSetEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AttesterSetEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsensusAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pubkey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pubkey == nil { + m.Pubkey = &types.Any{} + } + if err := m.Pubkey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAttesterSetResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAttesterSetResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAttesterSetResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, AttesterSetEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/network/types/query.pb.gw.go b/modules/network/types/query.pb.gw.go index 1dc93cde..91b4d014 100644 --- a/modules/network/types/query.pb.gw.go +++ b/modules/network/types/query.pb.gw.go @@ -393,6 +393,24 @@ func local_request_Query_AttesterInfo_0(ctx context.Context, marshaler runtime.M } +func request_Query_AttesterSet_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAttesterSetRequest + var metadata runtime.ServerMetadata + + msg, err := client.AttesterSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AttesterSet_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAttesterSetRequest + var metadata runtime.ServerMetadata + + msg, err := server.AttesterSet(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -583,6 +601,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_AttesterSet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AttesterSet_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AttesterSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -784,6 +825,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_AttesterSet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AttesterSet_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AttesterSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -803,6 +864,8 @@ var ( pattern_Query_LastAttestedHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"evabci", "network", "v1", "last-attested-height"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_AttesterInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"evabci", "network", "v1", "attester", "validator_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AttesterSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"evabci", "network", "v1", "attester_set"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -821,4 +884,6 @@ var ( forward_Query_LastAttestedHeight_0 = runtime.ForwardResponseMessage forward_Query_AttesterInfo_0 = runtime.ForwardResponseMessage + + forward_Query_AttesterSet_0 = runtime.ForwardResponseMessage ) diff --git a/modules/proto/evabci/network/v1/query.proto b/modules/proto/evabci/network/v1/query.proto index 366c39bb..ac16858b 100644 --- a/modules/proto/evabci/network/v1/query.proto +++ b/modules/proto/evabci/network/v1/query.proto @@ -6,6 +6,8 @@ option go_package = "github.com/evstack/ev-abci/modules/network/types"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; import "evabci/network/v1/types.proto"; import "evabci/network/v1/attester.proto"; @@ -51,6 +53,11 @@ service Query { rpc AttesterInfo(QueryAttesterInfoRequest) returns (QueryAttesterInfoResponse) { option (google.api.http).get = "/evabci/network/v1/attester/{validator_address}"; } + + // AttesterSet queries the full ordered attester set + rpc AttesterSet(QueryAttesterSetRequest) returns (QueryAttesterSetResponse) { + option (google.api.http).get = "/evabci/network/v1/attester_set"; + } } // QueryParamsRequest is the request type for the Query/Params RPC method. @@ -143,3 +150,21 @@ message QueryAttesterInfoRequest { message QueryAttesterInfoResponse { AttesterInfo attester_info = 1; } + +// QueryAttesterSetRequest is the request type for the Query/AttesterSet RPC method. +message QueryAttesterSetRequest {} + +// AttesterSetEntry is a single entry in the attester set, ordered by index. +message AttesterSetEntry { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string consensus_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + uint32 index = 3; + google.protobuf.Any pubkey = 4 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"]; +} + +// QueryAttesterSetResponse is the response type for the Query/AttesterSet RPC method. +message QueryAttesterSetResponse { + repeated AttesterSetEntry entries = 1 [(gogoproto.nullable) = false]; +} diff --git a/pkg/adapter/providers_test.go b/pkg/adapter/providers_test.go new file mode 100644 index 00000000..d9cb9a91 --- /dev/null +++ b/pkg/adapter/providers_test.go @@ -0,0 +1,66 @@ +package adapter_test + +import ( + "bytes" + "context" + "sort" + "testing" + + tmcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" + cmtstate "github.com/cometbft/cometbft/state" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/stretchr/testify/require" + + "github.com/evstack/ev-abci/pkg/adapter" +) + +type mockStateStore struct { + state *cmtstate.State +} + +func (m *mockStateStore) LoadState(_ context.Context) (*cmtstate.State, error) { + return m.state, nil +} + +func TestValidatorHasherOrderingMatchesAddressSort(t *testing.T) { + // 3 random ed25519 validators + keys := []tmcryptoed25519.PubKey{ + tmcryptoed25519.GenPrivKey().PubKey().(tmcryptoed25519.PubKey), + tmcryptoed25519.GenPrivKey().PubKey().(tmcryptoed25519.PubKey), + tmcryptoed25519.GenPrivKey().PubKey().(tmcryptoed25519.PubKey), + } + + // Canonical: sort by Address() bytes ascending, convert to libp2p, hash. + canonicalOrder := make([]tmcryptoed25519.PubKey, len(keys)) + copy(canonicalOrder, keys) + sort.Slice(canonicalOrder, func(i, j int) bool { + return bytes.Compare(canonicalOrder[i].Address(), canonicalOrder[j].Address()) < 0 + }) + libp2pCanonical := make([]crypto.PubKey, len(canonicalOrder)) + for i, k := range canonicalOrder { + p, err := crypto.UnmarshalEd25519PublicKey(k.Bytes()) + require.NoError(t, err) + libp2pCanonical[i] = p + } + sequencerAddr := canonicalOrder[0].Address().Bytes() + canonicalHash, err := adapter.ValidatorsHasher(libp2pCanonical, sequencerAddr) + require.NoError(t, err) + + // Build a cmttypes.ValidatorSet via NewValidatorSet (will sort internally). + vals := make([]*cmttypes.Validator, len(keys)) + for i, k := range keys { + vals[i] = cmttypes.NewValidator(k, 1) + } + vs := cmttypes.NewValidatorSet(vals) + + // Wrap in a mock state and call the provider. + st := &cmtstate.State{Validators: vs} + store := &mockStateStore{state: st} + hasher := adapter.ValidatorHasherFromStoreProvider(store) + gotHash, err := hasher(sequencerAddr, nil) + require.NoError(t, err) + + require.Equal(t, []byte(canonicalHash), []byte(gotHash), + "provider hash must match address-sorted canonical hash") +} diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index 73921e5d..d3c04bbb 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -15,7 +15,7 @@ import ( ctypes "github.com/cometbft/cometbft/rpc/core/types" rpctypes "github.com/cometbft/cometbft/rpc/jsonrpc/types" cmttypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/gogoproto/proto" storepkg "github.com/evstack/ev-node/pkg/store" @@ -334,82 +334,109 @@ func BlockchainInfo(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes. }, nil } -// getCommitForHeight returns commit info for a specific height, -// using attester signatures if in attester mode, otherwise sequencer signatures +// getCommitForHeight returns a deterministic cmttypes.Commit for height. +// In attester mode it builds the commit from the ordered attester set, placing +// BlockIDFlagAbsent for non-signers and refusing to return until 2/3 quorum is met. func getCommitForHeight(ctx context.Context, height uint64) (*cmttypes.Commit, error) { - // Debug: Log attester mode status - env.Logger.Info("getCommitForHeight called", - "height", height, - "AttesterMode", env.AttesterMode) - - // If not in attester mode, use the original sequencer-based commit if !env.AttesterMode { - env.Logger.Info("Using sequencer mode - returning sequencer signatures") return env.Adapter.GetLastCommit(ctx, height+1) } - // In attester mode, try to construct commit from attester signatures blockID, err := env.Adapter.Store.GetBlockID(ctx, height) if err != nil { return nil, fmt.Errorf("get block ID for height %d: %w", height, err) } - // Query attester signatures from the network module - env.Logger.Info("In attester mode - querying attester signatures", "height", height) + entries, err := getAttesterSet(ctx) + if err != nil { + return nil, fmt.Errorf("get attester set: %w", err) + } signatures, err := getAttesterSignatures(ctx, int64(height)) if err != nil { - env.Logger.Error("failed to get attester signatures", - "height", height, "error", err) - return nil, fmt.Errorf("attester mode: failed to get attester signatures for height %d: %w", height, err) + return nil, fmt.Errorf("get attester signatures: %w", err) } - // Build commit with attester signatures - commitSigs := make([]cmttypes.CommitSig, 0, len(signatures)) - for validatorAddr, signature := range signatures { - // Parse the signature bytes (they should be marshaled cmtproto.Vote) - var vote cmtproto.Vote - if err := proto.Unmarshal(signature, &vote); err != nil { - env.Logger.Error("failed to unmarshal attester vote", - "validator", validatorAddr, "error", err) + commitSigs := make([]cmttypes.CommitSig, 0, len(entries)) + signedCount := 0 + for _, e := range entries { + voteBytes, ok := signatures[e.ConsensusAddress] + if !ok { + commitSigs = append(commitSigs, cmttypes.CommitSig{BlockIDFlag: cmttypes.BlockIDFlagAbsent}) continue } - - // Decode bech32 validator address to get 20-byte address - valAddrBytes, err := sdk.ValAddressFromBech32(validatorAddr) - if err != nil { - env.Logger.Error("failed to decode validator address", - "validator", validatorAddr, "error", err) + var vote cmtproto.Vote + if err := proto.Unmarshal(voteBytes, &vote); err != nil { + commitSigs = append(commitSigs, cmttypes.CommitSig{BlockIDFlag: cmttypes.BlockIDFlagAbsent}) continue } - commitSigs = append(commitSigs, cmttypes.CommitSig{ BlockIDFlag: cmttypes.BlockIDFlagCommit, - ValidatorAddress: cmttypes.Address(valAddrBytes), + ValidatorAddress: e.ValidatorAddress, Timestamp: vote.Timestamp, Signature: vote.Signature, }) + signedCount++ } - // If no valid attester signatures, return error instead of fallback - if len(commitSigs) == 0 { - env.Logger.Error("no attester signatures found for block", "height", height) - return nil, fmt.Errorf("attester mode: no attester signatures found for height %d - block not attested", height) + total := len(entries) + if signedCount*3 <= total*2 { + return nil, fmt.Errorf("height %d not yet attested (signed %d of %d)", height, signedCount, total) } return &cmttypes.Commit{ - Height: int64(height), + Height: int64(height), //nolint:gosec Round: 0, BlockID: *blockID, Signatures: commitSigs, }, nil } -// getAttesterSignatures queries the network module to get all attester signatures for a height -func getAttesterSignatures(ctx context.Context, height int64) (map[string][]byte, error) { - // Use the new AttesterSignatures gRPC endpoint - env.Logger.Info("Querying AttesterSignatures endpoint", "height", height) +// attesterSetEntry holds an ordered attester set entry used for commit reconstruction. +type attesterSetEntry struct { + ConsensusAddress string + ValidatorAddress []byte + Pubkey cryptotypes.PubKey +} + +// getAttesterSet fetches the ordered attester set from the network module via ABCI query. +func getAttesterSet(ctx context.Context) ([]attesterSetEntry, error) { + req, err := proto.Marshal(&networktypes.QueryAttesterSetRequest{}) + if err != nil { + return nil, err + } + result, err := env.Adapter.App.Query(ctx, &abci.RequestQuery{ + Path: "/evabci.network.v1.Query/AttesterSet", + Data: req, + }) + if err != nil { + return nil, err + } + if result.Code != 0 { + return nil, fmt.Errorf("query AttesterSet failed: %s", result.Log) + } + var resp networktypes.QueryAttesterSetResponse + if err := proto.Unmarshal(result.Value, &resp); err != nil { + return nil, err + } + sort.Slice(resp.Entries, func(i, j int) bool { return resp.Entries[i].Index < resp.Entries[j].Index }) + + out := make([]attesterSetEntry, 0, len(resp.Entries)) + for _, e := range resp.Entries { + var pk cryptotypes.PubKey + if err := networktypes.ModuleCdc.InterfaceRegistry().UnpackAny(e.Pubkey, &pk); err != nil { + return nil, fmt.Errorf("unpack pubkey for %s: %w", e.ConsensusAddress, err) + } + out = append(out, attesterSetEntry{ + ConsensusAddress: e.ConsensusAddress, + ValidatorAddress: pk.Address(), + Pubkey: pk, + }) + } + return out, nil +} - // Query individual attester signatures using the new endpoint +// getAttesterSignatures queries the network module to get all attester signatures for a height. +func getAttesterSignatures(ctx context.Context, height int64) (map[string][]byte, error) { signaturesReq, err := proto.Marshal(&networktypes.QueryAttesterSignaturesRequest{Height: height}) if err != nil { return nil, fmt.Errorf("marshal attester signatures request: %w", err) @@ -420,12 +447,10 @@ func getAttesterSignatures(ctx context.Context, height int64) (map[string][]byte Data: signaturesReq, }) if err != nil { - env.Logger.Debug("AttesterSignatures query failed", "error", err) return make(map[string][]byte), nil } if result.Code != 0 { - env.Logger.Info("AttesterSignatures not found", "height", height, "code", result.Code) return make(map[string][]byte), nil } @@ -434,13 +459,18 @@ func getAttesterSignatures(ctx context.Context, height int64) (map[string][]byte return nil, fmt.Errorf("unmarshal attester signatures response: %w", err) } - // Convert to map format signatures := make(map[string][]byte) for _, sig := range signaturesResp.Signatures { signatures[sig.ValidatorAddress] = sig.Signature } - env.Logger.Info("Found AttesterSignatures", "height", height, "count", len(signatures)) - return signatures, nil } + +// GetCommitForHeightForTest is exported only for tests in this package. +func GetCommitForHeightForTest(ctx context.Context, e *Environment, height uint64) (*cmttypes.Commit, error) { + previousEnv := env + env = e + defer func() { env = previousEnv }() + return getCommitForHeight(ctx, height) +} diff --git a/pkg/rpc/core/commit_reconstruction_test.go b/pkg/rpc/core/commit_reconstruction_test.go new file mode 100644 index 00000000..1fb341ae --- /dev/null +++ b/pkg/rpc/core/commit_reconstruction_test.go @@ -0,0 +1,295 @@ +package core_test + +import ( + "bytes" + "context" + "sort" + "testing" + "time" + + abci "github.com/cometbft/cometbft/abci/types" + cmted25519 "github.com/cometbft/cometbft/crypto/ed25519" + cmtlog "github.com/cometbft/cometbft/libs/log" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttypes "github.com/cometbft/cometbft/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + ds "github.com/ipfs/go-datastore" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + networktypes "github.com/evstack/ev-abci/modules/network/types" + "github.com/evstack/ev-abci/pkg/adapter" + "github.com/evstack/ev-abci/pkg/rpc/core" + execstore "github.com/evstack/ev-abci/pkg/store" +) + +// mockABCI is a minimal mock for the servertypes.ABCI interface. +type mockABCI struct { + mock.Mock +} + +func (m *mockABCI) Info(req *abci.RequestInfo) (*abci.ResponseInfo, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseInfo) + return r, args.Error(1) +} + +func (m *mockABCI) Query(ctx context.Context, req *abci.RequestQuery) (*abci.ResponseQuery, error) { + args := m.Called(ctx, req) + r, _ := args.Get(0).(*abci.ResponseQuery) + return r, args.Error(1) +} + +func (m *mockABCI) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseCheckTx) + return r, args.Error(1) +} + +func (m *mockABCI) InitChain(req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseInitChain) + return r, args.Error(1) +} + +func (m *mockABCI) PrepareProposal(req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponsePrepareProposal) + return r, args.Error(1) +} + +func (m *mockABCI) ProcessProposal(req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseProcessProposal) + return r, args.Error(1) +} + +func (m *mockABCI) FinalizeBlock(req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseFinalizeBlock) + return r, args.Error(1) +} + +func (m *mockABCI) ExtendVote(ctx context.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) { + args := m.Called(ctx, req) + r, _ := args.Get(0).(*abci.ResponseExtendVote) + return r, args.Error(1) +} + +func (m *mockABCI) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseVerifyVoteExtension) + return r, args.Error(1) +} + +func (m *mockABCI) Commit() (*abci.ResponseCommit, error) { + args := m.Called() + r, _ := args.Get(0).(*abci.ResponseCommit) + return r, args.Error(1) +} + +func (m *mockABCI) ListSnapshots(req *abci.RequestListSnapshots) (*abci.ResponseListSnapshots, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseListSnapshots) + return r, args.Error(1) +} + +func (m *mockABCI) OfferSnapshot(req *abci.RequestOfferSnapshot) (*abci.ResponseOfferSnapshot, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseOfferSnapshot) + return r, args.Error(1) +} + +func (m *mockABCI) LoadSnapshotChunk(req *abci.RequestLoadSnapshotChunk) (*abci.ResponseLoadSnapshotChunk, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseLoadSnapshotChunk) + return r, args.Error(1) +} + +func (m *mockABCI) ApplySnapshotChunk(req *abci.RequestApplySnapshotChunk) (*abci.ResponseApplySnapshotChunk, error) { + args := m.Called(req) + r, _ := args.Get(0).(*abci.ResponseApplySnapshotChunk) + return r, args.Error(1) +} + +// buildEnv sets up a test Environment and returns it along with the canonical +// ValidatorSet and BlockID used for verification. +func buildEnv(t *testing.T, height uint64, keys []cmted25519.PrivKey, signers []int, chainID string) (*core.Environment, *cmttypes.ValidatorSet, cmttypes.BlockID) { + t.Helper() + + blockIDHash := bytes.Repeat([]byte{0xab}, 32) + + // Build canonical ValidatorSet (NewValidatorSet sorts by address internally). + vals := make([]*cmttypes.Validator, len(keys)) + for i, k := range keys { + vals[i] = cmttypes.NewValidator(k.PubKey(), 1) + } + valSet := cmttypes.NewValidatorSet(vals) + + // Map raw 20-byte address → private key for signing. + privByAddr := map[string]cmted25519.PrivKey{} + for _, priv := range keys { + privByAddr[string(priv.PubKey().Address())] = priv + } + + // Build ordered list following valSet order (already sorted by address). + consAddrs := make([]string, len(valSet.Validators)) + pubkeyAnys := make([]*codectypes.Any, len(valSet.Validators)) + for i, v := range valSet.Validators { + sdkPk, err := cryptocodec.FromCmtPubKeyInterface(v.PubKey) + require.NoError(t, err) + consAddrs[i] = sdk.ConsAddress(v.Address).String() + any, err := codectypes.NewAnyWithValue(sdkPk) + require.NoError(t, err) + pubkeyAnys[i] = any + } + + // Sign for each selected signer index (indices into valSet.Validators). + signatures := map[string][]byte{} + for _, i := range signers { + priv := privByAddr[string(valSet.Validators[i].Address)] + v := cmtproto.Vote{ + Type: cmtproto.PrecommitType, + Height: int64(height), //nolint:gosec + Round: 0, + BlockID: cmtproto.BlockID{Hash: blockIDHash, PartSetHeader: cmtproto.PartSetHeader{}}, + Timestamp: time.Date(2026, 4, 22, 12, 0, 0, 0, time.UTC), + ValidatorAddress: valSet.Validators[i].Address, + ValidatorIndex: int32(i), //nolint:gosec + } + sb := cmttypes.VoteSignBytes(chainID, &v) + sig, err := priv.Sign(sb) + require.NoError(t, err) + v.Signature = sig + bz, err := proto.Marshal(&v) + require.NoError(t, err) + signatures[consAddrs[i]] = bz + } + + // Prepare AttesterSet query response (index == position in sorted valSet). + setEntries := make([]networktypes.AttesterSetEntry, 0, len(valSet.Validators)) + for i := range valSet.Validators { + setEntries = append(setEntries, networktypes.AttesterSetEntry{ + Authority: sdk.AccAddress(valSet.Validators[i].Address).String(), + ConsensusAddress: consAddrs[i], + Index: uint32(i), //nolint:gosec + Pubkey: pubkeyAnys[i], + }) + } + setRespBz, err := proto.Marshal(&networktypes.QueryAttesterSetResponse{Entries: setEntries}) + require.NoError(t, err) + + // Prepare AttesterSignatures query response. + sigList := make([]*networktypes.AttesterSignature, 0, len(signatures)) + for consAddr, sig := range signatures { + sigList = append(sigList, &networktypes.AttesterSignature{ + ValidatorAddress: consAddr, + Signature: sig, + }) + } + sigRespBz, err := proto.Marshal(&networktypes.QueryAttesterSignaturesResponse{Signatures: sigList}) + require.NoError(t, err) + + mApp := new(mockABCI) + mApp.On("Query", mock.Anything, mock.MatchedBy(func(r *abci.RequestQuery) bool { + return r.Path == "/evabci.network.v1.Query/AttesterSet" + })).Return(&abci.ResponseQuery{Code: 0, Value: setRespBz}, nil) + mApp.On("Query", mock.Anything, mock.MatchedBy(func(r *abci.RequestQuery) bool { + return r.Path == "/evabci.network.v1.Query/AttesterSignatures" + })).Return(&abci.ResponseQuery{Code: 0, Value: sigRespBz}, nil) + + // Use real store with in-memory backend, save the block ID. + dsStore := ds.NewMapDatastore() + abciExecStore := execstore.NewExecABCIStore(dsStore) + blockID := cmttypes.BlockID{Hash: blockIDHash, PartSetHeader: cmttypes.PartSetHeader{}} + err = abciExecStore.SaveBlockID(context.Background(), height, &blockID) + require.NoError(t, err) + + env := &core.Environment{ + Adapter: &adapter.Adapter{ + App: mApp, + Store: abciExecStore, + }, + AttesterMode: true, + Logger: cmtlog.NewNopLogger(), + } + + return env, valSet, blockID +} + +func TestGetCommitForHeight_QuorumMet_SortedWithAbsent(t *testing.T) { + chainID := "test-chain" + keys := []cmted25519.PrivKey{ + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + } + signers := []int{0, 1, 2} // 3 of 4 — quorum + env, valSet, blockID := buildEnv(t, 100, keys, signers, chainID) + + commit, err := core.GetCommitForHeightForTest(context.Background(), env, 100) + require.NoError(t, err) + require.Equal(t, int64(100), commit.Height) + require.Equal(t, int32(0), commit.Round) + require.Equal(t, blockID, commit.BlockID) + require.Len(t, commit.Signatures, 4) + + // Committed validator addresses must be in ascending order. + var addrs [][]byte + for _, cs := range commit.Signatures { + if cs.BlockIDFlag == cmttypes.BlockIDFlagCommit { + addrs = append(addrs, cs.ValidatorAddress) + } + } + require.True(t, sort.SliceIsSorted(addrs, func(i, j int) bool { + return bytes.Compare(addrs[i], addrs[j]) < 0 + })) + + var commitCnt, absentCnt int + for _, cs := range commit.Signatures { + switch cs.BlockIDFlag { + case cmttypes.BlockIDFlagCommit: + commitCnt++ + case cmttypes.BlockIDFlagAbsent: + absentCnt++ + } + } + require.Equal(t, 3, commitCnt) + require.Equal(t, 1, absentCnt) + + // 07-tendermint light client must accept this commit. + require.NoError(t, valSet.VerifyCommitLight(chainID, blockID, 100, commit)) +} + +func TestGetCommitForHeight_NoQuorum_Error(t *testing.T) { + chainID := "test-chain" + keys := []cmted25519.PrivKey{ + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + } + signers := []int{0, 1} // 2 of 4 — not > 2/3 + env, _, _ := buildEnv(t, 200, keys, signers, chainID) + + _, err := core.GetCommitForHeightForTest(context.Background(), env, 200) + require.Error(t, err) + require.Contains(t, err.Error(), "not yet attested") +} + +func TestGetCommitForHeight_AllSigned(t *testing.T) { + chainID := "test-chain" + keys := []cmted25519.PrivKey{ + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + cmted25519.GenPrivKey(), cmted25519.GenPrivKey(), + } + env, valSet, blockID := buildEnv(t, 300, keys, []int{0, 1, 2, 3}, chainID) + + commit, err := core.GetCommitForHeightForTest(context.Background(), env, 300) + require.NoError(t, err) + require.Len(t, commit.Signatures, 4) + for _, cs := range commit.Signatures { + require.Equal(t, cmttypes.BlockIDFlagCommit, cs.BlockIDFlag) + } + require.NoError(t, valSet.VerifyCommitLight(chainID, blockID, 300, commit)) +} diff --git a/pkg/rpc/core/consensus.go b/pkg/rpc/core/consensus.go index ff0ee28a..3f380af0 100644 --- a/pkg/rpc/core/consensus.go +++ b/pkg/rpc/core/consensus.go @@ -1,20 +1,12 @@ package core import ( - "context" "fmt" - abci "github.com/cometbft/cometbft/abci/types" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" coretypes "github.com/cometbft/cometbft/rpc/core/types" rpctypes "github.com/cometbft/cometbft/rpc/jsonrpc/types" cmttypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/crypto/codec" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/gogoproto/proto" - - networktypes "github.com/evstack/ev-abci/modules/network/types" ) // Validators gets the validator set at the given block height. @@ -30,29 +22,18 @@ func Validators(ctx *rpctypes.Context, heightPtr *int64, _, _ *int) (*coretypes. return nil, fmt.Errorf("failed to normalize height: %w", err) } - // In attester mode, return active attesters instead of genesis validator + // In attester mode, return the full fixed attester set. /commit uses the + // same set and marks missing signatures as absent, so the two endpoints must + // stay aligned for light-client verification. if env.AttesterMode { - env.Logger.Info("Validators endpoint in attester mode - returning active attesters", "height", height) - - // Get attester signatures for this height to determine active attesters - signatures, err := getAttesterSignatures(ctx.Context(), int64(height)) + env.Logger.Info("Validators endpoint in attester mode - returning full attester set", "height", height) + entries, err := getAttesterSet(ctx.Context()) if err != nil { - env.Logger.Error("failed to get attester signatures", "height", height, "error", err) - // Fallback to genesis validator if no attester signatures available - return getGenesisValidatorSet(height) - } - - // If no attester signatures for this height, fallback to genesis validator - if len(signatures) == 0 { - env.Logger.Info("no attester signatures found for height, using genesis validator", "height", height) - return getGenesisValidatorSet(height) + return nil, fmt.Errorf("get attester set: %w", err) } - - // Convert attester signatures to validator set - validators, err := buildValidatorSetFromAttesters(signatures, height) + validators, err := buildValidatorSetFromAttesterSet(entries) if err != nil { - env.Logger.Error("failed to build validator set from attesters", "error", err) - return getGenesisValidatorSet(height) + return nil, fmt.Errorf("build validator set from attesters: %w", err) } return &coretypes.ResultValidators{ @@ -95,6 +76,27 @@ func getGenesisValidatorSet(height uint64) (*coretypes.ResultValidators, error) }, nil } +func buildValidatorSetFromAttesterSet(entries []attesterSetEntry) ([]*cmttypes.Validator, error) { + if len(entries) == 0 { + return nil, fmt.Errorf("no attesters found") + } + + validators := make([]*cmttypes.Validator, 0, len(entries)) + for _, e := range entries { + cmtPubKey, err := codec.ToCmtPubKeyInterface(e.Pubkey) + if err != nil { + return nil, fmt.Errorf("convert pubkey for %s: %w", e.ConsensusAddress, err) + } + validators = append(validators, &cmttypes.Validator{ + Address: e.ValidatorAddress, + PubKey: cmtPubKey, + VotingPower: 1, + ProposerPriority: 0, + }) + } + return validators, nil +} + // DumpConsensusState dumps consensus state. // UNSTABLE // More: https://docs.cometbft.com/v0.37/rpc/#/Info/dump_consensus_state @@ -147,109 +149,3 @@ func ConsensusParams(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.Result }, }, nil } - -// buildValidatorSetFromAttesters builds a CometBFT validator set from attester signatures -// using stored attester information including public keys -func buildValidatorSetFromAttesters(signatures map[string][]byte, height uint64) ([]*cmttypes.Validator, error) { - ctx := context.Background() - validators := make([]*cmttypes.Validator, 0, len(signatures)) - - for validatorAddr, signature := range signatures { - // Parse the signature bytes (they should be marshaled cmtproto.Vote) - var vote cmtproto.Vote - if err := proto.Unmarshal(signature, &vote); err != nil { - env.Logger.Error("failed to unmarshal attester vote", - "validator", validatorAddr, "error", err) - continue - } - - // Use the validator address from the vote for the consensus address - consensusAddr := cmttypes.Address(vote.ValidatorAddress) - if len(vote.ValidatorAddress) != 20 { - // Fallback: try to derive from the bech32 address - valAddrBytes, err := sdk.ValAddressFromBech32(validatorAddr) - if err != nil { - env.Logger.Error("failed to decode validator address", - "validator", validatorAddr, "error", err) - continue - } - // Use first 20 bytes as consensus address - consensusAddr = cmttypes.Address(valAddrBytes[:20]) - } - - // Query the network module for attester information via ABCI - attesterInfo, err := getAttesterInfoByAddress(ctx, validatorAddr) - if err != nil { - env.Logger.Error("failed to get attester info", - "validator", validatorAddr, "error", err) - continue - } - - // Unpack the Any type to get the actual public key using network module codec - var actualPubKey cryptotypes.PubKey - if err := networktypes.ModuleCdc.InterfaceRegistry().UnpackAny(attesterInfo.Pubkey, &actualPubKey); err != nil { - env.Logger.Error("failed to unpack public key from Any type", - "validator", validatorAddr, "error", err) - continue - } - - // Convert Cosmos SDK PubKey to CometBFT PubKey using standard codec - cmtPubKey, err := codec.ToCmtPubKeyInterface(actualPubKey) - if err != nil { - env.Logger.Error("failed to convert public key to CometBFT format", - "validator", validatorAddr, "error", err) - continue - } - - env.Logger.Info("creating validator entry for attester", - "validator", validatorAddr, "address", consensusAddr.String()) - - validators = append(validators, &cmttypes.Validator{ - Address: consensusAddr, - PubKey: cmtPubKey, - VotingPower: 1, // Set uniform voting power for attesters - ProposerPriority: 0, // Set to 0 for all attesters - }) - } - - if len(validators) == 0 { - return nil, fmt.Errorf("no valid attester validators found") - } - - env.Logger.Info("Built validator set from attesters", - "count", len(validators), "height", height) - - return validators, nil -} - -// getAttesterInfoByAddress queries the network module for attester information via ABCI -func getAttesterInfoByAddress(ctx context.Context, validatorAddr string) (*networktypes.AttesterInfo, error) { - // Create properly marshaled query request - queryReq := &networktypes.QueryAttesterInfoRequest{ - ValidatorAddress: validatorAddr, - } - - queryReqBytes, err := proto.Marshal(queryReq) - if err != nil { - return nil, fmt.Errorf("marshal query request: %w", err) - } - - result, err := env.Adapter.App.Query(ctx, &abci.RequestQuery{ - Path: "/evabci.network.v1.Query/AttesterInfo", - Data: queryReqBytes, // Properly marshaled protobuf request - }) - if err != nil { - return nil, fmt.Errorf("query attester info: %w", err) - } - - if result.Code != 0 { - return nil, fmt.Errorf("attester info not found: code %d, log: %s", result.Code, result.Log) - } - - var queryResp networktypes.QueryAttesterInfoResponse - if err := proto.Unmarshal(result.Value, &queryResp); err != nil { - return nil, fmt.Errorf("unmarshal attester info response: %w", err) - } - - return queryResp.AttesterInfo, nil -} diff --git a/pkg/rpc/core/consensus_test.go b/pkg/rpc/core/consensus_test.go index aa0a9599..3c61adae 100644 --- a/pkg/rpc/core/consensus_test.go +++ b/pkg/rpc/core/consensus_test.go @@ -6,13 +6,18 @@ import ( "testing" "time" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/ed25519" cmtlog "github.com/cometbft/cometbft/libs/log" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" rpctypes "github.com/cometbft/cometbft/rpc/jsonrpc/types" cmtstate "github.com/cometbft/cometbft/state" cmttypes "github.com/cometbft/cometbft/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/gogoproto/proto" ds "github.com/ipfs/go-datastore" testifyassert "github.com/stretchr/testify/assert" testifymock "github.com/stretchr/testify/mock" @@ -20,6 +25,7 @@ import ( rollkitmocks "github.com/evstack/ev-node/test/mocks" + networktypes "github.com/evstack/ev-abci/modules/network/types" "github.com/evstack/ev-abci/pkg/adapter" execstore "github.com/evstack/ev-abci/pkg/store" ) @@ -222,6 +228,106 @@ func TestValidators(t *testing.T) { }) } +func TestValidatorsAttesterModeReturnsFullAttesterSet(t *testing.T) { + chainID := "test-chain" + height := int64(100) + privs := []ed25519.PrivKey{ + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + } + + setEntries := make([]networktypes.AttesterSetEntry, 0, len(privs)) + attesterInfoByAddr := make(map[string]*networktypes.AttesterInfo) + for i, priv := range privs { + pub := priv.PubKey() + sdkPk, err := cryptocodec.FromCmtPubKeyInterface(pub) + require.NoError(t, err) + any, err := codectypes.NewAnyWithValue(sdkPk) + require.NoError(t, err) + consAddr := sdk.ConsAddress(pub.Address()).String() + setEntries = append(setEntries, networktypes.AttesterSetEntry{ + Authority: sdk.AccAddress(pub.Address()).String(), + ConsensusAddress: consAddr, + Index: uint32(i), //nolint:gosec + Pubkey: any, + }) + attesterInfoByAddr[consAddr] = &networktypes.AttesterInfo{ + Authority: sdk.AccAddress(pub.Address()).String(), + Pubkey: any, + ConsensusAddress: consAddr, + } + } + + setRespBz, err := proto.Marshal(&networktypes.QueryAttesterSetResponse{Entries: setEntries}) + require.NoError(t, err) + + signatures := make([]*networktypes.AttesterSignature, 0, 3) + blockID := cmtproto.BlockID{Hash: make([]byte, 32), PartSetHeader: cmtproto.PartSetHeader{}} + for i, priv := range privs[:3] { + vote := cmtproto.Vote{ + Type: cmtproto.PrecommitType, + Height: height, + Round: 0, + BlockID: blockID, + Timestamp: time.Date(2026, 4, 22, 12, 0, 0, 0, time.UTC), + ValidatorAddress: priv.PubKey().Address(), + ValidatorIndex: int32(i), //nolint:gosec + } + sig, err := priv.Sign(cmttypes.VoteSignBytes(chainID, &vote)) + require.NoError(t, err) + vote.Signature = sig + voteBz, err := proto.Marshal(&vote) + require.NoError(t, err) + signatures = append(signatures, &networktypes.AttesterSignature{ + ValidatorAddress: setEntries[i].ConsensusAddress, + Signature: voteBz, + }) + } + sigRespBz, err := proto.Marshal(&networktypes.QueryAttesterSignaturesResponse{Signatures: signatures}) + require.NoError(t, err) + + mApp := new(MockApp) + mApp.On("Query", testifymock.Anything, testifymock.MatchedBy(func(r *abci.RequestQuery) bool { + return r.Path == "/evabci.network.v1.Query/AttesterSet" + })).Return(&abci.ResponseQuery{Code: 0, Value: setRespBz}, nil) + mApp.On("Query", testifymock.Anything, testifymock.MatchedBy(func(r *abci.RequestQuery) bool { + return r.Path == "/evabci.network.v1.Query/AttesterSignatures" + })).Return(&abci.ResponseQuery{Code: 0, Value: sigRespBz}, nil).Maybe() + for consAddr, info := range attesterInfoByAddr { + infoRespBz, err := proto.Marshal(&networktypes.QueryAttesterInfoResponse{AttesterInfo: info}) + require.NoError(t, err) + consAddr := consAddr + mApp.On("Query", testifymock.Anything, testifymock.MatchedBy(func(r *abci.RequestQuery) bool { + if r.Path != "/evabci.network.v1.Query/AttesterInfo" { + return false + } + var req networktypes.QueryAttesterInfoRequest + if err := proto.Unmarshal(r.Data, &req); err != nil { + return false + } + return req.ValidatorAddress == consAddr + })).Return(&abci.ResponseQuery{Code: 0, Value: infoRespBz}, nil).Maybe() + } + + env = &Environment{ + Adapter: &adapter.Adapter{App: mApp}, + AttesterMode: true, + Logger: cmtlog.NewNopLogger(), + } + + result, err := Validators(&rpctypes.Context{}, &height, nil, nil) + require.NoError(t, err) + require.Len(t, result.Validators, 4) + require.Equal(t, 4, result.Count) + require.Equal(t, 4, result.Total) + for i, validator := range result.Validators { + require.Equal(t, privs[i].PubKey().Address(), validator.Address) + require.Equal(t, int64(1), validator.VotingPower) + } +} + func TestDumpConsensusState(t *testing.T) { assert := testifyassert.New(t) require := require.New(t)