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