github.com/ethersphere/bee/v2@v2.2.0/pkg/postage/stamper.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  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/crypto"
    13  	"github.com/ethersphere/bee/v2/pkg/storage"
    14  	"github.com/ethersphere/bee/v2/pkg/swarm"
    15  )
    16  
    17  var (
    18  	// ErrBucketFull is the error when a collision bucket is full.
    19  	ErrBucketFull = errors.New("bucket full")
    20  )
    21  
    22  // Stamper can issue stamps from the given address of chunk.
    23  type Stamper interface {
    24  	Stamp(swarm.Address) (*Stamp, error)
    25  }
    26  
    27  // stamper connects a stampissuer with a signer.
    28  // A stamper is created for each upload session.
    29  type stamper struct {
    30  	store  storage.Store
    31  	issuer *StampIssuer
    32  	signer crypto.Signer
    33  }
    34  
    35  // NewStamper constructs a Stamper.
    36  func NewStamper(store storage.Store, issuer *StampIssuer, signer crypto.Signer) Stamper {
    37  	return &stamper{store, issuer, signer}
    38  }
    39  
    40  // Stamp takes chunk, see if the chunk can be included in the batch and
    41  // signs it with the owner of the batch of this Stamp issuer.
    42  func (st *stamper) Stamp(addr swarm.Address) (*Stamp, error) {
    43  	st.issuer.mtx.Lock()
    44  	defer st.issuer.mtx.Unlock()
    45  
    46  	item := &StampItem{
    47  		BatchID:      st.issuer.data.BatchID,
    48  		chunkAddress: addr,
    49  	}
    50  	switch err := st.store.Get(item); {
    51  	case err == nil:
    52  		item.BatchTimestamp = unixTime()
    53  		if err = st.store.Put(item); err != nil {
    54  			return nil, err
    55  		}
    56  	case errors.Is(err, storage.ErrNotFound):
    57  		item.BatchIndex, item.BatchTimestamp, err = st.issuer.increment(addr)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		if err := st.store.Put(item); err != nil {
    62  			return nil, err
    63  		}
    64  	default:
    65  		return nil, fmt.Errorf("get stamp for %s: %w", item, err)
    66  	}
    67  
    68  	toSign, err := ToSignDigest(
    69  		addr.Bytes(),
    70  		st.issuer.data.BatchID,
    71  		item.BatchIndex,
    72  		item.BatchTimestamp,
    73  	)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	sig, err := st.signer.Sign(toSign)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	return NewStamp(st.issuer.data.BatchID, item.BatchIndex, item.BatchTimestamp, sig), nil
    82  }
    83  
    84  type presignedStamper struct {
    85  	stamp *Stamp
    86  	owner []byte
    87  }
    88  
    89  func NewPresignedStamper(stamp *Stamp, owner []byte) Stamper {
    90  	return &presignedStamper{stamp, owner}
    91  }
    92  
    93  func (st *presignedStamper) Stamp(addr swarm.Address) (*Stamp, error) {
    94  	// check stored stamp is against the chunk address
    95  	// Recover the public key from the signature
    96  	signerAddr, err := RecoverBatchOwner(addr, st.stamp)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	if !bytes.Equal(st.owner, signerAddr) {
   102  		return nil, ErrInvalidBatchSignature
   103  	}
   104  
   105  	return st.stamp, nil
   106  }