github.com/status-im/status-go@v1.1.0/services/shhext/api_nimbus.go (about) 1 //go:build nimbus 2 // +build nimbus 3 4 package shhext 5 6 import ( 7 "context" 8 9 "github.com/status-im/status-go/protocol/common" 10 11 "github.com/ethereum/go-ethereum/log" 12 13 "github.com/status-im/status-go/eth-node/types" 14 enstypes "github.com/status-im/status-go/eth-node/types/ens" 15 "github.com/status-im/status-go/protocol" 16 "github.com/status-im/status-go/protocol/encryption/multidevice" 17 "github.com/status-im/status-go/protocol/transport" 18 ) 19 20 // ----- 21 // PUBLIC API 22 // ----- 23 24 // NimbusPublicAPI extends whisper public API. 25 type NimbusPublicAPI struct { 26 service *NimbusService 27 publicAPI types.PublicWhisperAPI 28 log log.Logger 29 } 30 31 // NewPublicAPI returns instance of the public API. 32 func NewNimbusPublicAPI(s *NimbusService) *NimbusPublicAPI { 33 return &NimbusPublicAPI{ 34 service: s, 35 publicAPI: s.w.PublicWhisperAPI(), 36 log: log.New("package", "status-go/services/sshext.NimbusPublicAPI"), 37 } 38 } 39 40 // func (api *NimbusPublicAPI) getPeer(rawurl string) (*enode.Node, error) { 41 // if len(rawurl) == 0 { 42 // return mailservers.GetFirstConnected(api.service.server, api.service.peerStore) 43 // } 44 // return enode.ParseV4(rawurl) 45 // } 46 47 // // RetryConfig specifies configuration for retries with timeout and max amount of retries. 48 // type RetryConfig struct { 49 // BaseTimeout time.Duration 50 // // StepTimeout defines duration increase per each retry. 51 // StepTimeout time.Duration 52 // MaxRetries int 53 // } 54 55 // RequestMessagesSync repeats MessagesRequest using configuration in retry conf. 56 // func (api *NimbusPublicAPI) RequestMessagesSync(conf RetryConfig, r MessagesRequest) (MessagesResponse, error) { 57 // var resp MessagesResponse 58 59 // shh := api.service.w 60 // events := make(chan types.EnvelopeEvent, 10) 61 // var ( 62 // requestID types.HexBytes 63 // err error 64 // retries int 65 // ) 66 // for retries <= conf.MaxRetries { 67 // sub := shh.SubscribeEnvelopeEvents(events) 68 // r.Timeout = conf.BaseTimeout + conf.StepTimeout*time.Duration(retries) 69 // timeout := r.Timeout 70 // // FIXME this weird conversion is required because MessagesRequest expects seconds but defines time.Duration 71 // r.Timeout = time.Duration(int(r.Timeout.Seconds())) 72 // requestID, err = api.RequestMessages(context.Background(), r) 73 // if err != nil { 74 // sub.Unsubscribe() 75 // return resp, err 76 // } 77 // mailServerResp, err := waitForExpiredOrCompleted(types.BytesToHash(requestID), events, timeout) 78 // sub.Unsubscribe() 79 // if err == nil { 80 // resp.Cursor = hex.EncodeToString(mailServerResp.Cursor) 81 // resp.Error = mailServerResp.Error 82 // return resp, nil 83 // } 84 // retries++ 85 // api.log.Error("[RequestMessagesSync] failed", "err", err, "retries", retries) 86 // } 87 // return resp, fmt.Errorf("failed to request messages after %d retries", retries) 88 // } 89 90 // func waitForExpiredOrCompleted(requestID types.Hash, events chan types.EnvelopeEvent, timeout time.Duration) (*types.MailServerResponse, error) { 91 // expired := fmt.Errorf("request %x expired", requestID) 92 // after := time.NewTimer(timeout) 93 // defer after.Stop() 94 // for { 95 // var ev types.EnvelopeEvent 96 // select { 97 // case ev = <-events: 98 // case <-after.C: 99 // return nil, expired 100 // } 101 // if ev.Hash != requestID { 102 // continue 103 // } 104 // switch ev.Event { 105 // case types.EventMailServerRequestCompleted: 106 // data, ok := ev.Data.(*types.MailServerResponse) 107 // if ok { 108 // return data, nil 109 // } 110 // return nil, errors.New("invalid event data type") 111 // case types.EventMailServerRequestExpired: 112 // return nil, expired 113 // } 114 // } 115 // } 116 117 // // RequestMessages sends a request for historic messages to a MailServer. 118 // func (api *NimbusPublicAPI) RequestMessages(_ context.Context, r MessagesRequest) (types.HexBytes, error) { 119 // api.log.Info("RequestMessages", "request", r) 120 // shh := api.service.w 121 // now := api.service.w.GetCurrentTime() 122 // r.setDefaults(now) 123 124 // if r.From > r.To { 125 // return nil, fmt.Errorf("Query range is invalid: from > to (%d > %d)", r.From, r.To) 126 // } 127 128 // mailServerNode, err := api.getPeer(r.MailServerPeer) 129 // if err != nil { 130 // return nil, fmt.Errorf("%v: %v", ErrInvalidMailServerPeer, err) 131 // } 132 133 // var ( 134 // symKey []byte 135 // publicKey *ecdsa.PublicKey 136 // ) 137 138 // if r.SymKeyID != "" { 139 // symKey, err = shh.GetSymKey(r.SymKeyID) 140 // if err != nil { 141 // return nil, fmt.Errorf("%v: %v", ErrInvalidSymKeyID, err) 142 // } 143 // } else { 144 // publicKey = mailServerNode.Pubkey() 145 // } 146 147 // payload, err := makeMessagesRequestPayload(r) 148 // if err != nil { 149 // return nil, err 150 // } 151 152 // envelope, err := makeEnvelop( 153 // payload, 154 // symKey, 155 // publicKey, 156 // api.service.nodeID, 157 // shh.MinPow(), 158 // now, 159 // ) 160 // if err != nil { 161 // return nil, err 162 // } 163 // hash := envelope.Hash() 164 165 // if !r.Force { 166 // err = api.service.requestsRegistry.Register(hash, r.Topics) 167 // if err != nil { 168 // return nil, err 169 // } 170 // } 171 172 // if err := shh.RequestHistoricMessagesWithTimeout(mailServerNode.ID().Bytes(), envelope, r.Timeout*time.Second); err != nil { 173 // if !r.Force { 174 // api.service.requestsRegistry.Unregister(hash) 175 // } 176 // return nil, err 177 // } 178 179 // return hash[:], nil 180 // } 181 182 // // createSyncMailRequest creates SyncMailRequest. It uses a full bloom filter 183 // // if no topics are given. 184 // func createSyncMailRequest(r SyncMessagesRequest) (types.SyncMailRequest, error) { 185 // var bloom []byte 186 // if len(r.Topics) > 0 { 187 // bloom = topicsToBloom(r.Topics...) 188 // } else { 189 // bloom = types.MakeFullNodeBloom() 190 // } 191 192 // cursor, err := hex.DecodeString(r.Cursor) 193 // if err != nil { 194 // return types.SyncMailRequest{}, err 195 // } 196 197 // return types.SyncMailRequest{ 198 // Lower: r.From, 199 // Upper: r.To, 200 // Bloom: bloom, 201 // Limit: r.Limit, 202 // Cursor: cursor, 203 // }, nil 204 // } 205 206 // func createSyncMessagesResponse(r types.SyncEventResponse) SyncMessagesResponse { 207 // return SyncMessagesResponse{ 208 // Cursor: hex.EncodeToString(r.Cursor), 209 // Error: r.Error, 210 // } 211 // } 212 213 // // SyncMessages sends a request to a given MailServerPeer to sync historic messages. 214 // // MailServerPeers needs to be added as a trusted peer first. 215 // func (api *NimbusPublicAPI) SyncMessages(ctx context.Context, r SyncMessagesRequest) (SyncMessagesResponse, error) { 216 // log.Info("SyncMessages start", "request", r) 217 218 // var response SyncMessagesResponse 219 220 // mailServerEnode, err := enode.ParseV4(r.MailServerPeer) 221 // if err != nil { 222 // return response, fmt.Errorf("invalid MailServerPeer: %v", err) 223 // } 224 // mailServerID := mailServerEnode.ID().Bytes() 225 226 // request, err := createSyncMailRequest(r) 227 // if err != nil { 228 // return response, fmt.Errorf("failed to create a sync mail request: %v", err) 229 // } 230 231 // for { 232 // log.Info("Sending a request to sync messages", "request", request) 233 234 // resp, err := api.service.syncMessages(ctx, mailServerID, request) 235 // if err != nil { 236 // return response, err 237 // } 238 239 // log.Info("Syncing messages response", "error", resp.Error, "cursor", fmt.Sprintf("%#x", resp.Cursor)) 240 241 // if resp.Error != "" || len(resp.Cursor) == 0 || !r.FollowCursor { 242 // return createSyncMessagesResponse(resp), nil 243 // } 244 245 // request.Cursor = resp.Cursor 246 // } 247 // } 248 249 // ConfirmMessagesProcessedByID is a method to confirm that messages was consumed by 250 // the client side. 251 // TODO: this is broken now as it requires dedup ID while a message hash should be used. 252 func (api *NimbusPublicAPI) ConfirmMessagesProcessedByID(messageConfirmations []*Metadata) error { 253 confirmationCount := len(messageConfirmations) 254 dedupIDs := make([][]byte, confirmationCount) 255 encryptionIDs := make([][]byte, confirmationCount) 256 for i, confirmation := range messageConfirmations { 257 dedupIDs[i] = confirmation.DedupID 258 encryptionIDs[i] = confirmation.EncryptionID 259 } 260 return api.service.ConfirmMessagesProcessed(encryptionIDs) 261 } 262 263 // Post is used to send one-to-one for those who did not enabled device-to-device sync, 264 // in other words don't use PFS-enabled messages. Otherwise, SendDirectMessage is used. 265 // It's important to call NimbusPublicAPI.afterSend() so that the client receives a signal 266 // with confirmation that the message left the device. 267 func (api *NimbusPublicAPI) Post(ctx context.Context, newMessage types.NewMessage) (types.HexBytes, error) { 268 return api.publicAPI.Post(ctx, newMessage) 269 } 270 271 func (api *NimbusPublicAPI) Join(chat protocol.Chat) error { 272 return api.service.messenger.Join(chat) 273 } 274 275 func (api *NimbusPublicAPI) Leave(chat protocol.Chat) error { 276 return api.service.messenger.Leave(chat) 277 } 278 279 func (api *NimbusPublicAPI) LeaveGroupChat(ctx Context, chatID string) (*protocol.MessengerResponse, error) { 280 return api.service.messenger.LeaveGroupChat(ctx, chatID) 281 } 282 283 func (api *NimbusPublicAPI) CreateGroupChatWithMembers(ctx Context, name string, members []string) (*protocol.MessengerResponse, error) { 284 return api.service.messenger.CreateGroupChatWithMembers(ctx, name, members) 285 } 286 287 func (api *NimbusPublicAPI) AddMembersToGroupChat(ctx Context, chatID string, members []string) (*protocol.MessengerResponse, error) { 288 return api.service.messenger.AddMembersToGroupChat(ctx, chatID, members) 289 } 290 291 func (api *NimbusPublicAPI) RemoveMemberFromGroupChat(ctx Context, chatID string, member string) (*protocol.MessengerResponse, error) { 292 return api.service.messenger.RemoveMembersFromGroupChat(ctx, chatID, []string{member}) 293 } 294 295 func (api *NimbusPublicAPI) AddAdminsToGroupChat(ctx Context, chatID string, members []string) (*protocol.MessengerResponse, error) { 296 return api.service.messenger.AddAdminsToGroupChat(ctx, chatID, members) 297 } 298 299 func (api *NimbusPublicAPI) ConfirmJoiningGroup(ctx context.Context, chatID string) (*protocol.MessengerResponse, error) { 300 return api.service.messenger.ConfirmJoiningGroup(ctx, chatID) 301 } 302 303 // func (api *NimbusPublicAPI) requestMessagesUsingPayload(request db.HistoryRequest, peer, symkeyID string, payload []byte, force bool, timeout time.Duration, topics []types.TopicType) (hash types.Hash, err error) { 304 // shh := api.service.w 305 // now := api.service.w.GetCurrentTime() 306 307 // mailServerNode, err := api.getPeer(peer) 308 // if err != nil { 309 // return hash, fmt.Errorf("%v: %v", ErrInvalidMailServerPeer, err) 310 // } 311 312 // var ( 313 // symKey []byte 314 // publicKey *ecdsa.PublicKey 315 // ) 316 317 // if symkeyID != "" { 318 // symKey, err = shh.GetSymKey(symkeyID) 319 // if err != nil { 320 // return hash, fmt.Errorf("%v: %v", ErrInvalidSymKeyID, err) 321 // } 322 // } else { 323 // publicKey = mailServerNode.Pubkey() 324 // } 325 326 // envelope, err := makeEnvelop( 327 // payload, 328 // symKey, 329 // publicKey, 330 // api.service.nodeID, 331 // shh.MinPow(), 332 // now, 333 // ) 334 // if err != nil { 335 // return hash, err 336 // } 337 // hash = envelope.Hash() 338 339 // err = request.Replace(hash) 340 // if err != nil { 341 // return hash, err 342 // } 343 344 // if !force { 345 // err = api.service.requestsRegistry.Register(hash, topics) 346 // if err != nil { 347 // return hash, err 348 // } 349 // } 350 351 // if err := shh.RequestHistoricMessagesWithTimeout(mailServerNode.ID().Bytes(), envelope, timeout); err != nil { 352 // if !force { 353 // api.service.requestsRegistry.Unregister(hash) 354 // } 355 // return hash, err 356 // } 357 358 // return hash, nil 359 360 // } 361 362 // // InitiateHistoryRequests is a stateful API for initiating history request for each topic. 363 // // Caller of this method needs to define only two parameters per each TopicRequest: 364 // // - Topic 365 // // - Duration in nanoseconds. Will be used to determine starting time for history request. 366 // // After that status-go will guarantee that request for this topic and date will be performed. 367 // func (api *NimbusPublicAPI) InitiateHistoryRequests(parent context.Context, request InitiateHistoryRequestParams) (rst []types.HexBytes, err error) { 368 // tx := api.service.storage.NewTx() 369 // defer func() { 370 // if err == nil { 371 // err = tx.Commit() 372 // } 373 // }() 374 // ctx := NewContextFromService(parent, api.service, tx) 375 // requests, err := api.service.historyUpdates.CreateRequests(ctx, request.Requests) 376 // if err != nil { 377 // return nil, err 378 // } 379 // var ( 380 // payload []byte 381 // hash types.Hash 382 // ) 383 // for i := range requests { 384 // req := requests[i] 385 // options := CreateTopicOptionsFromRequest(req) 386 // bloom := options.ToBloomFilterOption() 387 // payload, err = bloom.ToMessagesRequestPayload() 388 // if err != nil { 389 // return rst, err 390 // } 391 // hash, err = api.requestMessagesUsingPayload(req, request.Peer, request.SymKeyID, payload, request.Force, request.Timeout, options.Topics()) 392 // if err != nil { 393 // return rst, err 394 // } 395 // rst = append(rst, hash.Bytes()) 396 // } 397 // return rst, err 398 // } 399 400 // // CompleteRequest client must mark request completed when all envelopes were processed. 401 // func (api *NimbusPublicAPI) CompleteRequest(parent context.Context, hex string) (err error) { 402 // tx := api.service.storage.NewTx() 403 // ctx := NewContextFromService(parent, api.service, tx) 404 // err = api.service.historyUpdates.UpdateFinishedRequest(ctx, types.HexToHash(hex)) 405 // if err == nil { 406 // return tx.Commit() 407 // } 408 // return err 409 // } 410 411 func (api *NimbusPublicAPI) LoadFilters(parent context.Context, chats []*transport.Filter) ([]*transport.Filter, error) { 412 return api.service.messenger.LoadFilters(chats) 413 } 414 415 func (api *NimbusPublicAPI) SaveChat(parent context.Context, chat *protocol.Chat) error { 416 api.log.Info("saving chat", "chat", chat) 417 return api.service.messenger.SaveChat(chat) 418 } 419 420 func (api *NimbusPublicAPI) Chats(parent context.Context) []*protocol.Chat { 421 return api.service.messenger.Chats() 422 } 423 424 func (api *NimbusPublicAPI) DeleteChat(parent context.Context, chatID string) error { 425 return api.service.messenger.DeleteChat(chatID) 426 } 427 428 func (api *NimbusPublicAPI) SaveContact(parent context.Context, contact *protocol.Contact) error { 429 return api.service.messenger.SaveContact(contact) 430 } 431 432 func (api *NimbusPublicAPI) BlockContact(parent context.Context, contact *protocol.Contact) (*protocol.MessengerResponse, error) { 433 api.log.Info("blocking contact", "contact", contact.ID) 434 return api.service.messenger.BlockContact(contact) 435 } 436 437 func (api *NimbusPublicAPI) Contacts(parent context.Context) []*protocol.Contact { 438 return api.service.messenger.Contacts() 439 } 440 441 func (api *NimbusPublicAPI) RemoveFilters(parent context.Context, chats []*transport.Filter) error { 442 return api.service.messenger.RemoveFilters(chats) 443 } 444 445 // EnableInstallation enables an installation for multi-device sync. 446 func (api *NimbusPublicAPI) EnableInstallation(installationID string) error { 447 return api.service.messenger.EnableInstallation(installationID) 448 } 449 450 // DisableInstallation disables an installation for multi-device sync. 451 func (api *NimbusPublicAPI) DisableInstallation(installationID string) error { 452 return api.service.messenger.DisableInstallation(installationID) 453 } 454 455 // GetOurInstallations returns all the installations available given an identity 456 func (api *NimbusPublicAPI) GetOurInstallations() []*multidevice.Installation { 457 return api.service.messenger.Installations() 458 } 459 460 // SetInstallationMetadata sets the metadata for our own installation 461 func (api *NimbusPublicAPI) SetInstallationMetadata(installationID string, data *multidevice.InstallationMetadata) error { 462 return api.service.messenger.SetInstallationMetadata(installationID, data) 463 } 464 465 // VerifyENSNames takes a list of ensdetails and returns whether they match the public key specified 466 func (api *NimbusPublicAPI) VerifyENSNames(details []enstypes.ENSDetails) (map[string]enstypes.ENSResponse, error) { 467 return api.service.messenger.VerifyENSNames(api.service.config.VerifyENSURL, ensContractAddress, details) 468 } 469 470 type ApplicationMessagesResponse struct { 471 Messages []*common.Message `json:"messages"` 472 Cursor string `json:"cursor"` 473 } 474 475 func (api *NimbusPublicAPI) ChatMessages(chatID, cursor string, limit int) (*ApplicationMessagesResponse, error) { 476 messages, cursor, err := api.service.messenger.MessageByChatID(chatID, cursor, limit) 477 if err != nil { 478 return nil, err 479 } 480 481 return &ApplicationMessagesResponse{ 482 Messages: messages, 483 Cursor: cursor, 484 }, nil 485 } 486 487 func (api *NimbusPublicAPI) DeleteMessage(id string) error { 488 return api.service.messenger.DeleteMessage(id) 489 } 490 491 func (api *NimbusPublicAPI) DeleteMessagesByChatID(id string) error { 492 return api.service.messenger.DeleteMessagesByChatID(id) 493 } 494 495 func (api *NimbusPublicAPI) MarkMessagesSeen(chatID string, ids []string) error { 496 return api.service.messenger.MarkMessagesSeen(chatID, ids) 497 } 498 499 func (api *NimbusPublicAPI) UpdateMessageOutgoingStatus(id, newOutgoingStatus string) error { 500 return api.service.messenger.UpdateMessageOutgoingStatus(id, newOutgoingStatus) 501 } 502 503 func (api *PublicAPI) StartMessenger() error { 504 return api.service.StartMessenger() 505 } 506 507 func (api *NimbusPublicAPI) SendChatMessage(ctx context.Context, message *common.Message) (*protocol.MessengerResponse, error) { 508 return api.service.messenger.SendChatMessage(ctx, message) 509 } 510 511 func (api *NimbusPublicAPI) SendPinMessage(ctx context.Context, message *common.PinMessage) (*protocol.MessengerResponse, error) { 512 return api.service.messenger.SendPinMessage(ctx, message) 513 } 514 515 func (api *NimbusPublicAPI) ReSendChatMessage(ctx context.Context, messageID string) error { 516 return api.service.messenger.ReSendChatMessage(ctx, messageID) 517 } 518 519 func (api *NimbusPublicAPI) RequestTransaction(ctx context.Context, chatID, value, contract, address string) (*protocol.MessengerResponse, error) { 520 return api.service.messenger.RequestTransaction(ctx, chatID, value, contract, address) 521 } 522 523 func (api *NimbusPublicAPI) RequestAddressForTransaction(ctx context.Context, chatID, from, value, contract string) (*protocol.MessengerResponse, error) { 524 return api.service.messenger.RequestAddressForTransaction(ctx, chatID, from, value, contract) 525 } 526 527 func (api *NimbusPublicAPI) DeclineRequestAddressForTransaction(ctx context.Context, messageID string) (*protocol.MessengerResponse, error) { 528 return api.service.messenger.DeclineRequestAddressForTransaction(ctx, messageID) 529 } 530 531 func (api *NimbusPublicAPI) DeclineRequestTransaction(ctx context.Context, messageID string) (*protocol.MessengerResponse, error) { 532 return api.service.messenger.DeclineRequestTransaction(ctx, messageID) 533 } 534 535 func (api *NimbusPublicAPI) AcceptRequestAddressForTransaction(ctx context.Context, messageID, address string) (*protocol.MessengerResponse, error) { 536 return api.service.messenger.AcceptRequestAddressForTransaction(ctx, messageID, address) 537 } 538 539 func (api *NimbusPublicAPI) SendTransaction(ctx context.Context, chatID, value, contract, transactionHash string, signature types.HexBytes) (*protocol.MessengerResponse, error) { 540 return api.service.messenger.SendTransaction(ctx, chatID, value, contract, transactionHash, signature) 541 } 542 543 func (api *NimbusPublicAPI) AcceptRequestTransaction(ctx context.Context, transactionHash, messageID string, signature types.HexBytes) (*protocol.MessengerResponse, error) { 544 return api.service.messenger.AcceptRequestTransaction(ctx, transactionHash, messageID, signature) 545 } 546 547 func (api *NimbusPublicAPI) SendContactUpdates(ctx context.Context, name, picture string) error { 548 return api.service.messenger.SendContactUpdates(ctx, name, picture) 549 } 550 551 func (api *NimbusPublicAPI) SendContactUpdate(ctx context.Context, contactID, name, picture string) (*protocol.MessengerResponse, error) { 552 return api.service.messenger.SendContactUpdate(ctx, contactID, name, picture) 553 } 554 555 func (api *NimbusPublicAPI) SendPairInstallation(ctx context.Context) (*protocol.MessengerResponse, error) { 556 return api.service.messenger.SendPairInstallation(ctx) 557 } 558 559 func (api *NimbusPublicAPI) SyncDevices(ctx context.Context, name, picture string) error { 560 return api.service.messenger.SyncDevices(ctx, name, picture) 561 } 562 563 // ----- 564 // HELPER 565 // ----- 566 567 // makeEnvelop makes an envelop for a historic messages request. 568 // Symmetric key is used to authenticate to MailServer. 569 // PK is the current node ID. 570 // func makeEnvelop( 571 // payload []byte, 572 // symKey []byte, 573 // publicKey *ecdsa.PublicKey, 574 // nodeID *ecdsa.PrivateKey, 575 // pow float64, 576 // now time.Time, 577 // ) (types.Envelope, error) { 578 // params := whisper.MessageParams{ 579 // PoW: pow, 580 // Payload: payload, 581 // WorkTime: defaultWorkTime, 582 // Src: nodeID, 583 // } 584 // // Either symKey or public key is required. 585 // // This condition is verified in `message.Wrap()` method. 586 // if len(symKey) > 0 { 587 // params.KeySym = symKey 588 // } else if publicKey != nil { 589 // params.Dst = publicKey 590 // } 591 // message, err := whisper.NewSentMessage(¶ms) 592 // if err != nil { 593 // return nil, err 594 // } 595 // envelope, err := message.Wrap(¶ms, now) 596 // if err != nil { 597 // return nil, err 598 // } 599 // return nimbusbridge.NewNimbusEnvelopeWrapper(envelope), nil 600 // } 601 602 // // makeMessagesRequestPayload makes a specific payload for MailServer 603 // // to request historic messages. 604 // func makeMessagesRequestPayload(r MessagesRequest) ([]byte, error) { 605 // cursor, err := hex.DecodeString(r.Cursor) 606 // if err != nil { 607 // return nil, fmt.Errorf("invalid cursor: %v", err) 608 // } 609 610 // if len(cursor) > 0 && len(cursor) != mailserver.CursorLength { 611 // return nil, fmt.Errorf("invalid cursor size: expected %d but got %d", mailserver.CursorLength, len(cursor)) 612 // } 613 614 // payload := mailserver.MessagesRequestPayload{ 615 // Lower: r.From, 616 // Upper: r.To, 617 // Bloom: createBloomFilter(r), 618 // Limit: r.Limit, 619 // Cursor: cursor, 620 // // Client must tell the MailServer if it supports batch responses. 621 // // This can be removed in the future. 622 // Batch: true, 623 // } 624 625 // return rlp.EncodeToBytes(payload) 626 // } 627 628 // func createBloomFilter(r MessagesRequest) []byte { 629 // if len(r.Topics) > 0 { 630 // return topicsToBloom(r.Topics...) 631 // } 632 633 // return types.TopicToBloom(r.Topic) 634 // } 635 636 // func topicsToBloom(topics ...types.TopicType) []byte { 637 // i := new(big.Int) 638 // for _, topic := range topics { 639 // bloom := types.TopicToBloom(topic) 640 // i.Or(i, new(big.Int).SetBytes(bloom[:])) 641 // } 642 643 // combined := make([]byte, types.BloomFilterSize) 644 // data := i.Bytes() 645 // copy(combined[types.BloomFilterSize-len(data):], data[:]) 646 647 // return combined 648 // }