mirror of
https://github.com/status-im/whisper.git
synced 2025-02-08 00:45:48 +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 {
|
type MailServerResponse struct {
|
||||||
LastEnvelopeHash common.Hash
|
LastEnvelopeHash common.Hash
|
||||||
Cursor []byte
|
Cursor []byte
|
||||||
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whisper represents a dark communication interface through the Ethereum
|
// 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")
|
return errors.New("invalid request response message")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if payload is
|
event, err := CreateMailServerEvent(payload)
|
||||||
// - 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)
|
|
||||||
|
|
||||||
if len(payload) < common.HashLength || len(payload) > common.HashLength*3+4 {
|
if err != nil {
|
||||||
log.Warn("invalid response message, peer will be disconnected", "peer", p.peer.ID(), "err", err, "payload size", len(payload))
|
log.Warn("error while parsing request complete code, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||||
return errors.New("invalid response size")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
if event != nil {
|
||||||
requestID common.Hash
|
whisper.envelopeFeed.Send(*event)
|
||||||
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 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:
|
default:
|
||||||
// New message types might be implemented in the future versions of Whisper.
|
// New message types might be implemented in the future versions of Whisper.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user