github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/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  	"io/ioutil"
    29  
    30  	"github.com/FusionFoundation/efsn/common"
    31  	"github.com/FusionFoundation/efsn/crypto/sha3"
    32  	"github.com/FusionFoundation/efsn/swarm/bmt"
    33  	ch "github.com/FusionFoundation/efsn/swarm/chunk"
    34  )
    35  
    36  const MaxPO = 16
    37  const AddressLength = 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 := ch.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 interface implemented by context.Contexts and data chunks
   173  type Chunk interface {
   174  	Address() Address
   175  	Payload() []byte
   176  	SpanBytes() []byte
   177  	Span() int64
   178  	Data() []byte
   179  }
   180  
   181  type chunk struct {
   182  	addr  Address
   183  	sdata []byte
   184  	span  int64
   185  }
   186  
   187  func NewChunk(addr Address, data []byte) *chunk {
   188  	return &chunk{
   189  		addr:  addr,
   190  		sdata: data,
   191  		span:  -1,
   192  	}
   193  }
   194  
   195  func (c *chunk) Address() Address {
   196  	return c.addr
   197  }
   198  
   199  func (c *chunk) SpanBytes() []byte {
   200  	return c.sdata[:8]
   201  }
   202  
   203  func (c *chunk) Span() int64 {
   204  	if c.span == -1 {
   205  		c.span = int64(binary.LittleEndian.Uint64(c.sdata[:8]))
   206  	}
   207  	return c.span
   208  }
   209  
   210  func (c *chunk) Data() []byte {
   211  	return c.sdata
   212  }
   213  
   214  func (c *chunk) Payload() []byte {
   215  	return c.sdata[8:]
   216  }
   217  
   218  // String() for pretty printing
   219  func (self *chunk) String() string {
   220  	return fmt.Sprintf("Address: %v TreeSize: %v Chunksize: %v", self.addr.Log(), self.span, len(self.sdata))
   221  }
   222  
   223  func GenerateRandomChunk(dataSize int64) Chunk {
   224  	hasher := MakeHashFunc(DefaultHash)()
   225  	sdata := make([]byte, dataSize+8)
   226  	rand.Read(sdata[8:])
   227  	binary.LittleEndian.PutUint64(sdata[:8], uint64(dataSize))
   228  	hasher.ResetWithLength(sdata[:8])
   229  	hasher.Write(sdata[8:])
   230  	return NewChunk(hasher.Sum(nil), sdata)
   231  }
   232  
   233  func GenerateRandomChunks(dataSize int64, count int) (chunks []Chunk) {
   234  	if dataSize > ch.DefaultSize {
   235  		dataSize = ch.DefaultSize
   236  	}
   237  	for i := 0; i < count; i++ {
   238  		ch := GenerateRandomChunk(ch.DefaultSize)
   239  		chunks = append(chunks, ch)
   240  	}
   241  	return chunks
   242  }
   243  
   244  func GenerateRandomData(l int) (r io.Reader, slice []byte) {
   245  	slice, err := ioutil.ReadAll(io.LimitReader(rand.Reader, int64(l)))
   246  	if err != nil {
   247  		panic("rand error")
   248  	}
   249  	// log.Warn("generate random data", "len", len(slice), "data", common.Bytes2Hex(slice))
   250  	r = io.LimitReader(bytes.NewReader(slice), int64(l))
   251  	return r, slice
   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  	BaseKey       []byte
   280  }
   281  
   282  func NewDefaultStoreParams() *StoreParams {
   283  	return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, nil, nil)
   284  }
   285  
   286  func NewStoreParams(ldbCap uint64, cacheCap uint, hash SwarmHasher, basekey []byte) *StoreParams {
   287  	if basekey == nil {
   288  		basekey = make([]byte, 32)
   289  	}
   290  	if hash == nil {
   291  		hash = MakeHashFunc(DefaultHash)
   292  	}
   293  	return &StoreParams{
   294  		Hash:          hash,
   295  		DbCapacity:    ldbCap,
   296  		CacheCapacity: cacheCap,
   297  		BaseKey:       basekey,
   298  	}
   299  }
   300  
   301  type ChunkData []byte
   302  
   303  type Reference []byte
   304  
   305  // Putter is responsible to store data and create a reference for it
   306  type Putter interface {
   307  	Put(context.Context, ChunkData) (Reference, error)
   308  	// RefSize returns the length of the Reference created by this Putter
   309  	RefSize() int64
   310  	// Close is to indicate that no more chunk data will be Put on this Putter
   311  	Close()
   312  	// Wait returns if all data has been store and the Close() was called.
   313  	Wait(context.Context) error
   314  }
   315  
   316  // Getter is an interface to retrieve a chunk's data by its reference
   317  type Getter interface {
   318  	Get(context.Context, Reference) (ChunkData, error)
   319  }
   320  
   321  // NOTE: this returns invalid data if chunk is encrypted
   322  func (c ChunkData) Size() uint64 {
   323  	return binary.LittleEndian.Uint64(c[:8])
   324  }
   325  
   326  func (c ChunkData) Data() []byte {
   327  	return c[8:]
   328  }
   329  
   330  type ChunkValidator interface {
   331  	Validate(addr Address, data []byte) bool
   332  }
   333  
   334  // Provides method for validation of content address in chunks
   335  // Holds the corresponding hasher to create the address
   336  type ContentAddressValidator struct {
   337  	Hasher SwarmHasher
   338  }
   339  
   340  // Constructor
   341  func NewContentAddressValidator(hasher SwarmHasher) *ContentAddressValidator {
   342  	return &ContentAddressValidator{
   343  		Hasher: hasher,
   344  	}
   345  }
   346  
   347  // Validate that the given key is a valid content address for the given data
   348  func (v *ContentAddressValidator) Validate(addr Address, data []byte) bool {
   349  	if l := len(data); l < 9 || l > ch.DefaultSize+8 {
   350  		// log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l)
   351  		return false
   352  	}
   353  
   354  	hasher := v.Hasher()
   355  	hasher.ResetWithLength(data[:8])
   356  	hasher.Write(data[8:])
   357  	hash := hasher.Sum(nil)
   358  
   359  	return bytes.Equal(hash, addr[:])
   360  }
   361  
   362  type ChunkStore interface {
   363  	Put(ctx context.Context, ch Chunk) (err error)
   364  	Get(rctx context.Context, ref Address) (ch Chunk, err error)
   365  	Close()
   366  }
   367  
   368  // SyncChunkStore is a ChunkStore which supports syncing
   369  type SyncChunkStore interface {
   370  	ChunkStore
   371  	BinIndex(po uint8) uint64
   372  	Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error
   373  	FetchFunc(ctx context.Context, ref Address) func(context.Context) error
   374  }
   375  
   376  // FakeChunkStore doesn't store anything, just implements the ChunkStore interface
   377  // It can be used to inject into a hasherStore if you don't want to actually store data just do the
   378  // hashing
   379  type FakeChunkStore struct {
   380  }
   381  
   382  // Put doesn't store anything it is just here to implement ChunkStore
   383  func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error {
   384  	return nil
   385  }
   386  
   387  // Gut doesn't store anything it is just here to implement ChunkStore
   388  func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
   389  	panic("FakeChunkStore doesn't support Get")
   390  }
   391  
   392  // Close doesn't store anything it is just here to implement ChunkStore
   393  func (f *FakeChunkStore) Close() {
   394  }