diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go index e1dab7b226..174fee3fe5 100644 --- a/whisper/whisperv6/api.go +++ b/whisper/whisperv6/api.go @@ -284,7 +284,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil. } var result []byte - env, err := whisperMsg.Wrap(params) + env, err := whisperMsg.Wrap(params, api.w.GetCurrentTime()) if err != nil { return nil, err } diff --git a/whisper/whisperv6/benchmarks_test.go b/whisper/whisperv6/benchmarks_test.go index 0473179da5..b96f9695c5 100644 --- a/whisper/whisperv6/benchmarks_test.go +++ b/whisper/whisperv6/benchmarks_test.go @@ -19,6 +19,7 @@ package whisperv6 import ( "crypto/sha256" "testing" + "time" "github.com/ethereum/go-ethereum/crypto" "golang.org/x/crypto/pbkdf2" @@ -40,7 +41,7 @@ func BenchmarkEncryptionSym(b *testing.B) { for i := 0; i < b.N; i++ { msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) + _, err := msg.Wrap(params, time.Now()) if err != nil { b.Errorf("failed Wrap with seed %d: %s.", seed, err) b.Errorf("i = %d, len(msg.Raw) = %d, params.Payload = %d.", i, len(msg.Raw), len(params.Payload)) @@ -65,7 +66,7 @@ func BenchmarkEncryptionAsym(b *testing.B) { for i := 0; i < b.N; i++ { msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) + _, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -80,7 +81,7 @@ func BenchmarkDecryptionSymValid(b *testing.B) { b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -102,7 +103,7 @@ func BenchmarkDecryptionSymInvalid(b *testing.B) { b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) } msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -131,7 +132,7 @@ func BenchmarkDecryptionAsymValid(b *testing.B) { params.KeySym = nil params.Dst = &key.PublicKey msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -158,7 +159,7 @@ func BenchmarkDecryptionAsymInvalid(b *testing.B) { params.KeySym = nil params.Dst = &key.PublicKey msg, _ := NewSentMessage(params) - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -200,7 +201,7 @@ func BenchmarkPoW(b *testing.B) { for i := 0; i < b.N; i++ { increment(params.Payload) msg, _ := NewSentMessage(params) - _, err := msg.Wrap(params) + _, err := msg.Wrap(params, time.Now()) if err != nil { b.Fatalf("failed Wrap with seed %d: %s.", seed, err) } diff --git a/whisper/whisperv6/envelope.go b/whisper/whisperv6/envelope.go index c42d1fa8ac..3b65fdba03 100644 --- a/whisper/whisperv6/envelope.go +++ b/whisper/whisperv6/envelope.go @@ -62,9 +62,9 @@ func (e *Envelope) rlpWithoutNonce() []byte { // NewEnvelope wraps a Whisper message with expiration and destination data // included into an envelope for network forwarding. -func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { +func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage, now time.Time) *Envelope { env := Envelope{ - Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), + Expiry: uint32(now.Add(time.Second * time.Duration(ttl)).Unix()), TTL: ttl, Topic: topic, Data: msg.Raw, diff --git a/whisper/whisperv6/envelope_test.go b/whisper/whisperv6/envelope_test.go index 410b250a3f..d7a4fc1665 100644 --- a/whisper/whisperv6/envelope_test.go +++ b/whisper/whisperv6/envelope_test.go @@ -21,6 +21,7 @@ package whisperv6 import ( mrand "math/rand" "testing" + "time" "github.com/ethereum/go-ethereum/crypto" ) @@ -50,7 +51,7 @@ func TestEnvelopeOpenAcceptsOnlyOneKeyTypeInFilter(t *testing.T) { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - e, err := msg.Wrap(¶ms) + e, err := msg.Wrap(¶ms, time.Now()) if err != nil { t.Fatalf("Failed to Wrap the message in an envelope with seed %d: %s", seed, err) } diff --git a/whisper/whisperv6/filter_test.go b/whisper/whisperv6/filter_test.go index 82e4aa0241..2054049cb4 100644 --- a/whisper/whisperv6/filter_test.go +++ b/whisper/whisperv6/filter_test.go @@ -203,7 +203,7 @@ func TestInstallIdenticalFilters(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := sentMessage.Wrap(params) + env, err := sentMessage.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -309,7 +309,7 @@ func TestMatchEnvelope(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -322,7 +322,7 @@ func TestMatchEnvelope(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err = msg.Wrap(params) + env, err = msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) } @@ -367,7 +367,7 @@ func TestMatchEnvelope(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err = msg.Wrap(params) + env, err = msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap() with seed %d: %s.", seed, err) } @@ -449,7 +449,7 @@ func TestMatchMessageSym(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := sentMessage.Wrap(params) + env, err := sentMessage.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -543,7 +543,7 @@ func TestMatchMessageAsym(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := sentMessage.Wrap(params) + env, err := sentMessage.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -628,7 +628,7 @@ func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := sentMessage.Wrap(params) + env, err := sentMessage.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) return nil @@ -804,7 +804,7 @@ func TestVariableTopics(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } diff --git a/whisper/whisperv6/message.go b/whisper/whisperv6/message.go index 2d4e862441..a12b445e2f 100644 --- a/whisper/whisperv6/message.go +++ b/whisper/whisperv6/message.go @@ -27,6 +27,7 @@ import ( "errors" mrand "math/rand" "strconv" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -234,7 +235,7 @@ func generateSecureRandomData(length int) ([]byte, error) { } // Wrap bundles the message into an Envelope to transmit over the network. -func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) { +func (msg *sentMessage) Wrap(options *MessageParams, now time.Time) (envelope *Envelope, err error) { if options.TTL == 0 { options.TTL = DefaultTTL } @@ -254,7 +255,7 @@ func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er return nil, err } - envelope = NewEnvelope(options.TTL, options.Topic, msg) + envelope = NewEnvelope(options.TTL, options.Topic, msg, now) if err = envelope.Seal(options); err != nil { return nil, err } diff --git a/whisper/whisperv6/message_test.go b/whisper/whisperv6/message_test.go index 0a5c1c8533..d1a5ddbc81 100644 --- a/whisper/whisperv6/message_test.go +++ b/whisper/whisperv6/message_test.go @@ -22,6 +22,7 @@ import ( "crypto/cipher" mrand "math/rand" "testing" + "time" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -77,7 +78,7 @@ func singleMessageTest(t *testing.T, symmetric bool) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -138,7 +139,7 @@ func TestMessageWrap(t *testing.T) { params.TTL = 1 params.WorkTime = 12 params.PoW = target - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -156,7 +157,7 @@ func TestMessageWrap(t *testing.T) { params.TTL = 1000000 params.WorkTime = 1 params.PoW = 10000000.0 - _, err = msg2.Wrap(params) + _, err = msg2.Wrap(params, time.Now()) if err == nil { t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed) } @@ -178,7 +179,7 @@ func TestMessageSeal(t *testing.T) { } params.TTL = 1 - env := NewEnvelope(params.TTL, params.Topic, msg) + env := NewEnvelope(params.TTL, params.Topic, msg, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -238,7 +239,7 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -294,7 +295,7 @@ func TestEncryptWithZeroKey(t *testing.T) { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } params.KeySym = make([]byte, aesKeyLength) - _, err = msg.Wrap(params) + _, err = msg.Wrap(params, time.Now()) if err == nil { t.Fatalf("wrapped with zero key, seed: %d.", seed) } @@ -308,7 +309,7 @@ func TestEncryptWithZeroKey(t *testing.T) { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } params.KeySym = make([]byte, 0) - _, err = msg.Wrap(params) + _, err = msg.Wrap(params, time.Now()) if err == nil { t.Fatalf("wrapped with empty key, seed: %d.", seed) } @@ -322,7 +323,7 @@ func TestEncryptWithZeroKey(t *testing.T) { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } params.KeySym = nil - _, err = msg.Wrap(params) + _, err = msg.Wrap(params, time.Now()) if err == nil { t.Fatalf("wrapped with nil key, seed: %d.", seed) } @@ -339,7 +340,7 @@ func TestRlpEncode(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("wrapped with zero key, seed: %d.", seed) } @@ -383,7 +384,7 @@ func singlePaddingTest(t *testing.T, padSize int) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize) } diff --git a/whisper/whisperv6/peer_test.go b/whisper/whisperv6/peer_test.go index fe31922cb2..b2f45a9053 100644 --- a/whisper/whisperv6/peer_test.go +++ b/whisper/whisperv6/peer_test.go @@ -381,7 +381,7 @@ func sendMsg(t *testing.T, expected bool, id int) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - envelope, err := msg.Wrap(&opt) + envelope, err := msg.Wrap(&opt, time.Now()) if err != nil { t.Fatalf("failed to seal message: %s", err) } @@ -405,7 +405,7 @@ func TestPeerBasic(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d.", seed) } diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go index eb713f84ee..c4512f0f11 100644 --- a/whisper/whisperv6/whisper.go +++ b/whisper/whisperv6/whisper.go @@ -59,6 +59,9 @@ const ( restrictConnectionBetweenLightClientsIdx // Restrict connection between two light clients ) +// timeSource is a functon that returns time. +type timeSource func() time.Time + // Whisper represents a dark communication interface through the Ethereum // network, using its very own P2P communication layer. type Whisper struct { @@ -87,6 +90,8 @@ type Whisper struct { statsMu sync.Mutex // guard stats stats Statistics // Statistics of whisper node + timeSource timeSource // source of time for internal whisper usage. time.Now by default. + mailServer MailServer // MailServer interface } @@ -106,6 +111,7 @@ func New(cfg *Config) *Whisper { p2pMsgQueue: make(chan *Envelope, messageQueueLimit), quit: make(chan struct{}), syncAllowance: DefaultSyncAllowance, + timeSource: time.Now, } whisper.filters = NewFilters(whisper) @@ -212,6 +218,16 @@ func (whisper *Whisper) RegisterServer(server MailServer) { whisper.mailServer = server } +// UseTimeSource assigns provided time source as a default for a whisper. +func (whisper *Whisper) UseTimeSource(source timeSource) { + whisper.timeSource = source +} + +// GetCurrentTime returns time according to a source used by whisper. +func (whisper *Whisper) GetCurrentTime() time.Time { + return whisper.timeSource() +} + // Protocols returns the whisper sub-protocols ran by this particular client. func (whisper *Whisper) Protocols() []p2p.Protocol { return []p2p.Protocol{whisper.protocol} @@ -773,7 +789,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { // appropriate time-stamp. In case of error, connection should be dropped. // param isP2P indicates whether the message is peer-to-peer (should not be forwarded). func (whisper *Whisper) add(envelope *Envelope, isP2P bool) (bool, error) { - now := uint32(time.Now().Unix()) + now := uint32(whisper.GetCurrentTime().Unix()) sent := envelope.Expiry - envelope.TTL if sent > now { @@ -916,7 +932,7 @@ func (whisper *Whisper) expire() { whisper.statsMu.Lock() defer whisper.statsMu.Unlock() whisper.stats.reset() - now := uint32(time.Now().Unix()) + now := uint32(whisper.GetCurrentTime().Unix()) for expiry, hashSet := range whisper.expirations { if expiry < now { // Dump all expired messages and remove timestamp diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go index 895bb2b969..0df876ef45 100644 --- a/whisper/whisperv6/whisper_test.go +++ b/whisper/whisperv6/whisper_test.go @@ -477,7 +477,7 @@ func TestExpiry(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -544,7 +544,7 @@ func TestCustomization(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -565,7 +565,7 @@ func TestCustomization(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err = msg.Wrap(params) + env, err = msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -649,7 +649,7 @@ func TestSymmetricSendCycle(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -727,7 +727,7 @@ func TestSymmetricSendWithoutAKey(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) } @@ -793,7 +793,7 @@ func TestSymmetricSendKeyMismatch(t *testing.T) { if err != nil { t.Fatalf("failed to create new message with seed %d: %s.", seed, err) } - env, err := msg.Wrap(params) + env, err := msg.Wrap(params, time.Now()) if err != nil { t.Fatalf("failed Wrap with seed %d: %s.", seed, err) }