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 }