mirror of
https://github.com/status-im/whisper.git
synced 2025-02-01 05:24:56 +00:00
Add an response that mailserver failed to complete request.
This commit is contained in:
parent
ca91ec35f6
commit
14e1bbfd9b
136
whisperv6/mailserver_response.go
Normal file
136
whisperv6/mailserver_response.go
Normal file
@ -0,0 +1,136 @@
|
||||
package whisperv6
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const (
|
||||
mailServerFailedPayloadPrefix = "ERROR="
|
||||
cursorSize = 36
|
||||
)
|
||||
|
||||
func invalidResponseSizeError(size int) error {
|
||||
return fmt.Errorf("unexpected payload size: %d", size)
|
||||
}
|
||||
|
||||
// CreateMailServerRequestCompletedPayload creates a payload representing
|
||||
// a successful request to mailserver
|
||||
func CreateMailServerRequestCompletedPayload(requestID, lastEnvelopeHash common.Hash, cursor []byte) []byte {
|
||||
payload := append(requestID[:], lastEnvelopeHash[:]...)
|
||||
payload = append(payload, cursor...)
|
||||
return payload
|
||||
}
|
||||
|
||||
// CreateMailServerRequestFailedPayload creates a payload representing
|
||||
// a failed request to a mailserver
|
||||
func CreateMailServerRequestFailedPayload(requestID common.Hash, err error) []byte {
|
||||
payloadPrefix := []byte(mailServerFailedPayloadPrefix)
|
||||
errorString := []byte(err.Error())
|
||||
payload := append(payloadPrefix, requestID[:]...)
|
||||
payload = append(payload, errorString[:]...)
|
||||
return payload
|
||||
}
|
||||
|
||||
// CreateMailServerEvent returns EnvelopeEvent with correct data
|
||||
// if payload corresponds to any of the know mailserver events:
|
||||
// * request completed successfully
|
||||
// * request failed
|
||||
// If the payload is unknown/unparseable, it returns `nil`
|
||||
func CreateMailServerEvent(payload []byte) (*EnvelopeEvent, error) {
|
||||
|
||||
if len(payload) < common.HashLength {
|
||||
return nil, invalidResponseSizeError(len(payload))
|
||||
}
|
||||
|
||||
event, err := tryCreateMailServerRequestFailedEvent(payload)
|
||||
|
||||
if err != nil || event != nil {
|
||||
return event, err
|
||||
}
|
||||
|
||||
return tryCreateMailServerRequestCompletedEvent(payload)
|
||||
}
|
||||
|
||||
func tryCreateMailServerRequestFailedEvent(payload []byte) (*EnvelopeEvent, error) {
|
||||
if len(payload) < common.HashLength+len(mailServerFailedPayloadPrefix) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
prefix, remainder := extractPrefix(payload, len(mailServerFailedPayloadPrefix))
|
||||
|
||||
if !bytes.Equal(prefix, []byte(mailServerFailedPayloadPrefix)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
requestID common.Hash
|
||||
errorMsg string
|
||||
)
|
||||
|
||||
requestID, remainder = extractHash(remainder)
|
||||
errorMsg = string(remainder)
|
||||
|
||||
event := EnvelopeEvent{
|
||||
Hash: requestID,
|
||||
Event: EventMailServerRequestCompleted,
|
||||
Data: &MailServerResponse{
|
||||
Error: errors.New(errorMsg),
|
||||
},
|
||||
}
|
||||
|
||||
return &event, nil
|
||||
|
||||
}
|
||||
|
||||
func tryCreateMailServerRequestCompletedEvent(payload []byte) (*EnvelopeEvent, error) {
|
||||
// check if payload is
|
||||
// - requestID or
|
||||
// - requestID + lastEnvelopeHash or
|
||||
// - requestID + lastEnvelopeHash + cursor
|
||||
// requestID is the hash of the request envelope.
|
||||
// lastEnvelopeHash is the last envelope sent by the mail server
|
||||
// cursor is the db key, 36 bytes: 4 for the timestamp + 32 for the envelope hash.
|
||||
if len(payload) > common.HashLength*2+cursorSize {
|
||||
return nil, invalidResponseSizeError(len(payload))
|
||||
}
|
||||
|
||||
var (
|
||||
requestID common.Hash
|
||||
lastEnvelopeHash common.Hash
|
||||
cursor []byte
|
||||
)
|
||||
|
||||
requestID, remainder := extractHash(payload)
|
||||
|
||||
if len(remainder) >= common.HashLength {
|
||||
lastEnvelopeHash, remainder = extractHash(remainder)
|
||||
}
|
||||
|
||||
if len(remainder) >= cursorSize {
|
||||
cursor = remainder
|
||||
}
|
||||
|
||||
event := EnvelopeEvent{
|
||||
Hash: requestID,
|
||||
Event: EventMailServerRequestCompleted,
|
||||
Data: &MailServerResponse{
|
||||
LastEnvelopeHash: lastEnvelopeHash,
|
||||
Cursor: cursor,
|
||||
},
|
||||
}
|
||||
|
||||
return &event, nil
|
||||
}
|
||||
|
||||
func extractHash(payload []byte) (common.Hash, []byte) {
|
||||
prefix, remainder := extractPrefix(payload, common.HashLength)
|
||||
return common.BytesToHash(prefix), remainder
|
||||
}
|
||||
|
||||
func extractPrefix(payload []byte, size int) ([]byte, []byte) {
|
||||
return payload[:size], payload[size:]
|
||||
}
|
130
whisperv6/mailserver_response_test.go
Normal file
130
whisperv6/mailserver_response_test.go
Normal file
@ -0,0 +1,130 @@
|
||||
package whisperv6
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||
)
|
||||
|
||||
func checkValidErrorPayload(t *testing.T, id []byte, errorMsg string) {
|
||||
requestID := common.BytesToHash(id)
|
||||
|
||||
errPayload := CreateMailServerRequestFailedPayload(requestID, errors.New(errorMsg))
|
||||
|
||||
event, err := CreateMailServerEvent(errPayload)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Could not parse payload: %v", errPayload)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(event.Hash[:], requestID[:]) {
|
||||
t.Errorf("Unexpected hash: %v, expected %v", event.Hash, requestID)
|
||||
return
|
||||
}
|
||||
|
||||
eventData, ok := event.Data.(*MailServerResponse)
|
||||
if !ok {
|
||||
t.Errorf("Unexpected data in event: %v, expected a MailServerResponse", event.Data)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Compare(eventData.Error.Error(), errorMsg) != 0 {
|
||||
t.Errorf("Unexpected error string: '%s', expected '%s'", eventData, errorMsg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func checkValidSuccessPayload(t *testing.T, id []byte, lastHash []byte, timestamp uint32, envHash []byte) {
|
||||
requestID := common.BytesToHash(id)
|
||||
lastEnvelopeHash := common.BytesToHash(lastHash)
|
||||
|
||||
timestampBytes := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(timestampBytes, timestamp)
|
||||
|
||||
envelopeHash := common.BytesToHash(envHash)
|
||||
|
||||
cursor := append(timestampBytes, envelopeHash[:]...)
|
||||
|
||||
successPayload := CreateMailServerRequestCompletedPayload(requestID, lastEnvelopeHash, cursor)
|
||||
|
||||
event, err := CreateMailServerEvent(successPayload)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
t.Errorf("Could not parse payload: %v", successPayload)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(event.Hash[:], requestID[:]) {
|
||||
t.Errorf("Unexpected hash: %v, expected %v", event.Hash, requestID)
|
||||
return
|
||||
}
|
||||
|
||||
eventData, ok := event.Data.(*MailServerResponse)
|
||||
if !ok {
|
||||
t.Errorf("Unexpected data in event: %v, expected a MailServerResponse", event.Data)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(eventData.LastEnvelopeHash[:], lastEnvelopeHash[:]) {
|
||||
t.Errorf("Unexpected LastEnvelopeHash: %v, expected %v",
|
||||
eventData.LastEnvelopeHash, lastEnvelopeHash)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(eventData.Cursor, cursor) {
|
||||
t.Errorf("Unexpected cursor: %v, expected: %v", eventData.Cursor, cursor)
|
||||
return
|
||||
}
|
||||
|
||||
if eventData.Error != nil {
|
||||
t.Errorf("Unexpected error: %v", eventData.Error)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMailServerEvent(t *testing.T) {
|
||||
// valid cases
|
||||
longErrorMessage := "longMessage|"
|
||||
for i := 0; i < 5; i++ {
|
||||
longErrorMessage = longErrorMessage + longErrorMessage
|
||||
}
|
||||
checkValidErrorPayload(t, []byte{0x01}, "test error 1")
|
||||
checkValidErrorPayload(t, []byte{0x02}, "test error 2")
|
||||
checkValidErrorPayload(t, []byte{0x02}, "")
|
||||
checkValidErrorPayload(t, []byte{0x00}, "test error 3")
|
||||
checkValidErrorPayload(t, []byte{}, "test error 4")
|
||||
|
||||
checkValidSuccessPayload(t, []byte{0x01}, []byte{0x02}, 123, []byte{0x03})
|
||||
// invalid payloads
|
||||
|
||||
// too small
|
||||
_, err := CreateMailServerEvent([]byte{0x00})
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, got nil")
|
||||
return
|
||||
}
|
||||
|
||||
// too big and not error payload
|
||||
payloadTooBig := make([]byte, common.HashLength*2+cursorSize+100)
|
||||
_, err = CreateMailServerEvent(payloadTooBig)
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, got nil")
|
||||
return
|
||||
}
|
||||
|
||||
}
|
@ -66,6 +66,7 @@ const (
|
||||
type MailServerResponse struct {
|
||||
LastEnvelopeHash common.Hash
|
||||
Cursor []byte
|
||||
Error error
|
||||
}
|
||||
|
||||
// Whisper represents a dark communication interface through the Ethereum
|
||||
@ -911,44 +912,17 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
return errors.New("invalid request response message")
|
||||
}
|
||||
|
||||
// check if payload is
|
||||
// - requestID or
|
||||
// - requestID + lastEnvelopeHash or
|
||||
// - requestID + lastEnvelopeHash + cursor
|
||||
// requestID is the hash of the request envelope.
|
||||
// lastEnvelopeHash is the last envelope sent by the mail server
|
||||
// cursor is the db key, 36 bytes: 4 for the timestamp + 32 for the envelope hash.
|
||||
// length := len(payload)
|
||||
event, err := CreateMailServerEvent(payload)
|
||||
|
||||
if len(payload) < common.HashLength || len(payload) > common.HashLength*3+4 {
|
||||
log.Warn("invalid response message, peer will be disconnected", "peer", p.peer.ID(), "err", err, "payload size", len(payload))
|
||||
return errors.New("invalid response size")
|
||||
if err != nil {
|
||||
log.Warn("error while parsing request complete code, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
requestID common.Hash
|
||||
lastEnvelopeHash common.Hash
|
||||
cursor []byte
|
||||
)
|
||||
|
||||
requestID = common.BytesToHash(payload[:common.HashLength])
|
||||
|
||||
if len(payload) >= common.HashLength*2 {
|
||||
lastEnvelopeHash = common.BytesToHash(payload[common.HashLength : common.HashLength*2])
|
||||
if event != nil {
|
||||
whisper.envelopeFeed.Send(*event)
|
||||
}
|
||||
|
||||
if len(payload) >= common.HashLength*2+36 {
|
||||
cursor = payload[common.HashLength*2 : common.HashLength*2+36]
|
||||
}
|
||||
|
||||
whisper.envelopeFeed.Send(EnvelopeEvent{
|
||||
Hash: requestID,
|
||||
Event: EventMailServerRequestCompleted,
|
||||
Data: &MailServerResponse{
|
||||
LastEnvelopeHash: lastEnvelopeHash,
|
||||
Cursor: cursor,
|
||||
},
|
||||
})
|
||||
}
|
||||
default:
|
||||
// New message types might be implemented in the future versions of Whisper.
|
||||
|
Loading…
x
Reference in New Issue
Block a user