Przeglądaj źródła

Merge pull request #690 from karalabe/whisper-cleanup

Whisper cleanup, part 1
Felix Lange 10 lat temu
rodzic
commit
faa2747809

+ 2 - 2
ui/qt/qwhisper/whisper.go

@@ -37,8 +37,8 @@ func (self *Whisper) Post(payload []string, to, from string, topics []string, pr
 	pk := crypto.ToECDSAPub(common.FromHex(from))
 	if key := self.Whisper.GetIdentity(pk); key != nil {
 		msg := whisper.NewMessage(data)
-		envelope, err := msg.Seal(time.Duration(priority*100000), whisper.Opts{
-			Ttl:    time.Duration(ttl) * time.Second,
+		envelope, err := msg.Wrap(time.Duration(priority*100000), whisper.Options{
+			TTL:    time.Duration(ttl) * time.Second,
 			To:     crypto.ToECDSAPub(common.FromHex(to)),
 			From:   key,
 			Topics: whisper.TopicsFromString(topics...),

+ 74 - 65
whisper/envelope.go

@@ -1,3 +1,6 @@
+// Contains the Whisper protocol Envelope element. For formal details please see
+// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes.
+
 package whisper
 
 import (
@@ -12,10 +15,8 @@ import (
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
-const (
-	DefaultPow = 50 * time.Millisecond
-)
-
+// Envelope represents a clear-text data packet to transmit through the Whisper
+// network. Its contents may or may not be encrypted and signed.
 type Envelope struct {
 	Expiry uint32 // Whisper protocol specifies int32, really should be int64
 	TTL    uint32 // ^^^^^^
@@ -26,96 +27,104 @@ type Envelope struct {
 	hash common.Hash
 }
 
-func (self *Envelope) Hash() common.Hash {
-	if (self.hash == common.Hash{}) {
-		enc, _ := rlp.EncodeToBytes(self)
-		self.hash = crypto.Sha3Hash(enc)
-	}
-	return self.hash
-}
-
-func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope {
-	exp := time.Now().Add(ttl)
+// 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 {
 	return &Envelope{
-		Expiry: uint32(exp.Unix()),
+		Expiry: uint32(time.Now().Add(ttl).Unix()),
 		TTL:    uint32(ttl.Seconds()),
 		Topics: topics,
-		Data:   data.Bytes(),
+		Data:   msg.bytes(),
 		Nonce:  0,
 	}
 }
 
+// Seal closes the envelope by spending the requested amount of time as a proof
+// of work on hashing the data.
 func (self *Envelope) Seal(pow time.Duration) {
-	self.proveWork(pow)
-}
-
-func (self *Envelope) Open(prv *ecdsa.PrivateKey) (msg *Message, err error) {
-	data := self.Data
-	var message Message
-	dataStart := 1
-	if data[0] > 0 {
-		if len(data) < 66 {
-			return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < 66")
-		}
-		dataStart = 66
-		message.Flags = data[0]
-		message.Signature = data[1:66]
-	}
-
-	payload := data[dataStart:]
-	if prv != nil {
-		message.Payload, err = crypto.Decrypt(prv, payload)
-		switch err {
-		case nil: // OK
-		case ecies.ErrInvalidPublicKey: // Payload isn't encrypted
-			message.Payload = payload
-			return &message, err
-		default:
-			return nil, fmt.Errorf("unable to open envelope. Decrypt failed: %v", err)
-		}
-	}
-
-	return &message, nil
-}
-
-func (self *Envelope) proveWork(dura time.Duration) {
-	var bestBit int
 	d := make([]byte, 64)
-	enc, _ := rlp.EncodeToBytes(self.withoutNonce())
-	copy(d[:32], enc)
+	copy(d[:32], self.rlpWithoutNonce())
 
-	then := time.Now().Add(dura).UnixNano()
-	for n := uint32(0); time.Now().UnixNano() < then; {
+	finish, bestBit := time.Now().Add(pow).UnixNano(), 0
+	for nonce := uint32(0); time.Now().UnixNano() < finish; {
 		for i := 0; i < 1024; i++ {
-			binary.BigEndian.PutUint32(d[60:], n)
+			binary.BigEndian.PutUint32(d[60:], nonce)
 
-			fbs := common.FirstBitSet(common.BigD(crypto.Sha3(d)))
-			if fbs > bestBit {
-				bestBit = fbs
-				self.Nonce = n
+			firstBit := common.FirstBitSet(common.BigD(crypto.Sha3(d)))
+			if firstBit > bestBit {
+				self.Nonce, bestBit = nonce, firstBit
 			}
-
-			n++
+			nonce++
 		}
 	}
 }
 
+// valid checks whether the claimed proof of work was indeed executed.
+// TODO: Is this really useful? Isn't this always true?
 func (self *Envelope) valid() bool {
 	d := make([]byte, 64)
-	enc, _ := rlp.EncodeToBytes(self.withoutNonce())
-	copy(d[:32], enc)
+	copy(d[:32], self.rlpWithoutNonce())
 	binary.BigEndian.PutUint32(d[60:], self.Nonce)
+
 	return common.FirstBitSet(common.BigD(crypto.Sha3(d))) > 0
 }
 
-func (self *Envelope) withoutNonce() interface{} {
-	return []interface{}{self.Expiry, self.TTL, self.Topics, self.Data}
+// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
+func (self *Envelope) rlpWithoutNonce() []byte {
+	enc, _ := rlp.EncodeToBytes([]interface{}{self.Expiry, self.TTL, self.Topics, self.Data})
+	return enc
+}
+
+// Open extracts the message contained within a potentially encrypted envelope.
+func (self *Envelope) Open(key *ecdsa.PrivateKey) (msg *Message, err error) {
+	// Split open the payload into a message construct
+	data := self.Data
+
+	message := &Message{
+		Flags: data[0],
+	}
+	data = data[1:]
+
+	if message.Flags&128 == 128 {
+		if len(data) < 65 {
+			return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < 65")
+		}
+		message.Signature, data = data[:65], data[65:]
+	}
+	message.Payload = data
+
+	// Short circuit if the encryption was requested
+	if key == nil {
+		return message, nil
+	}
+	// Otherwise try to decrypt the message
+	message.Payload, err = crypto.Decrypt(key, message.Payload)
+	switch err {
+	case nil:
+		return message, nil
+
+	case ecies.ErrInvalidPublicKey: // Payload isn't encrypted
+		return message, err
+
+	default:
+		return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err)
+	}
+}
+
+// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
+func (self *Envelope) Hash() common.Hash {
+	if (self.hash == common.Hash{}) {
+		enc, _ := rlp.EncodeToBytes(self)
+		self.hash = crypto.Sha3Hash(enc)
+	}
+	return self.hash
 }
 
 // rlpenv is an Envelope but is not an rlp.Decoder.
 // It is used for decoding because we need to
 type rlpenv Envelope
 
+// DecodeRLP decodes an Envelope from an RLP data stream.
 func (self *Envelope) DecodeRLP(s *rlp.Stream) error {
 	raw, err := s.Raw()
 	if err != nil {

+ 65 - 12
whisper/main.go

@@ -1,37 +1,90 @@
 // +build none
 
+// Contains a simple whisper peer setup and self messaging to allow playing
+// around with the protocol and API without a fancy client implementation.
+
 package main
 
 import (
 	"fmt"
 	"log"
 	"os"
+	"time"
 
-	"github.com/ethereum/go-ethereum/crypto/secp256k1"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/p2p"
+	"github.com/ethereum/go-ethereum/p2p/nat"
 	"github.com/ethereum/go-ethereum/whisper"
 )
 
 func main() {
 	logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel))
 
-	pub, _ := secp256k1.GenerateKeyPair()
-
-	whisper := whisper.New()
+	// Generate the peer identity
+	key, err := crypto.GenerateKey()
+	if err != nil {
+		fmt.Printf("Failed to generate peer key: %v.\n", err)
+		os.Exit(-1)
+	}
+	name := common.MakeName("whisper-go", "1.0")
+	shh := whisper.New()
 
-	srv := p2p.Server{
+	// Create an Ethereum peer to communicate through
+	server := p2p.Server{
+		PrivateKey: key,
 		MaxPeers:   10,
-		Identity:   p2p.NewSimpleClientIdentity("whisper-go", "1.0", "", string(pub)),
+		Name:       name,
+		Protocols:  []p2p.Protocol{shh.Protocol()},
 		ListenAddr: ":30300",
-		NAT:        p2p.UPNP(),
-
-		Protocols: []p2p.Protocol{whisper.Protocol()},
+		NAT:        nat.Any(),
 	}
-	if err := srv.Start(); err != nil {
-		fmt.Println("could not start server:", err)
+	fmt.Println("Starting Ethereum peer...")
+	if err := server.Start(); err != nil {
+		fmt.Printf("Failed to start Ethereum peer: %v.\n", err)
 		os.Exit(1)
 	}
 
-	select {}
+	// Send a message to self to check that something works
+	payload := fmt.Sprintf("Hello world, this is %v. In case you're wondering, the time is %v", name, time.Now())
+	if err := selfSend(shh, []byte(payload)); err != nil {
+		fmt.Printf("Failed to self message: %v.\n", err)
+		os.Exit(-1)
+	}
+}
+
+// SendSelf wraps a payload into a Whisper envelope and forwards it to itself.
+func selfSend(shh *whisper.Whisper, payload []byte) error {
+	ok := make(chan struct{})
+
+	// Start watching for self messages, output any arrivals
+	id := shh.NewIdentity()
+	shh.Watch(whisper.Filter{
+		To: &id.PublicKey,
+		Fn: func(msg *whisper.Message) {
+			fmt.Printf("Message received: %s, signed with 0x%x.\n", string(msg.Payload), msg.Signature)
+			close(ok)
+		},
+	})
+	// Wrap the payload and encrypt it
+	msg := whisper.NewMessage(payload)
+	envelope, err := msg.Wrap(whisper.DefaultProofOfWork, whisper.Options{
+		From: id,
+		To:   &id.PublicKey,
+		TTL:  whisper.DefaultTimeToLive,
+	})
+	if err != nil {
+		return fmt.Errorf("failed to seal message: %v", err)
+	}
+	// Dump the message into the system and wait for it to pop back out
+	if err := shh.Send(envelope); err != nil {
+		return fmt.Errorf("failed to send self-message: %v", err)
+	}
+	select {
+	case <-ok:
+	case <-time.After(time.Second):
+		return fmt.Errorf("failed to receive message in time")
+	}
+	return nil
 }

+ 76 - 45
whisper/message.go

@@ -1,7 +1,11 @@
+// Contains the Whisper protocol Message element. For formal details please see
+// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages.
+
 package whisper
 
 import (
 	"crypto/ecdsa"
+	"math/rand"
 	"time"
 
 	"github.com/ethereum/go-ethereum/crypto"
@@ -9,8 +13,11 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 )
 
+// Message represents an end-user data packet to trasmit through the Whisper
+// protocol. These are wrapped into Envelopes that need not be understood by
+// intermediate nodes, just forwarded.
 type Message struct {
-	Flags     byte
+	Flags     byte // First bit is signature presence, rest reserved and should be random
 	Signature []byte
 	Payload   []byte
 	Sent      int64
@@ -18,71 +25,95 @@ type Message struct {
 	To *ecdsa.PublicKey
 }
 
+// Options specifies the exact way a message should be wrapped into an Envelope.
+type Options struct {
+	From   *ecdsa.PrivateKey
+	To     *ecdsa.PublicKey
+	TTL    time.Duration
+	Topics [][]byte
+}
+
+// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
 func NewMessage(payload []byte) *Message {
-	return &Message{Flags: 0, Payload: payload, Sent: time.Now().Unix()}
+	// Construct an initial flag set: bit #1 = 0 (no signature), rest random
+	flags := byte(rand.Intn(128))
+
+	// Assemble and return the message
+	return &Message{
+		Flags:   flags,
+		Payload: payload,
+		Sent:    time.Now().Unix(),
+	}
 }
 
-func (self *Message) hash() []byte {
-	return crypto.Sha3(append([]byte{self.Flags}, self.Payload...))
+// Wrap bundles the message into an Envelope to transmit over the network.
+//
+// pow (Proof Of Work) controls how much time to spend on hashing the message,
+// inherently controlling its priority through the network (smaller hash, bigger
+// priority).
+//
+// The user can control the amount of identity, privacy and encryption through
+// the options parameter as follows:
+//   - options.From == nil && options.To == nil: anonymous broadcast
+//   - options.From != nil && options.To == nil: signed broadcast (known sender)
+//   - options.From == nil && options.To != nil: encrypted anonymous message
+//   - options.From != nil && options.To != nil: encrypted signed message
+func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error) {
+	// Use the default TTL if non was specified
+	if options.TTL == 0 {
+		options.TTL = DefaultTimeToLive
+	}
+	// Sign and encrypt the message if requested
+	if options.From != nil {
+		if err := self.sign(options.From); err != nil {
+			return nil, err
+		}
+	}
+	if options.To != nil {
+		if err := self.encrypt(options.To); err != nil {
+			return nil, err
+		}
+	}
+	// Wrap the processed message, seal it and return
+	envelope := NewEnvelope(options.TTL, options.Topics, self)
+	envelope.Seal(pow)
+
+	return envelope, nil
 }
 
+// sign calculates and sets the cryptographic signature for the message , also
+// setting the sign flag.
 func (self *Message) sign(key *ecdsa.PrivateKey) (err error) {
-	self.Flags = 1
+	self.Flags |= 1 << 7
 	self.Signature, err = crypto.Sign(self.hash(), key)
 	return
 }
 
+// Recover retrieves the public key of the message signer.
 func (self *Message) Recover() *ecdsa.PublicKey {
-	defer func() { recover() }() // in case of invalid sig
+	defer func() { recover() }() // in case of invalid signature
+
 	pub, err := crypto.SigToPub(self.hash(), self.Signature)
 	if err != nil {
-		glog.V(logger.Error).Infof("Could not get pubkey from signature: ", err)
+		glog.V(logger.Error).Infof("Could not get public key from signature: %v", err)
 		return nil
 	}
 	return pub
 }
 
-func (self *Message) Encrypt(to *ecdsa.PublicKey) (err error) {
+// encrypt encrypts a message payload with a public key.
+func (self *Message) encrypt(to *ecdsa.PublicKey) (err error) {
 	self.Payload, err = crypto.Encrypt(to, self.Payload)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (self *Message) Bytes() []byte {
-	return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...)
+	return
 }
 
-type Opts struct {
-	From   *ecdsa.PrivateKey
-	To     *ecdsa.PublicKey
-	Ttl    time.Duration
-	Topics [][]byte
+// hash calculates the SHA3 checksum of the message flags and payload.
+func (self *Message) hash() []byte {
+	return crypto.Sha3(append([]byte{self.Flags}, self.Payload...))
 }
 
-func (self *Message) Seal(pow time.Duration, opts Opts) (*Envelope, error) {
-	if opts.From != nil {
-		err := self.sign(opts.From)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if opts.To != nil {
-		err := self.Encrypt(opts.To)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if opts.Ttl == 0 {
-		opts.Ttl = DefaultTtl
-	}
-
-	envelope := NewEnvelope(opts.Ttl, opts.Topics, self)
-	envelope.Seal(pow)
-
-	return envelope, nil
+// bytes flattens the message contents (flags, signature and payload) into a
+// single binary blob.
+func (self *Message) bytes() []byte {
+	return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...)
 }

+ 138 - 0
whisper/message_test.go

@@ -0,0 +1,138 @@
+package whisper
+
+import (
+	"bytes"
+	"crypto/elliptic"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/crypto"
+)
+
+// Tests whether a message can be wrapped without any identity or encryption.
+func TestMessageSimpleWrap(t *testing.T) {
+	payload := []byte("hello world")
+
+	msg := NewMessage(payload)
+	if _, err := msg.Wrap(DefaultProofOfWork, Options{}); err != nil {
+		t.Fatalf("failed to wrap message: %v", err)
+	}
+	if msg.Flags&128 != 0 {
+		t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 0)
+	}
+	if len(msg.Signature) != 0 {
+		t.Fatalf("signature found for simple wrapping: 0x%x", msg.Signature)
+	}
+	if bytes.Compare(msg.Payload, payload) != 0 {
+		t.Fatalf("payload mismatch after wrapping: have 0x%x, want 0x%x", msg.Payload, payload)
+	}
+}
+
+// Tests whether a message can be signed, and wrapped in plain-text.
+func TestMessageCleartextSignRecover(t *testing.T) {
+	key, err := crypto.GenerateKey()
+	if err != nil {
+		t.Fatalf("failed to create crypto key: %v", err)
+	}
+	payload := []byte("hello world")
+
+	msg := NewMessage(payload)
+	if _, err := msg.Wrap(DefaultProofOfWork, Options{
+		From: key,
+	}); err != nil {
+		t.Fatalf("failed to sign message: %v", err)
+	}
+	if msg.Flags&128 != 128 {
+		t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 1)
+	}
+	if bytes.Compare(msg.Payload, payload) != 0 {
+		t.Fatalf("payload mismatch after signing: have 0x%x, want 0x%x", msg.Payload, payload)
+	}
+
+	pubKey := msg.Recover()
+	if pubKey == nil {
+		t.Fatalf("failed to recover public key")
+	}
+	p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
+	p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+	if !bytes.Equal(p1, p2) {
+		t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
+	}
+}
+
+// Tests whether a message can be encrypted and decrypted using an anonymous
+// sender (i.e. no signature).
+func TestMessageAnonymousEncryptDecrypt(t *testing.T) {
+	key, err := crypto.GenerateKey()
+	if err != nil {
+		t.Fatalf("failed to create recipient crypto key: %v", err)
+	}
+	payload := []byte("hello world")
+
+	msg := NewMessage(payload)
+	envelope, err := msg.Wrap(DefaultProofOfWork, Options{
+		To: &key.PublicKey,
+	})
+	if err != nil {
+		t.Fatalf("failed to encrypt message: %v", err)
+	}
+	if msg.Flags&128 != 0 {
+		t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 0)
+	}
+	if len(msg.Signature) != 0 {
+		t.Fatalf("signature found for anonymous message: 0x%x", msg.Signature)
+	}
+
+	out, err := envelope.Open(key)
+	if err != nil {
+		t.Fatalf("failed to open encrypted message: %v", err)
+	}
+	if !bytes.Equal(out.Payload, payload) {
+		t.Error("payload mismatch: have 0x%x, want 0x%x", out.Payload, payload)
+	}
+}
+
+// Tests whether a message can be properly signed and encrypted.
+func TestMessageFullCrypto(t *testing.T) {
+	fromKey, err := crypto.GenerateKey()
+	if err != nil {
+		t.Fatalf("failed to create sender crypto key: %v", err)
+	}
+	toKey, err := crypto.GenerateKey()
+	if err != nil {
+		t.Fatalf("failed to create recipient crypto key: %v", err)
+	}
+
+	payload := []byte("hello world")
+	msg := NewMessage(payload)
+	envelope, err := msg.Wrap(DefaultProofOfWork, Options{
+		From: fromKey,
+		To:   &toKey.PublicKey,
+	})
+	if err != nil {
+		t.Fatalf("failed to encrypt message: %v", err)
+	}
+	if msg.Flags&128 != 128 {
+		t.Fatalf("signature flag mismatch: have %d, want %d", (msg.Flags&128)>>7, 1)
+	}
+	if len(msg.Signature) == 0 {
+		t.Fatalf("no signature found for signed message")
+	}
+
+	out, err := envelope.Open(toKey)
+	if err != nil {
+		t.Fatalf("failed to open encrypted message: %v", err)
+	}
+	if !bytes.Equal(out.Payload, payload) {
+		t.Error("payload mismatch: have 0x%x, want 0x%x", out.Payload, payload)
+	}
+
+	pubKey := out.Recover()
+	if pubKey == nil {
+		t.Fatalf("failed to recover public key")
+	}
+	p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
+	p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+	if !bytes.Equal(p1, p2) {
+		t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
+	}
+}

+ 0 - 50
whisper/messages_test.go

@@ -1,50 +0,0 @@
-package whisper
-
-import (
-	"bytes"
-	"crypto/elliptic"
-	"fmt"
-	"testing"
-
-	"github.com/ethereum/go-ethereum/crypto"
-)
-
-func TestSign(t *testing.T) {
-	prv, _ := crypto.GenerateKey()
-	msg := NewMessage([]byte("hello world"))
-	msg.sign(prv)
-
-	pubKey := msg.Recover()
-	p1 := elliptic.Marshal(crypto.S256(), prv.PublicKey.X, prv.PublicKey.Y)
-	p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
-
-	if !bytes.Equal(p1, p2) {
-		t.Error("recovered pub key did not match")
-	}
-}
-
-func TestMessageEncryptDecrypt(t *testing.T) {
-	prv1, _ := crypto.GenerateKey()
-	prv2, _ := crypto.GenerateKey()
-
-	data := []byte("hello world")
-	msg := NewMessage(data)
-	envelope, err := msg.Seal(DefaultPow, Opts{
-		From: prv1,
-		To:   &prv2.PublicKey,
-	})
-	if err != nil {
-		fmt.Println(err)
-		t.FailNow()
-	}
-
-	msg1, err := envelope.Open(prv2)
-	if err != nil {
-		t.Error(err)
-		t.FailNow()
-	}
-
-	if !bytes.Equal(msg1.Payload, data) {
-		t.Error("encryption error. data did not match")
-	}
-}

+ 4 - 1
whisper/whisper.go

@@ -28,7 +28,10 @@ type MessageEvent struct {
 	Message *Message
 }
 
-const DefaultTtl = 50 * time.Second
+const (
+	DefaultTimeToLive  = 50 * time.Second
+	DefaultProofOfWork = 50 * time.Millisecond
+)
 
 type Whisper struct {
 	protocol p2p.Protocol

+ 2 - 2
whisper/whisper_test.go

@@ -18,8 +18,8 @@ func TestEvent(t *testing.T) {
 	})
 
 	msg := NewMessage([]byte(fmt.Sprintf("Hello world. This is whisper-go. Incase you're wondering; the time is %v", time.Now())))
-	envelope, err := msg.Seal(DefaultPow, Opts{
-		Ttl:  DefaultTtl,
+	envelope, err := msg.Wrap(DefaultProofOfWork, Options{
+		TTL:  DefaultTimeToLive,
 		From: id,
 		To:   &id.PublicKey,
 	})

+ 2 - 2
xeth/whisper.go

@@ -32,8 +32,8 @@ func (self *Whisper) Post(payload string, to, from string, topics []string, prio
 	pk := crypto.ToECDSAPub(common.FromHex(from))
 	if key := self.Whisper.GetIdentity(pk); key != nil || len(from) == 0 {
 		msg := whisper.NewMessage(common.FromHex(payload))
-		envelope, err := msg.Seal(time.Duration(priority*100000), whisper.Opts{
-			Ttl:    time.Duration(ttl) * time.Second,
+		envelope, err := msg.Wrap(time.Duration(priority*100000), whisper.Options{
+			TTL:    time.Duration(ttl) * time.Second,
 			To:     crypto.ToECDSAPub(common.FromHex(to)),
 			From:   key,
 			Topics: whisper.TopicsFromString(topics...),