Skip to content

Commit 0b7245d

Browse files
authored
Query messages that have reached consensus (#17)
1 parent 1dc9f80 commit 0b7245d

File tree

6 files changed

+1313
-101
lines changed

6 files changed

+1313
-101
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
**/*.pb.go linguist-generated=true
2+
**/mocks/*.go linguist-generated=true

client/paloma/client.go

+66-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package paloma
22

33
import (
44
"context"
5+
"fmt"
56
"strings"
67

78
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@@ -62,7 +63,7 @@ func queryMessagesForSigning[T consensus.Signable](
6263
if err != nil {
6364
return nil, err
6465
}
65-
var res []QueuedMessage[T]
66+
res := []QueuedMessage[T]{}
6667
for _, msg := range msgs.GetMessageToSign() {
6768
var m consensus.Signable
6869
err := anyunpacker.UnpackAny(msg.GetMsg(), &m)
@@ -84,6 +85,70 @@ func queryMessagesForSigning[T consensus.Signable](
8485
return res, nil
8586
}
8687

88+
type ValidatorSignature struct {
89+
ValAddress string
90+
Signature []byte
91+
}
92+
type ConsensusReachedMsg[T consensus.Signable] struct {
93+
ID string
94+
Nonce []byte
95+
Signatures []ValidatorSignature
96+
Msg T
97+
}
98+
99+
func QueryConsensusReachedMessages[T consensus.Signable](
100+
ctx context.Context,
101+
c Client,
102+
queueTypeName string,
103+
) ([]ConsensusReachedMsg[T], error) {
104+
return queryConsensusReachedMessages[T](ctx, c.GRPCClient, c.L.Codec.Marshaler, queueTypeName)
105+
}
106+
107+
func queryConsensusReachedMessages[T consensus.Signable](
108+
ctx context.Context,
109+
c grpc.ClientConn,
110+
anyunpacker codectypes.AnyUnpacker,
111+
queueTypeName string,
112+
) ([]ConsensusReachedMsg[T], error) {
113+
qc := consensus.NewQueryClient(c)
114+
consensusRes, err := qc.ConsensusReached(ctx, &consensus.QueryConsensusReachedRequest{
115+
QueueTypeName: queueTypeName,
116+
})
117+
118+
if err != nil {
119+
return nil, err
120+
}
121+
122+
var res []ConsensusReachedMsg[T]
123+
for _, rawMsg := range consensusRes.GetMessages() {
124+
var signable consensus.Signable
125+
err := anyunpacker.UnpackAny(rawMsg.GetMsg(), &signable)
126+
if err != nil {
127+
return nil, err
128+
}
129+
packedMsg, ok := signable.(T)
130+
if !ok {
131+
var expected T
132+
return nil, ErrIncorrectTypeSavedInMessage.Format(expected, signable)
133+
}
134+
135+
m := ConsensusReachedMsg[T]{
136+
ID: fmt.Sprintf("%d", rawMsg.GetId()),
137+
Nonce: rawMsg.Nonce,
138+
Msg: packedMsg,
139+
}
140+
for _, signData := range rawMsg.GetSignData() {
141+
m.Signatures = append(m.Signatures, ValidatorSignature{
142+
ValAddress: signData.GetValAddress(),
143+
Signature: signData.GetSignature(),
144+
})
145+
}
146+
res = append(res, m)
147+
}
148+
149+
return res, nil
150+
}
151+
87152
type BroadcastMessageSignatureIn struct {
88153
ID uint64
89154
QueueTypeName string

client/paloma/client_test.go

+146-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ import (
2020
"github.com/stretchr/testify/mock"
2121
"github.com/stretchr/testify/require"
2222

23+
"google.golang.org/grpc/status"
2324
"google.golang.org/grpc/test/bufconn"
2425

2526
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
2627
"github.com/cosmos/cosmos-sdk/types/module"
28+
"github.com/vizualni/whoops"
2729
"google.golang.org/grpc"
2830
)
2931

@@ -106,7 +108,8 @@ func TestQueryingMessagesForSigning(t *testing.T) {
106108
expectsAnyError bool
107109
}{
108110
{
109-
name: "called with correct arguments",
111+
name: "called with correct arguments",
112+
expRes: []QueuedMessage[*testdata.SimpleMessage]{},
110113
mcksrv: func(t *testing.T) *consensusmocks.QueryServer {
111114
srv := consensusmocks.NewQueryServer(t)
112115
srv.On("QueuedMessagesForSigning", mock.Anything, &consensus.QueryQueuedMessagesForSigningRequest{
@@ -498,3 +501,145 @@ func TestBroadcastingMessageSignatures(t *testing.T) {
498501
})
499502
}
500503
}
504+
505+
func TestQueryConsensusReached(t *testing.T) {
506+
codec := makeCodec()
507+
ctx := context.Background()
508+
509+
fakeErr := whoops.String("oh no")
510+
511+
for _, tt := range []struct {
512+
name string
513+
mcksrv func(t *testing.T) *consensusmocks.QueryServer
514+
expectedErr error
515+
expectedRes []ConsensusReachedMsg[*testdata.SimpleMessage]
516+
anyUnpacker codectypes.AnyUnpacker
517+
}{
518+
{
519+
name: "when there are no messages it returns empty slice",
520+
mcksrv: func(t *testing.T) *consensusmocks.QueryServer {
521+
srv := consensusmocks.NewQueryServer(t)
522+
srv.On("ConsensusReached", mock.Anything, &consensus.QueryConsensusReachedRequest{
523+
QueueTypeName: "queue-name",
524+
}).Once().Return(&consensus.QueryConsensusReachedResponse{}, nil)
525+
return srv
526+
},
527+
},
528+
{
529+
name: "when there are messages it returns them",
530+
mcksrv: func(t *testing.T) *consensusmocks.QueryServer {
531+
srv := consensusmocks.NewQueryServer(t)
532+
srv.On("ConsensusReached", mock.Anything, &consensus.QueryConsensusReachedRequest{
533+
QueueTypeName: "queue-name",
534+
}).Once().Return(&consensus.QueryConsensusReachedResponse{
535+
Messages: []*consensus.MessageApproved{
536+
{
537+
Nonce: []byte("abc"),
538+
Id: 123,
539+
Msg: whoops.Must(codectypes.NewAnyWithValue(&testdata.SimpleMessage{
540+
Sender: "bob",
541+
})),
542+
SignData: []*consensus.MessageApprovedSignData{
543+
{
544+
ValAddress: "1",
545+
Signature: []byte("1"),
546+
},
547+
{
548+
ValAddress: "2",
549+
Signature: []byte("2"),
550+
},
551+
},
552+
},
553+
{
554+
Nonce: []byte("def"),
555+
Id: 456,
556+
Msg: whoops.Must(codectypes.NewAnyWithValue(&testdata.SimpleMessage{
557+
Sender: "alice",
558+
})),
559+
SignData: []*consensus.MessageApprovedSignData{
560+
{
561+
ValAddress: "1",
562+
Signature: []byte("11"),
563+
},
564+
{
565+
ValAddress: "2",
566+
Signature: []byte("22"),
567+
},
568+
},
569+
},
570+
},
571+
}, nil)
572+
return srv
573+
},
574+
expectedRes: []ConsensusReachedMsg[*testdata.SimpleMessage]{
575+
{
576+
ID: "123",
577+
Nonce: []byte("abc"),
578+
Msg: &testdata.SimpleMessage{
579+
Sender: "bob",
580+
},
581+
Signatures: []ValidatorSignature{
582+
{
583+
ValAddress: "1",
584+
Signature: []byte("1"),
585+
},
586+
{
587+
ValAddress: "2",
588+
Signature: []byte("2"),
589+
},
590+
},
591+
},
592+
{
593+
ID: "456",
594+
Nonce: []byte("def"),
595+
Msg: &testdata.SimpleMessage{
596+
Sender: "alice",
597+
},
598+
Signatures: []ValidatorSignature{
599+
{
600+
ValAddress: "1",
601+
Signature: []byte("11"),
602+
},
603+
{
604+
ValAddress: "2",
605+
Signature: []byte("22"),
606+
},
607+
},
608+
},
609+
},
610+
},
611+
{
612+
name: "if there is an error it returns it",
613+
mcksrv: func(t *testing.T) *consensusmocks.QueryServer {
614+
srv := consensusmocks.NewQueryServer(t)
615+
srv.On("ConsensusReached", mock.Anything, &consensus.QueryConsensusReachedRequest{
616+
QueueTypeName: "queue-name",
617+
}).Once().Return(nil, fakeErr)
618+
return srv
619+
},
620+
expectedErr: fakeErr,
621+
},
622+
} {
623+
t.Run(tt.name, func(t *testing.T) {
624+
srv := tt.mcksrv(t)
625+
conn, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(queryServerDailer(t, srv)))
626+
require.NoError(t, err)
627+
628+
if tt.anyUnpacker == nil {
629+
tt.anyUnpacker = codec.Marshaler
630+
}
631+
632+
msgs, err := queryConsensusReachedMessages[*testdata.SimpleMessage](ctx, conn, tt.anyUnpacker, "queue-name")
633+
if serr := status.Convert(err); serr != nil {
634+
if tt.expectedErr != nil {
635+
require.Equal(t, serr.Message(), tt.expectedErr.Error())
636+
} else {
637+
require.NoError(t, err, "expected err %s, got err %s", tt.expectedErr, err)
638+
}
639+
} else {
640+
require.ErrorIs(t, err, tt.expectedErr)
641+
}
642+
require.Equal(t, tt.expectedRes, msgs)
643+
})
644+
}
645+
}

proto/paloma/consensus/query.proto

+26
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "gogoproto/gogo.proto";
55
import "google/api/annotations.proto";
66
import "cosmos/base/query/v1beta1/pagination.proto";
77
import "consensus/params.proto";
8+
import "consensus/consensus_queue.proto";
89
import "google/protobuf/any.proto";
910
// this line is used by starport scaffolding # 1
1011

@@ -21,6 +22,11 @@ service Query {
2122
option (google.api.http).get = "/volumefi/paloma/consensus/queued_messages_for_signing";
2223
}
2324

25+
// Queries a list of ConsensusReached items.
26+
rpc ConsensusReached(QueryConsensusReachedRequest) returns (QueryConsensusReachedResponse) {
27+
option (google.api.http).get = "/palomachain/paloma/consensus/consensus_reached/{queueTypeName}";
28+
}
29+
2430
// this line is used by starport scaffolding # 2
2531
}
2632

@@ -48,4 +54,24 @@ message MessageToSign {
4854
google.protobuf.Any msg = 3;
4955
}
5056

57+
message MessageApprovedSignData {
58+
string valAddress = 1;
59+
bytes signature = 2;
60+
}
61+
62+
message MessageApproved {
63+
bytes nonce = 1;
64+
uint64 id = 2;
65+
google.protobuf.Any msg = 3;
66+
repeated MessageApprovedSignData signData = 4;
67+
}
68+
69+
message QueryConsensusReachedRequest {
70+
string queueTypeName = 1;
71+
}
72+
73+
message QueryConsensusReachedResponse {
74+
repeated MessageApproved messages = 1;
75+
}
76+
5177
// this line is used by starport scaffolding # 3

types/paloma/x/consensus/types/mocks/QueryServer.go

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)