github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:45</date>
    10  //</624450123711123456>
    11  
    12  
    13  //包mailserver提供了一个简单的示例mailserver实现
    14  package mailserver
    15  
    16  import (
    17  	"encoding/binary"
    18  	"fmt"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/log"
    23  	"github.com/ethereum/go-ethereum/rlp"
    24  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    25  	"github.com/syndtr/goleveldb/leveldb"
    26  	"github.com/syndtr/goleveldb/leveldb/opt"
    27  	"github.com/syndtr/goleveldb/leveldb/util"
    28  )
    29  
    30  //wmailserver表示邮件服务器的状态数据。
    31  type WMailServer struct {
    32  	db  *leveldb.DB
    33  	w   *whisper.Whisper
    34  	pow float64
    35  	key []byte
    36  }
    37  
    38  type DBKey struct {
    39  	timestamp uint32
    40  	hash      common.Hash
    41  	raw       []byte
    42  }
    43  
    44  //newdbkey是一个帮助函数,它创建一个leveldb
    45  //来自哈希和整数的键。
    46  func NewDbKey(t uint32, h common.Hash) *DBKey {
    47  	const sz = common.HashLength + 4
    48  	var k DBKey
    49  	k.timestamp = t
    50  	k.hash = h
    51  	k.raw = make([]byte, sz)
    52  	binary.BigEndian.PutUint32(k.raw, k.timestamp)
    53  	copy(k.raw[4:], k.hash[:])
    54  	return &k
    55  }
    56  
    57  //init初始化邮件服务器。
    58  func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) error {
    59  	var err error
    60  	if len(path) == 0 {
    61  		return fmt.Errorf("DB file is not specified")
    62  	}
    63  
    64  	if len(password) == 0 {
    65  		return fmt.Errorf("password is not specified")
    66  	}
    67  
    68  	s.db, err = leveldb.OpenFile(path, &opt.Options{OpenFilesCacheCapacity: 32})
    69  	if err != nil {
    70  		return fmt.Errorf("open DB file: %s", err)
    71  	}
    72  
    73  	s.w = shh
    74  	s.pow = pow
    75  
    76  	MailServerKeyID, err := s.w.AddSymKeyFromPassword(password)
    77  	if err != nil {
    78  		return fmt.Errorf("create symmetric key: %s", err)
    79  	}
    80  	s.key, err = s.w.GetSymKey(MailServerKeyID)
    81  	if err != nil {
    82  		return fmt.Errorf("save symmetric key: %s", err)
    83  	}
    84  	return nil
    85  }
    86  
    87  //关闭前清理。
    88  func (s *WMailServer) Close() {
    89  	if s.db != nil {
    90  		s.db.Close()
    91  	}
    92  }
    93  
    94  //存档存储
    95  func (s *WMailServer) Archive(env *whisper.Envelope) {
    96  	key := NewDbKey(env.Expiry-env.TTL, env.Hash())
    97  	rawEnvelope, err := rlp.EncodeToBytes(env)
    98  	if err != nil {
    99  		log.Error(fmt.Sprintf("rlp.EncodeToBytes failed: %s", err))
   100  	} else {
   101  		err = s.db.Put(key.raw, rawEnvelope, nil)
   102  		if err != nil {
   103  			log.Error(fmt.Sprintf("Writing to DB failed: %s", err))
   104  		}
   105  	}
   106  }
   107  
   108  //Delivermail根据
   109  //邮件的所有者。
   110  func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) {
   111  	if peer == nil {
   112  		log.Error("Whisper peer is nil")
   113  		return
   114  	}
   115  
   116  	ok, lower, upper, bloom := s.validateRequest(peer.ID(), request)
   117  	if ok {
   118  		s.processRequest(peer, lower, upper, bloom)
   119  	}
   120  }
   121  
   122  func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bloom []byte) []*whisper.Envelope {
   123  	ret := make([]*whisper.Envelope, 0)
   124  	var err error
   125  	var zero common.Hash
   126  	kl := NewDbKey(lower, zero)
   127  ku := NewDbKey(upper+1, zero) //leveldb是独占的,而whisper API是包含的
   128  	i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
   129  	defer i.Release()
   130  
   131  	for i.Next() {
   132  		var envelope whisper.Envelope
   133  		err = rlp.DecodeBytes(i.Value(), &envelope)
   134  		if err != nil {
   135  			log.Error(fmt.Sprintf("RLP decoding failed: %s", err))
   136  		}
   137  
   138  		if whisper.BloomFilterMatch(bloom, envelope.Bloom()) {
   139  			if peer == nil {
   140  //用于测试目的
   141  				ret = append(ret, &envelope)
   142  			} else {
   143  				err = s.w.SendP2PDirect(peer, &envelope)
   144  				if err != nil {
   145  					log.Error(fmt.Sprintf("Failed to send direct message to peer: %s", err))
   146  					return nil
   147  				}
   148  			}
   149  		}
   150  	}
   151  
   152  	err = i.Error()
   153  	if err != nil {
   154  		log.Error(fmt.Sprintf("Level DB iterator error: %s", err))
   155  	}
   156  
   157  	return ret
   158  }
   159  
   160  func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, []byte) {
   161  	if s.pow > 0.0 && request.PoW() < s.pow {
   162  		return false, 0, 0, nil
   163  	}
   164  
   165  	f := whisper.Filter{KeySym: s.key}
   166  	decrypted := request.Open(&f)
   167  	if decrypted == nil {
   168  		log.Warn(fmt.Sprintf("Failed to decrypt p2p request"))
   169  		return false, 0, 0, nil
   170  	}
   171  
   172  	src := crypto.FromECDSAPub(decrypted.Src)
   173  	if len(src)-len(peerID) == 1 {
   174  		src = src[1:]
   175  	}
   176  
   177  //如果你想核对签名,你可以在这里核对。例如。:
   178  //如果!bytes.equal(peerid,src)
   179  	if src == nil {
   180  		log.Warn(fmt.Sprintf("Wrong signature of p2p request"))
   181  		return false, 0, 0, nil
   182  	}
   183  
   184  	var bloom []byte
   185  	payloadSize := len(decrypted.Payload)
   186  	if payloadSize < 8 {
   187  		log.Warn(fmt.Sprintf("Undersized p2p request"))
   188  		return false, 0, 0, nil
   189  	} else if payloadSize == 8 {
   190  		bloom = whisper.MakeFullNodeBloom()
   191  	} else if payloadSize < 8+whisper.BloomFilterSize {
   192  		log.Warn(fmt.Sprintf("Undersized bloom filter in p2p request"))
   193  		return false, 0, 0, nil
   194  	} else {
   195  		bloom = decrypted.Payload[8 : 8+whisper.BloomFilterSize]
   196  	}
   197  
   198  	lower := binary.BigEndian.Uint32(decrypted.Payload[:4])
   199  	upper := binary.BigEndian.Uint32(decrypted.Payload[4:8])
   200  	return true, lower, upper, bloom
   201  }
   202