github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/hasherstore.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 //</624450119906889728> 11 12 13 package storage 14 15 import ( 16 "context" 17 "fmt" 18 "sync/atomic" 19 20 ch "github.com/ethereum/go-ethereum/swarm/chunk" 21 "github.com/ethereum/go-ethereum/swarm/storage/encryption" 22 "golang.org/x/crypto/sha3" 23 ) 24 25 type hasherStore struct { 26 store ChunkStore 27 toEncrypt bool 28 hashFunc SwarmHasher 29 hashSize int //内容哈希大小 30 refSize int64 //引用大小(内容哈希+可能的加密密钥) 31 errC chan error //全局错误通道 32 doneC chan struct{} //通过close()调用关闭,以指示count是最后的块数 33 quitC chan struct{} //关闭以退出未终止的例程 34 //nrchunks与原子函数一起使用 35 //它必须位于结构的末尾,以确保ARM体系结构的64位对齐。 36 //参见:https://golang.org/pkg/sync/atomic/pkg note bug 37 nrChunks uint64 //要存储的块数 38 } 39 40 //NewHasherStore创建了一个HasherStore对象,它实现了推杆和getter接口。 41 //使用hasherstore,您可以将区块数据(仅为[]字节)放入chunkstore中并获取它们。 42 //如果需要,哈希存储将获取数据加密/解密的核心。 43 func NewHasherStore(store ChunkStore, hashFunc SwarmHasher, toEncrypt bool) *hasherStore { 44 hashSize := hashFunc().Size() 45 refSize := int64(hashSize) 46 if toEncrypt { 47 refSize += encryption.KeyLength 48 } 49 50 h := &hasherStore{ 51 store: store, 52 toEncrypt: toEncrypt, 53 hashFunc: hashFunc, 54 hashSize: hashSize, 55 refSize: refSize, 56 errC: make(chan error), 57 doneC: make(chan struct{}), 58 quitC: make(chan struct{}), 59 } 60 61 return h 62 } 63 64 //将chunkdata存储到哈希存储的chunkstore中并返回引用。 65 //如果hasherstore具有chunkEncryption对象,则数据将被加密。 66 //异步函数,返回时不必存储数据。 67 func (h *hasherStore) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { 68 c := chunkData 69 var encryptionKey encryption.Key 70 if h.toEncrypt { 71 var err error 72 c, encryptionKey, err = h.encryptChunkData(chunkData) 73 if err != nil { 74 return nil, err 75 } 76 } 77 chunk := h.createChunk(c) 78 h.storeChunk(ctx, chunk) 79 80 return Reference(append(chunk.Address(), encryptionKey...)), nil 81 } 82 83 //get返回具有给定引用的块的数据(从HasherStore的ChunkStore中检索)。 84 //如果数据已加密,并且引用包含加密密钥,则将在 85 //返回。 86 func (h *hasherStore) Get(ctx context.Context, ref Reference) (ChunkData, error) { 87 addr, encryptionKey, err := parseReference(ref, h.hashSize) 88 if err != nil { 89 return nil, err 90 } 91 92 chunk, err := h.store.Get(ctx, addr) 93 if err != nil { 94 return nil, err 95 } 96 97 chunkData := ChunkData(chunk.Data()) 98 toDecrypt := (encryptionKey != nil) 99 if toDecrypt { 100 var err error 101 chunkData, err = h.decryptChunkData(chunkData, encryptionKey) 102 if err != nil { 103 return nil, err 104 } 105 } 106 return chunkData, nil 107 } 108 109 //CLOSE表示不再将块与哈希存储放在一起,因此等待 110 //函数可以在存储所有以前放置的块后返回。 111 func (h *hasherStore) Close() { 112 close(h.doneC) 113 } 114 115 //等待返回时间 116 //1)已调用close()函数,并且 117 //2)已放置的所有块已存储 118 func (h *hasherStore) Wait(ctx context.Context) error { 119 defer close(h.quitC) 120 var nrStoredChunks uint64 //存储的块数 121 var done bool 122 doneC := h.doneC 123 for { 124 select { 125 //如果上下文在前面完成,只需返回并返回错误 126 case <-ctx.Done(): 127 return ctx.Err() 128 //如果所有块都已提交,则DONEC将关闭,从那时起,我们只需等待所有块也被存储。 129 case <-doneC: 130 done = true 131 doneC = nil 132 //已存储块,如果err为nil,则成功,因此请增加存储块计数器 133 case err := <-h.errC: 134 if err != nil { 135 return err 136 } 137 nrStoredChunks++ 138 } 139 //如果所有的块都已提交,并且所有的块都已存储,那么我们可以返回 140 if done { 141 if nrStoredChunks >= atomic.LoadUint64(&h.nrChunks) { 142 return nil 143 } 144 } 145 } 146 } 147 148 func (h *hasherStore) createHash(chunkData ChunkData) Address { 149 hasher := h.hashFunc() 150 hasher.ResetWithLength(chunkData[:8]) //8字节长度 151 hasher.Write(chunkData[8:]) //减去8[]字节长度 152 return hasher.Sum(nil) 153 } 154 155 func (h *hasherStore) createChunk(chunkData ChunkData) *chunk { 156 hash := h.createHash(chunkData) 157 chunk := NewChunk(hash, chunkData) 158 return chunk 159 } 160 161 func (h *hasherStore) encryptChunkData(chunkData ChunkData) (ChunkData, encryption.Key, error) { 162 if len(chunkData) < 8 { 163 return nil, nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) 164 } 165 166 key, encryptedSpan, encryptedData, err := h.encrypt(chunkData) 167 if err != nil { 168 return nil, nil, err 169 } 170 c := make(ChunkData, len(encryptedSpan)+len(encryptedData)) 171 copy(c[:8], encryptedSpan) 172 copy(c[8:], encryptedData) 173 return c, key, nil 174 } 175 176 func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryption.Key) (ChunkData, error) { 177 if len(chunkData) < 8 { 178 return nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData)) 179 } 180 181 decryptedSpan, decryptedData, err := h.decrypt(chunkData, encryptionKey) 182 if err != nil { 183 return nil, err 184 } 185 186 //删除刚添加用于填充的多余字节 187 length := ChunkData(decryptedSpan).Size() 188 for length > ch.DefaultSize { 189 length = length + (ch.DefaultSize - 1) 190 length = length / ch.DefaultSize 191 length *= uint64(h.refSize) 192 } 193 194 c := make(ChunkData, length+8) 195 copy(c[:8], decryptedSpan) 196 copy(c[8:], decryptedData[:length]) 197 198 return c, nil 199 } 200 201 func (h *hasherStore) RefSize() int64 { 202 return h.refSize 203 } 204 205 func (h *hasherStore) encrypt(chunkData ChunkData) (encryption.Key, []byte, []byte, error) { 206 key := encryption.GenerateRandomKey(encryption.KeyLength) 207 encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) 208 if err != nil { 209 return nil, nil, nil, err 210 } 211 encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) 212 if err != nil { 213 return nil, nil, nil, err 214 } 215 return key, encryptedSpan, encryptedData, nil 216 } 217 218 func (h *hasherStore) decrypt(chunkData ChunkData, key encryption.Key) ([]byte, []byte, error) { 219 encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8]) 220 if err != nil { 221 return nil, nil, err 222 } 223 encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:]) 224 if err != nil { 225 return nil, nil, err 226 } 227 return encryptedSpan, encryptedData, nil 228 } 229 230 func (h *hasherStore) newSpanEncryption(key encryption.Key) encryption.Encryption { 231 return encryption.New(key, 0, uint32(ch.DefaultSize/h.refSize), sha3.NewLegacyKeccak256) 232 } 233 234 func (h *hasherStore) newDataEncryption(key encryption.Key) encryption.Encryption { 235 return encryption.New(key, int(ch.DefaultSize), 0, sha3.NewLegacyKeccak256) 236 } 237 238 func (h *hasherStore) storeChunk(ctx context.Context, chunk *chunk) { 239 atomic.AddUint64(&h.nrChunks, 1) 240 go func() { 241 select { 242 case h.errC <- h.store.Put(ctx, chunk): 243 case <-h.quitC: 244 } 245 }() 246 } 247 248 func parseReference(ref Reference, hashSize int) (Address, encryption.Key, error) { 249 encryptedRefLength := hashSize + encryption.KeyLength 250 switch len(ref) { 251 case AddressLength: 252 return Address(ref), nil, nil 253 case encryptedRefLength: 254 encKeyIdx := len(ref) - encryption.KeyLength 255 return Address(ref[:encKeyIdx]), encryption.Key(ref[encKeyIdx:]), nil 256 default: 257 return nil, nil, fmt.Errorf("Invalid reference length, expected %v or %v got %v", hashSize, encryptedRefLength, len(ref)) 258 } 259 } 260