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