whisper: clean up and integrate topics
This commit is contained in:
parent
7b501906db
commit
9a53390f49
@ -19,7 +19,7 @@ import (
|
||||
type Envelope struct {
|
||||
Expiry uint32 // Whisper protocol specifies int32, really should be int64
|
||||
TTL uint32 // ^^^^^^
|
||||
Topics [][]byte
|
||||
Topics []Topic
|
||||
Data []byte
|
||||
Nonce uint32
|
||||
|
||||
@ -28,7 +28,7 @@ type Envelope struct {
|
||||
|
||||
// NewEnvelope wraps a Whisper message with expiration and destination data
|
||||
// included into an envelope for network forwarding.
|
||||
func NewEnvelope(ttl time.Duration, topics [][]byte, msg *Message) *Envelope {
|
||||
func NewEnvelope(ttl time.Duration, topics []Topic, msg *Message) *Envelope {
|
||||
return &Envelope{
|
||||
Expiry: uint32(time.Now().Add(ttl).Unix()),
|
||||
TTL: uint32(ttl.Seconds()),
|
||||
|
@ -5,6 +5,6 @@ import "crypto/ecdsa"
|
||||
type Filter struct {
|
||||
To *ecdsa.PublicKey
|
||||
From *ecdsa.PublicKey
|
||||
Topics [][]byte
|
||||
Topics []Topic
|
||||
Fn func(*Message)
|
||||
}
|
||||
|
@ -75,8 +75,13 @@ func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Convert the user topic into whisper ones
|
||||
topics := make([]Topic, len(options.Topics))
|
||||
for i, topic := range options.Topics {
|
||||
topics[i] = NewTopic(topic)
|
||||
}
|
||||
// Wrap the processed message, seal it and return
|
||||
envelope := NewEnvelope(options.TTL, options.Topics, self)
|
||||
envelope := NewEnvelope(options.TTL, topics, self)
|
||||
envelope.Seal(pow)
|
||||
|
||||
return envelope, nil
|
||||
|
35
whisper/topic.go
Normal file
35
whisper/topic.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Contains the Whisper protocol Topic element. For formal details please see
|
||||
// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics.
|
||||
|
||||
package whisper
|
||||
|
||||
import "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
// Topic represents a cryptographically secure, probabilistic partial
|
||||
// classifications of a message, determined as the first (left) 4 bytes of the
|
||||
// SHA3 hash of some arbitrary data given by the original author of the message.
|
||||
type Topic [4]byte
|
||||
|
||||
// NewTopic creates a topic from the 4 byte prefix of the SHA3 hash of the data.
|
||||
func NewTopic(data []byte) Topic {
|
||||
prefix := [4]byte{}
|
||||
copy(prefix[:], crypto.Sha3(data)[:4])
|
||||
return Topic(prefix)
|
||||
}
|
||||
|
||||
// String converts a topic byte array to a string representation.
|
||||
func (self *Topic) String() string {
|
||||
return string(self[:])
|
||||
}
|
||||
|
||||
// TopicSet represents a hash set to check if a topic exists or not.
|
||||
type TopicSet map[string]struct{}
|
||||
|
||||
// NewTopicSet creates a topic hash set from a slice of topics.
|
||||
func NewTopicSet(topics []Topic) TopicSet {
|
||||
set := make(map[string]struct{})
|
||||
for _, topic := range topics {
|
||||
set[topic.String()] = struct{}{}
|
||||
}
|
||||
return TopicSet(set)
|
||||
}
|
38
whisper/topic_test.go
Normal file
38
whisper/topic_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package whisper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var topicCreationTests = []struct {
|
||||
data []byte
|
||||
hash [4]byte
|
||||
}{
|
||||
{hash: [4]byte{0xc5, 0xd2, 0x46, 0x01}, data: nil},
|
||||
{hash: [4]byte{0xc5, 0xd2, 0x46, 0x01}, data: []byte{}},
|
||||
{hash: [4]byte{0x8f, 0x9a, 0x2b, 0x7d}, data: []byte("test name")},
|
||||
}
|
||||
|
||||
func TestTopicCreation(t *testing.T) {
|
||||
for i, tt := range topicCreationTests {
|
||||
topic := NewTopic(tt.data)
|
||||
if bytes.Compare(topic[:], tt.hash[:]) != 0 {
|
||||
t.Errorf("test %d: hash mismatch: have %v, want %v.", i, topic, tt.hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopicSetCreation(t *testing.T) {
|
||||
topics := make([]Topic, len(topicCreationTests))
|
||||
for i, tt := range topicCreationTests {
|
||||
topics[i] = NewTopic(tt.data)
|
||||
}
|
||||
set := NewTopicSet(topics)
|
||||
for i, tt := range topicCreationTests {
|
||||
topic := NewTopic(tt.data)
|
||||
if _, ok := set[topic.String()]; !ok {
|
||||
t.Errorf("topic %d: not found in set", i)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package whisper
|
||||
|
||||
import "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
func hashTopic(topic []byte) []byte {
|
||||
return crypto.Sha3(topic)[:4]
|
||||
}
|
||||
|
||||
// NOTE this isn't DRY, but I don't want to iterate twice.
|
||||
|
||||
// Returns a formatted topics byte slice.
|
||||
// data: unformatted data (e.g., no hashes needed)
|
||||
func Topics(data [][]byte) [][]byte {
|
||||
d := make([][]byte, len(data))
|
||||
for i, byts := range data {
|
||||
d[i] = hashTopic(byts)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func TopicsFromString(data ...string) [][]byte {
|
||||
d := make([][]byte, len(data))
|
||||
for i, str := range data {
|
||||
d[i] = hashTopic([]byte(str))
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func bytesToMap(s [][]byte) map[string]struct{} {
|
||||
m := make(map[string]struct{})
|
||||
for _, topic := range s {
|
||||
m[string(topic)] = struct{}{}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
@ -119,7 +119,7 @@ func (self *Whisper) Watch(opts Filter) int {
|
||||
return self.filters.Install(filter.Generic{
|
||||
Str1: string(crypto.FromECDSAPub(opts.To)),
|
||||
Str2: string(crypto.FromECDSAPub(opts.From)),
|
||||
Data: bytesToMap(opts.Topics),
|
||||
Data: NewTopicSet(opts.Topics),
|
||||
Fn: func(data interface{}) {
|
||||
opts.Fn(data.(*Message))
|
||||
},
|
||||
@ -272,9 +272,9 @@ func (self *Whisper) Protocol() p2p.Protocol {
|
||||
return self.protocol
|
||||
}
|
||||
|
||||
func createFilter(message *Message, topics [][]byte, key *ecdsa.PrivateKey) filter.Filter {
|
||||
func createFilter(message *Message, topics []Topic, key *ecdsa.PrivateKey) filter.Filter {
|
||||
return filter.Generic{
|
||||
Str1: string(crypto.FromECDSAPub(&key.PublicKey)), Str2: string(crypto.FromECDSAPub(message.Recover())),
|
||||
Data: bytesToMap(topics),
|
||||
Data: NewTopicSet(topics),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user