github.com/divan/go-ethereum@v1.8.14-0.20180820134928-1de9ada4016d/swarm/storage/types.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package storage
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"crypto"
    23  	"crypto/rand"
    24  	"encoding/binary"
    25  	"fmt"
    26  	"hash"
    27  	"io"
    28  	"sync"
    29  
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/crypto/sha3"
    32  	"github.com/ethereum/go-ethereum/swarm/bmt"
    33  	"github.com/ethereum/go-ethereum/swarm/chunk"
    34  )
    35  
    36  const MaxPO = 16
    37  const KeyLength = 32
    38  
    39  type Hasher func() hash.Hash
    40  type SwarmHasher func() SwarmHash
    41  
    42  // Peer is the recorded as Source on the chunk
    43  // should probably not be here? but network should wrap chunk object
    44  type Peer interface{}
    45  
    46  type Address []byte
    47  
    48  func (a Address) Size() uint {
    49  	return uint(len(a))
    50  }
    51  
    52  func (a Address) isEqual(y Address) bool {
    53  	return bytes.Equal(a, y)
    54  }
    55  
    56  func (a Address) bits(i, j uint) uint {
    57  	ii := i >> 3
    58  	jj := i & 7
    59  	if ii >= a.Size() {
    60  		return 0
    61  	}
    62  
    63  	if jj+j <= 8 {
    64  		return uint((a[ii] >> jj) & ((1 << j) - 1))
    65  	}
    66  
    67  	res := uint(a[ii] >> jj)
    68  	jj = 8 - jj
    69  	j -= jj
    70  	for j != 0 {
    71  		ii++
    72  		if j < 8 {
    73  			res += uint(a[ii]&((1<<j)-1)) << jj
    74  			return res
    75  		}
    76  		res += uint(a[ii]) << jj
    77  		jj += 8
    78  		j -= 8
    79  	}
    80  	return res
    81  }
    82  
    83  func Proximity(one, other []byte) (ret int) {
    84  	b := (MaxPO-1)/8 + 1
    85  	if b > len(one) {
    86  		b = len(one)
    87  	}
    88  	m := 8
    89  	for i := 0; i < b; i++ {
    90  		oxo := one[i] ^ other[i]
    91  		if i == b-1 {
    92  			m = MaxPO % 8
    93  		}
    94  		for j := 0; j < m; j++ {
    95  			if (oxo>>uint8(7-j))&0x01 != 0 {
    96  				return i*8 + j
    97  			}
    98  		}
    99  	}
   100  	return MaxPO
   101  }
   102  
   103  func IsZeroAddr(addr Address) bool {
   104  	return len(addr) == 0 || bytes.Equal(addr, ZeroAddr)
   105  }
   106  
   107  var ZeroAddr = Address(common.Hash{}.Bytes())
   108  
   109  func MakeHashFunc(hash string) SwarmHasher {
   110  	switch hash {
   111  	case "SHA256":
   112  		return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} }
   113  	case "SHA3":
   114  		return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} }
   115  	case "BMT":
   116  		return func() SwarmHash {
   117  			hasher := sha3.NewKeccak256
   118  			hasherSize := hasher().Size()
   119  			segmentCount := chunk.DefaultSize / hasherSize
   120  			pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize)
   121  			return bmt.New(pool)
   122  		}
   123  	}
   124  	return nil
   125  }
   126  
   127  func (a Address) Hex() string {
   128  	return fmt.Sprintf("%064x", []byte(a[:]))
   129  }
   130  
   131  func (a Address) Log() string {
   132  	if len(a[:]) < 8 {
   133  		return fmt.Sprintf("%x", []byte(a[:]))
   134  	}
   135  	return fmt.Sprintf("%016x", []byte(a[:8]))
   136  }
   137  
   138  func (a Address) String() string {
   139  	return fmt.Sprintf("%064x", []byte(a)[:])
   140  }
   141  
   142  func (a Address) MarshalJSON() (out []byte, err error) {
   143  	return []byte(`"` + a.String() + `"`), nil
   144  }
   145  
   146  func (a *Address) UnmarshalJSON(value []byte) error {
   147  	s := string(value)
   148  	*a = make([]byte, 32)
   149  	h := common.Hex2Bytes(s[1 : len(s)-1])
   150  	copy(*a, h)
   151  	return nil
   152  }
   153  
   154  type AddressCollection []Address
   155  
   156  func NewAddressCollection(l int) AddressCollection {
   157  	return make(AddressCollection, l)
   158  }
   159  
   160  func (c AddressCollection) Len() int {
   161  	return len(c)
   162  }
   163  
   164  func (c AddressCollection) Less(i, j int) bool {
   165  	return bytes.Compare(c[i], c[j]) == -1
   166  }
   167  
   168  func (c AddressCollection) Swap(i, j int) {
   169  	c[i], c[j] = c[j], c[i]
   170  }
   171  
   172  // Chunk also serves as a request object passed to ChunkStores
   173  // in case it is a retrieval request, Data is nil and Size is 0
   174  // Note that Size is not the size of the data chunk, which is Data.Size()
   175  // but the size of the subtree encoded in the chunk
   176  // 0 if request, to be supplied by the dpa
   177  type Chunk struct {
   178  	Addr  Address // always
   179  	SData []byte  // nil if request, to be supplied by dpa
   180  	Size  int64   // size of the data covered by the subtree encoded in this chunk
   181  	//Source   Peer           // peer
   182  	C          chan bool // to signal data delivery by the dpa
   183  	ReqC       chan bool // to signal the request done
   184  	dbStoredC  chan bool // never remove a chunk from memStore before it is written to dbStore
   185  	dbStored   bool
   186  	dbStoredMu *sync.Mutex
   187  	errored    error // flag which is set when the chunk request has errored or timeouted
   188  	erroredMu  sync.Mutex
   189  }
   190  
   191  func (c *Chunk) SetErrored(err error) {
   192  	c.erroredMu.Lock()
   193  	defer c.erroredMu.Unlock()
   194  
   195  	c.errored = err
   196  }
   197  
   198  func (c *Chunk) GetErrored() error {
   199  	c.erroredMu.Lock()
   200  	defer c.erroredMu.Unlock()
   201  
   202  	return c.errored
   203  }
   204  
   205  func NewChunk(addr Address, reqC chan bool) *Chunk {
   206  	return &Chunk{
   207  		Addr:       addr,
   208  		ReqC:       reqC,
   209  		dbStoredC:  make(chan bool),
   210  		dbStoredMu: &sync.Mutex{},
   211  	}
   212  }
   213  
   214  func (c *Chunk) markAsStored() {
   215  	c.dbStoredMu.Lock()
   216  	defer c.dbStoredMu.Unlock()
   217  
   218  	if !c.dbStored {
   219  		close(c.dbStoredC)
   220  		c.dbStored = true
   221  	}
   222  }
   223  
   224  func (c *Chunk) WaitToStore() error {
   225  	<-c.dbStoredC
   226  	return c.GetErrored()
   227  }
   228  
   229  func GenerateRandomChunk(dataSize int64) *Chunk {
   230  	return GenerateRandomChunks(dataSize, 1)[0]
   231  }
   232  
   233  func GenerateRandomChunks(dataSize int64, count int) (chunks []*Chunk) {
   234  	var i int
   235  	hasher := MakeHashFunc(DefaultHash)()
   236  	if dataSize > chunk.DefaultSize {
   237  		dataSize = chunk.DefaultSize
   238  	}
   239  
   240  	for i = 0; i < count; i++ {
   241  		chunks = append(chunks, NewChunk(nil, nil))
   242  		chunks[i].SData = make([]byte, dataSize+8)
   243  		rand.Read(chunks[i].SData)
   244  		binary.LittleEndian.PutUint64(chunks[i].SData[:8], uint64(dataSize))
   245  		hasher.ResetWithLength(chunks[i].SData[:8])
   246  		hasher.Write(chunks[i].SData[8:])
   247  		chunks[i].Addr = make([]byte, 32)
   248  		copy(chunks[i].Addr, hasher.Sum(nil))
   249  	}
   250  
   251  	return chunks
   252  }
   253  
   254  // Size, Seek, Read, ReadAt
   255  type LazySectionReader interface {
   256  	Context() context.Context
   257  	Size(context.Context, chan bool) (int64, error)
   258  	io.Seeker
   259  	io.Reader
   260  	io.ReaderAt
   261  }
   262  
   263  type LazyTestSectionReader struct {
   264  	*io.SectionReader
   265  }
   266  
   267  func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) {
   268  	return r.SectionReader.Size(), nil
   269  }
   270  
   271  func (r *LazyTestSectionReader) Context() context.Context {
   272  	return context.TODO()
   273  }
   274  
   275  type StoreParams struct {
   276  	Hash                       SwarmHasher `toml:"-"`
   277  	DbCapacity                 uint64
   278  	CacheCapacity              uint
   279  	ChunkRequestsCacheCapacity uint
   280  	BaseKey                    []byte
   281  }
   282  
   283  func NewDefaultStoreParams() *StoreParams {
   284  	return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, defaultChunkRequestsCacheCapacity, nil, nil)
   285  }
   286  
   287  func NewStoreParams(ldbCap uint64, cacheCap uint, requestsCap uint, hash SwarmHasher, basekey []byte) *StoreParams {
   288  	if basekey == nil {
   289  		basekey = make([]byte, 32)
   290  	}
   291  	if hash == nil {
   292  		hash = MakeHashFunc(DefaultHash)
   293  	}
   294  	return &StoreParams{
   295  		Hash:                       hash,
   296  		DbCapacity:                 ldbCap,
   297  		CacheCapacity:              cacheCap,
   298  		ChunkRequestsCacheCapacity: requestsCap,
   299  		BaseKey:                    basekey,
   300  	}
   301  }
   302  
   303  type ChunkData []byte
   304  
   305  type Reference []byte
   306  
   307  // Putter is responsible to store data and create a reference for it
   308  type Putter interface {
   309  	Put(context.Context, ChunkData) (Reference, error)
   310  	// RefSize returns the length of the Reference created by this Putter
   311  	RefSize() int64
   312  	// Close is to indicate that no more chunk data will be Put on this Putter
   313  	Close()
   314  	// Wait returns if all data has been store and the Close() was called.
   315  	Wait(context.Context) error
   316  }
   317  
   318  // Getter is an interface to retrieve a chunk's data by its reference
   319  type Getter interface {
   320  	Get(context.Context, Reference) (ChunkData, error)
   321  }
   322  
   323  // NOTE: this returns invalid data if chunk is encrypted
   324  func (c ChunkData) Size() int64 {
   325  	return int64(binary.LittleEndian.Uint64(c[:8]))
   326  }
   327  
   328  func (c ChunkData) Data() []byte {
   329  	return c[8:]
   330  }
   331  
   332  type ChunkValidator interface {
   333  	Validate(addr Address, data []byte) bool
   334  }
   335  
   336  // Provides method for validation of content address in chunks
   337  // Holds the corresponding hasher to create the address
   338  type ContentAddressValidator struct {
   339  	Hasher SwarmHasher
   340  }
   341  
   342  // Constructor
   343  func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator {
   344  	return &ContentAddressValidator{
   345  		Hasher: hasher,
   346  	}
   347  }
   348  
   349  // Validate that the given key is a valid content address for the given data
   350  func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool {
   351  	if l := len(data); l < 9 || l > chunk.DefaultSize+8 {
   352  		return false
   353  	}
   354  
   355  	hasher := v.Hasher()
   356  	hasher.ResetWithLength(data[:8])
   357  	hasher.Write(data[8:])
   358  	hash := hasher.Sum(nil)
   359  
   360  	return bytes.Equal(hash, addr[:])
   361  }