github.com/ethersphere/bee/v2@v2.2.0/pkg/postage/stampissuer.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package postage
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  	"math/big"
    12  	"path"
    13  	"sync"
    14  	"time"
    15  
    16  	storage "github.com/ethersphere/bee/v2/pkg/storage"
    17  	"github.com/ethersphere/bee/v2/pkg/swarm"
    18  	"github.com/vmihailenco/msgpack/v5"
    19  )
    20  
    21  var (
    22  	// errStampItemMarshalBatchIDInvalid is returned when trying to
    23  	// marshal a stampItem with invalid batchID.
    24  	errStampItemMarshalBatchIDInvalid = errors.New("marshal postage.stampItem: batchID is invalid")
    25  	// errStampItemMarshalChunkAddressInvalid is returned when trying
    26  	// to marshal a stampItem with invalid chunkAddress.
    27  	errStampItemMarshalChunkAddressInvalid = errors.New("marshal postage.stampItem: chunkAddress is invalid")
    28  	// errStampItemUnmarshalInvalidSize is returned when trying
    29  	// to unmarshal buffer with smaller size then is the size
    30  	// of the Item fields.
    31  	errStampItemUnmarshalInvalidSize = errors.New("unmarshal postage.stampItem: invalid size")
    32  )
    33  
    34  const stampItemSize = swarm.HashSize + swarm.HashSize + swarm.StampIndexSize + swarm.StampTimestampSize
    35  
    36  type StampItem struct {
    37  	// Keys.
    38  	BatchID      []byte
    39  	chunkAddress swarm.Address
    40  
    41  	// Values.
    42  	BatchIndex     []byte
    43  	BatchTimestamp []byte
    44  }
    45  
    46  // ID implements the storage.Item interface.
    47  func (si StampItem) ID() string {
    48  	return fmt.Sprintf("%s/%s", string(si.BatchID), si.chunkAddress.String())
    49  }
    50  
    51  // Namespace implements the storage.Item interface.
    52  func (si StampItem) Namespace() string {
    53  	return "stampItem"
    54  }
    55  
    56  // Marshal implements the storage.Item interface.
    57  func (si StampItem) Marshal() ([]byte, error) {
    58  	switch {
    59  	case len(si.BatchID) != swarm.HashSize:
    60  		return nil, errStampItemMarshalBatchIDInvalid
    61  	case len(si.chunkAddress.Bytes()) != swarm.HashSize:
    62  		return nil, errStampItemMarshalChunkAddressInvalid
    63  	}
    64  
    65  	buf := make([]byte, stampItemSize+1)
    66  
    67  	l := 0
    68  	copy(buf[l:l+swarm.HashSize], si.BatchID)
    69  	l += swarm.HashSize
    70  	copy(buf[l:l+swarm.HashSize], si.chunkAddress.Bytes())
    71  	l += swarm.HashSize
    72  	copy(buf[l:l+swarm.StampIndexSize], si.BatchIndex)
    73  	l += swarm.StampIndexSize
    74  	copy(buf[l:l+swarm.StampTimestampSize], si.BatchTimestamp)
    75  
    76  	return buf, nil
    77  }
    78  
    79  // Unmarshal implements the storage.Item interface.
    80  func (si *StampItem) Unmarshal(bytes []byte) error {
    81  	if len(bytes) != stampItemSize+1 {
    82  		return errStampItemUnmarshalInvalidSize
    83  	}
    84  
    85  	ni := new(StampItem)
    86  
    87  	l := 0
    88  	ni.BatchID = append(make([]byte, 0, swarm.HashSize), bytes[l:l+swarm.HashSize]...)
    89  	l += swarm.HashSize
    90  	ni.chunkAddress = swarm.NewAddress(bytes[l : l+swarm.HashSize])
    91  	l += swarm.HashSize
    92  	ni.BatchIndex = append(make([]byte, 0, swarm.StampIndexSize), bytes[l:l+swarm.StampIndexSize]...)
    93  	l += swarm.StampIndexSize
    94  	ni.BatchTimestamp = append(make([]byte, 0, swarm.StampTimestampSize), bytes[l:l+swarm.StampTimestampSize]...)
    95  
    96  	*si = *ni
    97  	return nil
    98  }
    99  
   100  // Clone  implements the storage.Item interface.
   101  func (si *StampItem) Clone() storage.Item {
   102  	if si == nil {
   103  		return nil
   104  	}
   105  	return &StampItem{
   106  		BatchID:        append([]byte(nil), si.BatchID...),
   107  		chunkAddress:   si.chunkAddress.Clone(),
   108  		BatchIndex:     append([]byte(nil), si.BatchIndex...),
   109  		BatchTimestamp: append([]byte(nil), si.BatchTimestamp...),
   110  	}
   111  }
   112  
   113  // String implements the fmt.Stringer interface.
   114  func (si StampItem) String() string {
   115  	return path.Join(si.Namespace(), si.ID())
   116  }
   117  
   118  // stampIssuerData groups related StampIssuer data.
   119  // The data are factored out in order to make
   120  // serialization/deserialization easier and at the same
   121  // time not to export the fields outside of the package.
   122  type stampIssuerData struct {
   123  	Label          string   `msgpack:"label"`          // Label to identify the batch period/importance.
   124  	KeyID          string   `msgpack:"keyID"`          // Owner identity.
   125  	BatchID        []byte   `msgpack:"batchID"`        // The batch stamps are issued from.
   126  	BatchAmount    *big.Int `msgpack:"batchAmount"`    // Amount paid for the batch.
   127  	BatchDepth     uint8    `msgpack:"batchDepth"`     // Batch depth: batch size = 2^{depth}.
   128  	BucketDepth    uint8    `msgpack:"bucketDepth"`    // Bucket depth: the depth of collision Buckets uniformity.
   129  	Buckets        []uint32 `msgpack:"buckets"`        // Collision Buckets: counts per neighbourhoods (limited to 2^{batchdepth-bucketdepth}).
   130  	MaxBucketCount uint32   `msgpack:"maxBucketCount"` // the count of the fullest bucket
   131  	BlockNumber    uint64   `msgpack:"blockNumber"`    // BlockNumber when this batch was created
   132  	ImmutableFlag  bool     `msgpack:"immutableFlag"`  // Specifies immutability of the created batch.
   133  }
   134  
   135  // Clone returns a deep copy of the stampIssuerData.
   136  func (s stampIssuerData) Clone() stampIssuerData {
   137  	return stampIssuerData{
   138  		Label:         s.Label,
   139  		KeyID:         s.KeyID,
   140  		BatchID:       append([]byte(nil), s.BatchID...),
   141  		BatchAmount:   new(big.Int).Set(s.BatchAmount),
   142  		BatchDepth:    s.BatchDepth,
   143  		BucketDepth:   s.BucketDepth,
   144  		Buckets:       append([]uint32(nil), s.Buckets...),
   145  		BlockNumber:   s.BlockNumber,
   146  		ImmutableFlag: s.ImmutableFlag,
   147  	}
   148  }
   149  
   150  // StampIssuer is a local extension of a batch issuing stamps for uploads.
   151  // A StampIssuer instance extends a batch with bucket collision tracking
   152  // embedded in multiple Stampers, can be used concurrently.
   153  type StampIssuer struct {
   154  	data stampIssuerData
   155  	mtx  sync.Mutex
   156  }
   157  
   158  // NewStampIssuer constructs a StampIssuer as an extension of a batch for local
   159  // upload.
   160  //
   161  // BucketDepth must always be smaller than batchDepth otherwise increment() panics.
   162  func NewStampIssuer(label, keyID string, batchID []byte, batchAmount *big.Int, batchDepth, bucketDepth uint8, blockNumber uint64, immutableFlag bool) *StampIssuer {
   163  	return &StampIssuer{
   164  		data: stampIssuerData{
   165  			Label:         label,
   166  			KeyID:         keyID,
   167  			BatchID:       batchID,
   168  			BatchAmount:   batchAmount,
   169  			BatchDepth:    batchDepth,
   170  			BucketDepth:   bucketDepth,
   171  			Buckets:       make([]uint32, 1<<bucketDepth),
   172  			BlockNumber:   blockNumber,
   173  			ImmutableFlag: immutableFlag,
   174  		},
   175  	}
   176  }
   177  
   178  // increment increments the count in the correct collision
   179  // bucket for a newly stamped chunk with given addr address.
   180  // Must be mutex locked before usage.
   181  func (si *StampIssuer) increment(addr swarm.Address) (batchIndex []byte, batchTimestamp []byte, err error) {
   182  	bIdx := toBucket(si.BucketDepth(), addr)
   183  	bCnt := si.data.Buckets[bIdx]
   184  
   185  	if bCnt == si.BucketUpperBound() {
   186  		if si.ImmutableFlag() {
   187  			return nil, nil, ErrBucketFull
   188  		}
   189  
   190  		bCnt = 0
   191  		si.data.Buckets[bIdx] = 0
   192  	}
   193  
   194  	si.data.Buckets[bIdx]++
   195  	if si.data.Buckets[bIdx] > si.data.MaxBucketCount {
   196  		si.data.MaxBucketCount = si.data.Buckets[bIdx]
   197  	}
   198  
   199  	return indexToBytes(bIdx, bCnt), unixTime(), nil
   200  }
   201  
   202  // Label returns the label of the issuer.
   203  func (si *StampIssuer) Label() string {
   204  	return si.data.Label
   205  }
   206  
   207  // MarshalBinary implements the encoding.BinaryMarshaler interface.
   208  func (si *StampIssuer) MarshalBinary() ([]byte, error) {
   209  	return msgpack.Marshal(si.data)
   210  }
   211  
   212  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
   213  func (si *StampIssuer) UnmarshalBinary(data []byte) error {
   214  	return msgpack.Unmarshal(data, &si.data)
   215  }
   216  
   217  // Utilization returns the batch utilization in the form of
   218  // an integer between 0 and 4294967295. Batch fullness can be
   219  // calculated with: max_bucket_value / 2 ^ (batch_depth - bucket_depth)
   220  func (si *StampIssuer) Utilization() uint32 {
   221  	return si.data.MaxBucketCount
   222  }
   223  
   224  // ID returns the BatchID for this batch.
   225  func (si *StampIssuer) ID() []byte {
   226  	id := make([]byte, len(si.data.BatchID))
   227  	copy(id, si.data.BatchID)
   228  	return id
   229  }
   230  
   231  // Depth represent issued batch depth.
   232  func (si *StampIssuer) Depth() uint8 {
   233  	return si.data.BatchDepth
   234  }
   235  
   236  // Amount represent issued batch amount paid.
   237  func (si *StampIssuer) Amount() *big.Int {
   238  	return si.data.BatchAmount
   239  }
   240  
   241  // BucketDepth the depth of collision Buckets uniformity.
   242  func (si *StampIssuer) BucketDepth() uint8 {
   243  	return si.data.BucketDepth
   244  }
   245  
   246  // BucketUpperBound returns the maximum number of collisions
   247  // possible in a bucket given the batch's depth and bucket
   248  // depth.
   249  func (si *StampIssuer) BucketUpperBound() uint32 {
   250  	return 1 << (si.Depth() - si.BucketDepth())
   251  }
   252  
   253  // BlockNumber when this batch was created.
   254  func (si *StampIssuer) BlockNumber() uint64 {
   255  	return si.data.BlockNumber
   256  }
   257  
   258  // ImmutableFlag immutability of the created batch.
   259  func (si *StampIssuer) ImmutableFlag() bool {
   260  	return si.data.ImmutableFlag
   261  }
   262  
   263  func (si *StampIssuer) Buckets() []uint32 {
   264  	si.mtx.Lock()
   265  	defer si.mtx.Unlock()
   266  	b := make([]uint32, len(si.data.Buckets))
   267  	copy(b, si.data.Buckets)
   268  	return b
   269  }
   270  
   271  // StampIssuerItem is a storage.Item implementation for StampIssuer.
   272  type StampIssuerItem struct {
   273  	Issuer *StampIssuer
   274  }
   275  
   276  // NewStampIssuerItem creates a new StampIssuerItem.
   277  func NewStampIssuerItem(ID []byte) *StampIssuerItem {
   278  	return &StampIssuerItem{
   279  		Issuer: &StampIssuer{
   280  			data: stampIssuerData{
   281  				BatchID: ID,
   282  			},
   283  		},
   284  	}
   285  }
   286  
   287  // ID is the batch ID.
   288  func (s *StampIssuerItem) ID() string {
   289  	return string(s.Issuer.ID())
   290  }
   291  
   292  // Namespace returns the storage namespace for a stampIssuer.
   293  func (s *StampIssuerItem) Namespace() string {
   294  	return "StampIssuerItem"
   295  }
   296  
   297  // Marshal marshals the StampIssuerItem into a byte slice.
   298  func (s *StampIssuerItem) Marshal() ([]byte, error) {
   299  	return s.Issuer.MarshalBinary()
   300  }
   301  
   302  // Unmarshal unmarshals a byte slice into a StampIssuerItem.
   303  func (s *StampIssuerItem) Unmarshal(bytes []byte) error {
   304  	issuer := new(StampIssuer)
   305  	err := issuer.UnmarshalBinary(bytes)
   306  	if err != nil {
   307  		return err
   308  	}
   309  	s.Issuer = issuer
   310  	return nil
   311  }
   312  
   313  // Clone returns a clone of StampIssuerItem.
   314  func (s *StampIssuerItem) Clone() storage.Item {
   315  	if s == nil {
   316  		return nil
   317  	}
   318  	return &StampIssuerItem{
   319  		Issuer: &StampIssuer{
   320  			data: s.Issuer.data.Clone(),
   321  		},
   322  	}
   323  }
   324  
   325  // String returns the string representation of a StampIssuerItem.
   326  func (s StampIssuerItem) String() string {
   327  	return path.Join(s.Namespace(), s.ID())
   328  }
   329  
   330  var _ storage.Item = (*StampIssuerItem)(nil)
   331  
   332  // toBucket calculates the index of the collision bucket for a swarm address
   333  // bucket index := collision bucket depth number of bits as bigendian uint32
   334  func toBucket(depth uint8, addr swarm.Address) uint32 {
   335  	return binary.BigEndian.Uint32(addr.Bytes()[:4]) >> (32 - depth)
   336  }
   337  
   338  // indexToBytes creates an uint64 index from
   339  // - bucket index (neighbourhood index, uint32 <2^depth, bytes 2-4)
   340  // - and the within-bucket index (uint32 <2^(batchdepth-bucketdepth), bytes 5-8)
   341  func indexToBytes(bucket, index uint32) []byte {
   342  	buf := make([]byte, IndexSize)
   343  	binary.BigEndian.PutUint32(buf, bucket)
   344  	binary.BigEndian.PutUint32(buf[4:], index)
   345  	return buf
   346  }
   347  
   348  // BucketIndexFromBytes returns bucket index and within-bucket index from supplied bytes.
   349  func BucketIndexFromBytes(buf []byte) (bucket, index uint32) {
   350  	index64 := IndexFromBytes(buf)
   351  	return uint32(index64 >> 32), uint32(index64)
   352  }
   353  
   354  // IndexFromBytes returns uint64 value from supplied bytes
   355  func IndexFromBytes(buf []byte) uint64 {
   356  	return binary.BigEndian.Uint64(buf)
   357  }
   358  
   359  func unixTime() []byte {
   360  	buf := make([]byte, 8)
   361  	binary.BigEndian.PutUint64(buf, uint64(time.Now().UnixNano()))
   362  	return buf
   363  }
   364  
   365  // TimestampFromBytes returns uint64 value from supplied bytes
   366  func TimestampFromBytes(buf []byte) uint64 {
   367  	return binary.BigEndian.Uint64(buf)
   368  }