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