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 }