github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/whisper/mailserver/mailserver.go (about)

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