github.com/hyperion-hyn/go-ethereum@v2.4.0+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  
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/crypto/sha3"
    31  	"github.com/ethereum/go-ethereum/swarm/bmt"
    32  	ch "github.com/ethereum/go-ethereum/swarm/chunk"
    33  )
    34  
    35  const MaxPO = 16
    36  const AddressLength = 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  // Proximity(x, y) returns the proximity order of the MSB distance between x and y
    83  //
    84  // The distance metric MSB(x, y) of two equal length byte sequences x an y is the
    85  // value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed.
    86  // the binary cast is big endian: most significant bit first (=MSB).
    87  //
    88  // Proximity(x, y) is a discrete logarithmic scaling of the MSB distance.
    89  // It is defined as the reverse rank of the integer part of the base 2
    90  // logarithm of the distance.
    91  // It is calculated by counting the number of common leading zeros in the (MSB)
    92  // binary representation of the x^y.
    93  //
    94  // (0 farthest, 255 closest, 256 self)
    95  func Proximity(one, other []byte) (ret int) {
    96  	b := (MaxPO-1)/8 + 1
    97  	if b > len(one) {
    98  		b = len(one)
    99  	}
   100  	m := 8
   101  	for i := 0; i < b; i++ {
   102  		oxo := one[i] ^ other[i]
   103  		if i == b-1 {
   104  			m = MaxPO % 8
   105  		}
   106  		for j := 0; j < m; j++ {
   107  			if (oxo>>uint8(7-j))&0x01 != 0 {
   108  				return i*8 + j
   109  			}
   110  		}
   111  	}
   112  	return MaxPO
   113  }
   114  
   115  func IsZeroAddr(addr Address) bool {
   116  	return len(addr) == 0 || bytes.Equal(addr, ZeroAddr)
   117  }
   118  
   119  var ZeroAddr = Address(common.Hash{}.Bytes())
   120  
   121  func MakeHashFunc(hash string) SwarmHasher {
   122  	switch hash {
   123  	case "SHA256":
   124  		return func() SwarmHash { return &HashWithLength{crypto.SHA256.New()} }
   125  	case "SHA3":
   126  		return func() SwarmHash { return &HashWithLength{sha3.NewKeccak256()} }
   127  	case "BMT":
   128  		return func() SwarmHash {
   129  			hasher := sha3.NewKeccak256
   130  			hasherSize := hasher().Size()
   131  			segmentCount := ch.DefaultSize / hasherSize
   132  			pool := bmt.NewTreePool(hasher, segmentCount, bmt.PoolSize)
   133  			return bmt.New(pool)
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  func (a Address) Hex() string {
   140  	return fmt.Sprintf("%064x", []byte(a[:]))
   141  }
   142  
   143  func (a Address) Log() string {
   144  	if len(a[:]) < 8 {
   145  		return fmt.Sprintf("%x", []byte(a[:]))
   146  	}
   147  	return fmt.Sprintf("%016x", []byte(a[:8]))
   148  }
   149  
   150  func (a Address) String() string {
   151  	return fmt.Sprintf("%064x", []byte(a))
   152  }
   153  
   154  func (a Address) MarshalJSON() (out []byte, err error) {
   155  	return []byte(`"` + a.String() + `"`), nil
   156  }
   157  
   158  func (a *Address) UnmarshalJSON(value []byte) error {
   159  	s := string(value)
   160  	*a = make([]byte, 32)
   161  	h := common.Hex2Bytes(s[1 : len(s)-1])
   162  	copy(*a, h)
   163  	return nil
   164  }
   165  
   166  type AddressCollection []Address
   167  
   168  func NewAddressCollection(l int) AddressCollection {
   169  	return make(AddressCollection, l)
   170  }
   171  
   172  func (c AddressCollection) Len() int {
   173  	return len(c)
   174  }
   175  
   176  func (c AddressCollection) Less(i, j int) bool {
   177  	return bytes.Compare(c[i], c[j]) == -1
   178  }
   179  
   180  func (c AddressCollection) Swap(i, j int) {
   181  	c[i], c[j] = c[j], c[i]
   182  }
   183  
   184  // Chunk interface implemented by context.Contexts and data chunks
   185  type Chunk interface {
   186  	Address() Address
   187  	Payload() []byte
   188  	SpanBytes() []byte
   189  	Span() int64
   190  	Data() []byte
   191  }
   192  
   193  type chunk struct {
   194  	addr  Address
   195  	sdata []byte
   196  	span  int64
   197  }
   198  
   199  func NewChunk(addr Address, data []byte) *chunk {
   200  	return &chunk{
   201  		addr:  addr,
   202  		sdata: data,
   203  		span:  -1,
   204  	}
   205  }
   206  
   207  func (c *chunk) Address() Address {
   208  	return c.addr
   209  }
   210  
   211  func (c *chunk) SpanBytes() []byte {
   212  	return c.sdata[:8]
   213  }
   214  
   215  func (c *chunk) Span() int64 {
   216  	if c.span == -1 {
   217  		c.span = int64(binary.LittleEndian.Uint64(c.sdata[:8]))
   218  	}
   219  	return c.span
   220  }
   221  
   222  func (c *chunk) Data() []byte {
   223  	return c.sdata
   224  }
   225  
   226  func (c *chunk) Payload() []byte {
   227  	return c.sdata[8:]
   228  }
   229  
   230  // String() for pretty printing
   231  func (self *chunk) String() string {
   232  	return fmt.Sprintf("Address: %v TreeSize: %v Chunksize: %v", self.addr.Log(), self.span, len(self.sdata))
   233  }
   234  
   235  func GenerateRandomChunk(dataSize int64) Chunk {
   236  	hasher := MakeHashFunc(DefaultHash)()
   237  	sdata := make([]byte, dataSize+8)
   238  	rand.Read(sdata[8:])
   239  	binary.LittleEndian.PutUint64(sdata[:8], uint64(dataSize))
   240  	hasher.ResetWithLength(sdata[:8])
   241  	hasher.Write(sdata[8:])
   242  	return NewChunk(hasher.Sum(nil), sdata)
   243  }
   244  
   245  func GenerateRandomChunks(dataSize int64, count int) (chunks []Chunk) {
   246  	for i := 0; i < count; i++ {
   247  		ch := GenerateRandomChunk(dataSize)
   248  		chunks = append(chunks, ch)
   249  	}
   250  	return chunks
   251  }
   252  
   253  // Size, Seek, Read, ReadAt
   254  type LazySectionReader interface {
   255  	Context() context.Context
   256  	Size(context.Context, chan bool) (int64, error)
   257  	io.Seeker
   258  	io.Reader
   259  	io.ReaderAt
   260  }
   261  
   262  type LazyTestSectionReader struct {
   263  	*io.SectionReader
   264  }
   265  
   266  func (r *LazyTestSectionReader) Size(context.Context, chan bool) (int64, error) {
   267  	return r.SectionReader.Size(), nil
   268  }
   269  
   270  func (r *LazyTestSectionReader) Context() context.Context {
   271  	return context.TODO()
   272  }
   273  
   274  type StoreParams struct {
   275  	Hash          SwarmHasher `toml:"-"`
   276  	DbCapacity    uint64
   277  	CacheCapacity uint
   278  	BaseKey       []byte
   279  }
   280  
   281  func NewDefaultStoreParams() *StoreParams {
   282  	return NewStoreParams(defaultLDBCapacity, defaultCacheCapacity, nil, nil)
   283  }
   284  
   285  func NewStoreParams(ldbCap uint64, cacheCap uint, hash SwarmHasher, basekey []byte) *StoreParams {
   286  	if basekey == nil {
   287  		basekey = make([]byte, 32)
   288  	}
   289  	if hash == nil {
   290  		hash = MakeHashFunc(DefaultHash)
   291  	}
   292  	return &StoreParams{
   293  		Hash:          hash,
   294  		DbCapacity:    ldbCap,
   295  		CacheCapacity: cacheCap,
   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() uint64 {
   322  	return 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  	if l := len(data); l < 9 || l > ch.DefaultSize+8 {
   349  		// log.Error("invalid chunk size", "chunk", addr.Hex(), "size", l)
   350  		return false
   351  	}
   352  
   353  	hasher := v.Hasher()
   354  	hasher.ResetWithLength(data[:8])
   355  	hasher.Write(data[8:])
   356  	hash := hasher.Sum(nil)
   357  
   358  	return bytes.Equal(hash, addr[:])
   359  }
   360  
   361  type ChunkStore interface {
   362  	Put(ctx context.Context, ch Chunk) (err error)
   363  	Get(rctx context.Context, ref Address) (ch Chunk, err error)
   364  	Close()
   365  }
   366  
   367  // SyncChunkStore is a ChunkStore which supports syncing
   368  type SyncChunkStore interface {
   369  	ChunkStore
   370  	BinIndex(po uint8) uint64
   371  	Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error
   372  	FetchFunc(ctx context.Context, ref Address) func(context.Context) error
   373  }
   374  
   375  // FakeChunkStore doesn't store anything, just implements the ChunkStore interface
   376  // It can be used to inject into a hasherStore if you don't want to actually store data just do the
   377  // hashing
   378  type FakeChunkStore struct {
   379  }
   380  
   381  // Put doesn't store anything it is just here to implement ChunkStore
   382  func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error {
   383  	return nil
   384  }
   385  
   386  // Gut doesn't store anything it is just here to implement ChunkStore
   387  func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
   388  	panic("FakeChunkStore doesn't support Get")
   389  }
   390  
   391  // Close doesn't store anything it is just here to implement ChunkStore
   392  func (f *FakeChunkStore) Close() {
   393  }