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