github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/mailserver/mailserver.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:51</date>
    10  //</624342687989895168>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package mailserver
    29  
    30  import (
    31  	"encoding/binary"
    32  	"fmt"
    33  
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/crypto"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"github.com/ethereum/go-ethereum/rlp"
    38  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    39  	"github.com/syndtr/goleveldb/leveldb"
    40  	"github.com/syndtr/goleveldb/leveldb/util"
    41  )
    42  
    43  type WMailServer struct {
    44  	db  *leveldb.DB
    45  	w   *whisper.Whisper
    46  	pow float64
    47  	key []byte
    48  }
    49  
    50  type DBKey struct {
    51  	timestamp uint32
    52  	hash      common.Hash
    53  	raw       []byte
    54  }
    55  
    56  func NewDbKey(t uint32, h common.Hash) *DBKey {
    57  	const sz = common.HashLength + 4
    58  	var k DBKey
    59  	k.timestamp = t
    60  	k.hash = h
    61  	k.raw = make([]byte, sz)
    62  	binary.BigEndian.PutUint32(k.raw, k.timestamp)
    63  	copy(k.raw[4:], k.hash[:])
    64  	return &k
    65  }
    66  
    67  func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) error {
    68  	var err error
    69  	if len(path) == 0 {
    70  		return fmt.Errorf("DB file is not specified")
    71  	}
    72  
    73  	if len(password) == 0 {
    74  		return fmt.Errorf("password is not specified")
    75  	}
    76  
    77  	s.db, err = leveldb.OpenFile(path, nil)
    78  	if err != nil {
    79  		return fmt.Errorf("open DB file: %s", err)
    80  	}
    81  
    82  	s.w = shh
    83  	s.pow = pow
    84  
    85  	MailServerKeyID, err := s.w.AddSymKeyFromPassword(password)
    86  	if err != nil {
    87  		return fmt.Errorf("create symmetric key: %s", err)
    88  	}
    89  	s.key, err = s.w.GetSymKey(MailServerKeyID)
    90  	if err != nil {
    91  		return fmt.Errorf("save symmetric key: %s", err)
    92  	}
    93  	return nil
    94  }
    95  
    96  func (s *WMailServer) Close() {
    97  	if s.db != nil {
    98  		s.db.Close()
    99  	}
   100  }
   101  
   102  func (s *WMailServer) Archive(env *whisper.Envelope) {
   103  	key := NewDbKey(env.Expiry-env.TTL, env.Hash())
   104  	rawEnvelope, err := rlp.EncodeToBytes(env)
   105  	if err != nil {
   106  		log.Error(fmt.Sprintf("rlp.EncodeToBytes failed: %s", err))
   107  	} else {
   108  		err = s.db.Put(key.raw, rawEnvelope, nil)
   109  		if err != nil {
   110  			log.Error(fmt.Sprintf("Writing to DB failed: %s", err))
   111  		}
   112  	}
   113  }
   114  
   115  func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) {
   116  	if peer == nil {
   117  		log.Error("Whisper peer is nil")
   118  		return
   119  	}
   120  
   121  	ok, lower, upper, bloom := s.validateRequest(peer.ID(), request)
   122  	if ok {
   123  		s.processRequest(peer, lower, upper, bloom)
   124  	}
   125  }
   126  
   127  func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bloom []byte) []*whisper.Envelope {
   128  	ret := make([]*whisper.Envelope, 0)
   129  	var err error
   130  	var zero common.Hash
   131  	kl := NewDbKey(lower, zero)
   132  	ku := NewDbKey(upper, zero)
   133  	i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
   134  	defer i.Release()
   135  
   136  	for i.Next() {
   137  		var envelope whisper.Envelope
   138  		err = rlp.DecodeBytes(i.Value(), &envelope)
   139  		if err != nil {
   140  			log.Error(fmt.Sprintf("RLP decoding failed: %s", err))
   141  		}
   142  
   143  		if whisper.BloomFilterMatch(bloom, envelope.Bloom()) {
   144  			if peer == nil {
   145  //
   146  				ret = append(ret, &envelope)
   147  			} else {
   148  				err = s.w.SendP2PDirect(peer, &envelope)
   149  				if err != nil {
   150  					log.Error(fmt.Sprintf("Failed to send direct message to peer: %s", err))
   151  					return nil
   152  				}
   153  			}
   154  		}
   155  	}
   156  
   157  	err = i.Error()
   158  	if err != nil {
   159  		log.Error(fmt.Sprintf("Level DB iterator error: %s", err))
   160  	}
   161  
   162  	return ret
   163  }
   164  
   165  func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, []byte) {
   166  	if s.pow > 0.0 && request.PoW() < s.pow {
   167  		return false, 0, 0, nil
   168  	}
   169  
   170  	f := whisper.Filter{KeySym: s.key}
   171  	decrypted := request.Open(&f)
   172  	if decrypted == nil {
   173  		log.Warn(fmt.Sprintf("Failed to decrypt p2p request"))
   174  		return false, 0, 0, nil
   175  	}
   176  
   177  	src := crypto.FromECDSAPub(decrypted.Src)
   178  	if len(src)-len(peerID) == 1 {
   179  		src = src[1:]
   180  	}
   181  
   182  //
   183  //
   184  	if src == nil {
   185  		log.Warn(fmt.Sprintf("Wrong signature of p2p request"))
   186  		return false, 0, 0, nil
   187  	}
   188  
   189  	var bloom []byte
   190  	payloadSize := len(decrypted.Payload)
   191  	if payloadSize < 8 {
   192  		log.Warn(fmt.Sprintf("Undersized p2p request"))
   193  		return false, 0, 0, nil
   194  	} else if payloadSize == 8 {
   195  		bloom = whisper.MakeFullNodeBloom()
   196  	} else if payloadSize < 8+whisper.BloomFilterSize {
   197  		log.Warn(fmt.Sprintf("Undersized bloom filter in p2p request"))
   198  		return false, 0, 0, nil
   199  	} else {
   200  		bloom = decrypted.Payload[8 : 8+whisper.BloomFilterSize]
   201  	}
   202  
   203  	lower := binary.BigEndian.Uint32(decrypted.Payload[:4])
   204  	upper := binary.BigEndian.Uint32(decrypted.Payload[4:8])
   205  	return true, lower, upper, bloom
   206  }
   207