diff --git a/services/shhext/api.go b/services/shhext/api.go index abb4693c4..5434cf72f 100644 --- a/services/shhext/api.go +++ b/services/shhext/api.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -63,8 +64,12 @@ type MessagesRequest struct { Cursor string `json:"cursor"` // Topic is a regular Whisper topic. + // DEPRECATED Topic whisper.TopicType `json:"topic"` + // Topics is a list of Whisper topics. + Topics []whisper.TopicType `json:"topics"` + // SymKeyID is an ID of a symmetric key to authenticate to MailServer. // It's derived from MailServer password. // @@ -427,7 +432,7 @@ func makePayload(r MessagesRequest) []byte { // to binary.BigEndian.PutUint32(data[4:], r.To) // bloom - copy(data[8:], whisper.TopicToBloom(r.Topic)) + copy(data[8:], createBloomFilter(r)) // limit binary.BigEndian.PutUint32(data[8+whisper.BloomFilterSize:], r.Limit) @@ -441,3 +446,25 @@ func makePayload(r MessagesRequest) []byte { return append(data, cursorBytes...) } + +func createBloomFilter(r MessagesRequest) []byte { + if len(r.Topics) > 0 { + return topicsToBloom(r.Topics...) + } + + return whisper.TopicToBloom(r.Topic) +} + +func topicsToBloom(topics ...whisper.TopicType) []byte { + i := new(big.Int) + for _, topic := range topics { + bloom := whisper.TopicToBloom(topic) + i.Or(i, new(big.Int).SetBytes(bloom[:])) + } + + combined := make([]byte, whisper.BloomFilterSize) + data := i.Bytes() + copy(combined[whisper.BloomFilterSize-len(data):], data[:]) + + return combined +} diff --git a/services/shhext/api_test.go b/services/shhext/api_test.go index a10cac613..a1c3e5016 100644 --- a/services/shhext/api_test.go +++ b/services/shhext/api_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + whisper "github.com/status-im/whisper/whisperv6" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -52,3 +54,44 @@ func TestMessagesRequest_setDefaults(t *testing.T) { }) } } + +func TestTopicsToBloom(t *testing.T) { + t1 := stringToTopic("t1") + b1 := whisper.TopicToBloom(t1) + t2 := stringToTopic("t2") + b2 := whisper.TopicToBloom(t2) + t3 := stringToTopic("t3") + b3 := whisper.TopicToBloom(t3) + + reqBloom := topicsToBloom(t1) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b1)) + assert.False(t, whisper.BloomFilterMatch(reqBloom, b2)) + assert.False(t, whisper.BloomFilterMatch(reqBloom, b3)) + + reqBloom = topicsToBloom(t1, t2) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b1)) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b2)) + assert.False(t, whisper.BloomFilterMatch(reqBloom, b3)) + + reqBloom = topicsToBloom(t1, t2, t3) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b1)) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b2)) + assert.True(t, whisper.BloomFilterMatch(reqBloom, b3)) +} + +func TestCreateBloomFilter(t *testing.T) { + t1 := stringToTopic("t1") + t2 := stringToTopic("t2") + + req := MessagesRequest{Topic: t1} + bloom := createBloomFilter(req) + assert.Equal(t, topicsToBloom(t1), bloom) + + req = MessagesRequest{Topics: []whisper.TopicType{t1, t2}} + bloom = createBloomFilter(req) + assert.Equal(t, topicsToBloom(t1, t2), bloom) +} + +func stringToTopic(s string) whisper.TopicType { + return whisper.BytesToTopic([]byte(s)) +}