diff --git a/pkg/authn/authn.pb.go b/pkg/authn/authn.pb.go index c0de527b..11767aff 100644 --- a/pkg/authn/authn.pb.go +++ b/pkg/authn/authn.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v4.25.3 +// protoc-gen-go v1.33.0 +// protoc v4.24.4 // source: authn.proto package authn diff --git a/pkg/identity/api/v1/identity_service.go b/pkg/identity/api/v1/identity_service.go index 7f36b31d..18d30c77 100644 --- a/pkg/identity/api/v1/identity_service.go +++ b/pkg/identity/api/v1/identity_service.go @@ -7,8 +7,8 @@ import ( "github.com/xmtp/xmtp-node-go/pkg/mlsvalidate" api "github.com/xmtp/xmtp-node-go/pkg/proto/identity/api/v1" "go.uber.org/zap" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + // "google.golang.org/grpc/codes" + // "google.golang.org/grpc/status" ) type Service struct { @@ -97,5 +97,6 @@ func (s *Service) GetInboxIds(ctx context.Context, req *api.GetInboxIdsRequest) for the address where revocation_sequence_id is lower or NULL 2. Return the value of the 'inbox_id' column */ - return nil, status.Errorf(codes.Unimplemented, "unimplemented") + + return s.store.GetInboxIds(ctx, req) } diff --git a/pkg/mls/store/models.go b/pkg/mls/store/models.go index 47d7145b..75e9ff27 100644 --- a/pkg/mls/store/models.go +++ b/pkg/mls/store/models.go @@ -24,6 +24,15 @@ type InboxLogEntry struct { IdentityUpdateProto []byte } +type AddressLogEntry struct { + bun.BaseModel `bun:"table:address_log"` + + Address string `bun:",notnull"` + InboxId string `bun:",notnull"` + AssociationSequenceId *uint64 `bun:","` + RevocationSequenceId *uint64 `bun:","` +} + type Installation struct { bun.BaseModel `bun:"table:installations"` diff --git a/pkg/mls/store/store.go b/pkg/mls/store/store.go index db2300da..d182401c 100644 --- a/pkg/mls/store/store.go +++ b/pkg/mls/store/store.go @@ -203,6 +203,60 @@ func (s *Store) GetInboxLogs(ctx context.Context, batched_req *identity.GetIdent }, nil } +type GroupedAddressLogEntry struct { + Address string + InboxId string + MaxAssociationSequenceId uint64 +} + +func (s *Store) GetInboxIds(ctx context.Context, req *identity.GetInboxIdsRequest) (*identity.GetInboxIdsResponse, error) { + + addresses := []string{} + for _, request := range req.Requests { + addresses = append(addresses, request.GetAddress()) + } + + db_log_entries := make([]*AddressLogEntry, 0) + + s.log.Info("Addresses", zap.Any("addresses", addresses)) + subquery := s.db.NewSelect(). + Column("address"). + ColumnExpr("MAX(association_sequence_id) AS max_association_sequence_id"). + Table("address_log"). + Where("address IN (?)", bun.In(addresses)). + Group("address") + + err := s.db.NewSelect(). + Column("a.address", "a.inbox_id", "a.association_sequence_id"). + TableExpr("address_log AS a"). + Join("INNER JOIN (?) AS b ON a.address = b.address AND a.association_sequence_id = b.max_association_sequence_id", subquery). + Scan(ctx, &db_log_entries) + + s.log.Info("GetInboxIds", zap.Any("db_log_entries", db_log_entries)) + + if err != nil { + return nil, err + } + + out := make([]*identity.GetInboxIdsResponse_Response, len(addresses)) + + for index, address := range addresses { + resp := identity.GetInboxIdsResponse_Response{} + resp.Address = address + + for _, log_entry := range db_log_entries { + if log_entry.Address == address { + resp.InboxId = &log_entry.InboxId + } + } + out[index] = &resp + } + + return &identity.GetInboxIdsResponse{ + Responses: out, + }, nil +} + // Creates the installation and last resort key package func (s *Store) CreateInstallation(ctx context.Context, installationId []byte, walletAddress string, credentialIdentity, keyPackage []byte, expiration uint64) error { createdAt := nowNs() diff --git a/pkg/mls/store/store_test.go b/pkg/mls/store/store_test.go index 0f74996e..15371925 100644 --- a/pkg/mls/store/store_test.go +++ b/pkg/mls/store/store_test.go @@ -657,3 +657,66 @@ func TestQueryWelcomeMessagesV1_Paginate(t *testing.T) { require.Equal(t, []byte("content7"), resp.Messages[0].GetV1().Data) require.Equal(t, []byte("content8"), resp.Messages[1].GetV1().Data) } + +func InsertAddressLog(store *Store, address string, inboxId string, associationSequenceId *uint64, revocationSequenceId *uint64) error { + + entry := AddressLogEntry{ + Address: address, + InboxId: inboxId, + AssociationSequenceId: associationSequenceId, + RevocationSequenceId: revocationSequenceId, + } + ctx := context.Background() + + _, err := store.db.NewInsert(). + Model(&entry). + Exec(ctx) + + return err +} + +func TestInboxIds(t *testing.T) { + store, cleanup := NewTestStore(t) + defer cleanup() + + seq, rev := uint64(1), uint64(5) + err := InsertAddressLog(store, "address", "inbox1", &seq, &rev) + require.NoError(t, err) + seq, rev = uint64(2), uint64(8) + err = InsertAddressLog(store, "address", "inbox1", &seq, &rev) + require.NoError(t, err) + seq, rev = uint64(3), uint64(9) + err = InsertAddressLog(store, "address", "inbox1", &seq, &rev) + require.NoError(t, err) + seq, rev = uint64(4), uint64(1) + err = InsertAddressLog(store, "address", "correct", &seq, &rev) + require.NoError(t, err) + + reqs := make([]*identity.GetInboxIdsRequest_Request, 0) + reqs = append(reqs, &identity.GetInboxIdsRequest_Request{ + Address: "address", + }) + req := &identity.GetInboxIdsRequest{ + Requests: reqs, + } + resp, _ := store.GetInboxIds(context.Background(), req) + t.Log(resp) + + require.Equal(t, "correct", *resp.Responses[0].InboxId) + + seq = uint64(5) + err = InsertAddressLog(store, "address", "correct_inbox2", &seq, nil) + require.NoError(t, err) + resp, _ = store.GetInboxIds(context.Background(), req) + require.Equal(t, "correct_inbox2", *resp.Responses[0].InboxId) + + reqs = append(reqs, &identity.GetInboxIdsRequest_Request{Address: "address2"}) + req = &identity.GetInboxIdsRequest{ + Requests: reqs, + } + seq, rev = uint64(8), uint64(2) + err = InsertAddressLog(store, "address2", "inbox2", &seq, &rev) + require.NoError(t, err) + resp, _ = store.GetInboxIds(context.Background(), req) + require.Equal(t, "inbox2", *resp.Responses[1].InboxId) +}