github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/internal/blocklist/blocklist.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 blocklist
     6  
     7  import (
     8  	"errors"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/p2p"
    13  	"github.com/ethersphere/bee/v2/pkg/storage"
    14  	"github.com/ethersphere/bee/v2/pkg/swarm"
    15  )
    16  
    17  var keyPrefix = "blocklist-"
    18  
    19  type currentTimeFn = func() time.Time
    20  
    21  type Blocklist struct {
    22  	store         storage.StateStorer
    23  	currentTimeFn currentTimeFn
    24  }
    25  
    26  func NewBlocklist(store storage.StateStorer) *Blocklist {
    27  	return &Blocklist{
    28  		store:         store,
    29  		currentTimeFn: time.Now,
    30  	}
    31  }
    32  
    33  type entry struct {
    34  	Timestamp time.Time `json:"timestamp"`
    35  	Duration  string    `json:"duration"` // Duration is string because the time.Duration does not implement MarshalJSON/UnmarshalJSON methods.
    36  	Reason    string    `json:"reason"`
    37  	Full      bool      `json:"full"`
    38  }
    39  
    40  func (b *Blocklist) Exists(overlay swarm.Address) (bool, error) {
    41  	key := generateKey(overlay)
    42  	e, duration, err := b.get(key)
    43  	if err != nil {
    44  		if errors.Is(err, storage.ErrNotFound) {
    45  			return false, nil
    46  		}
    47  
    48  		return false, err
    49  	}
    50  
    51  	if b.currentTimeFn().Sub(e.Timestamp) > duration && duration != 0 {
    52  		_ = b.store.Delete(key)
    53  		return false, nil
    54  	}
    55  
    56  	return true, nil
    57  }
    58  
    59  func (b *Blocklist) Add(overlay swarm.Address, duration time.Duration, reason string, full bool) (err error) {
    60  	key := generateKey(overlay)
    61  	_, d, err := b.get(key)
    62  	if err != nil {
    63  		if !errors.Is(err, storage.ErrNotFound) {
    64  			return err
    65  		}
    66  	}
    67  
    68  	// if peer is already blacklisted, blacklist it for the maximum amount of time
    69  	if duration < d && duration != 0 || d == 0 {
    70  		duration = d
    71  	}
    72  
    73  	return b.store.Put(key, &entry{
    74  		Timestamp: b.currentTimeFn(),
    75  		Duration:  duration.String(),
    76  		Reason:    reason,
    77  		Full:      full,
    78  	})
    79  }
    80  
    81  // Peers returns all currently blocklisted peers.
    82  func (b *Blocklist) Peers() ([]p2p.BlockListedPeer, error) {
    83  	var peers []p2p.BlockListedPeer
    84  	if err := b.store.Iterate(keyPrefix, func(k, v []byte) (bool, error) {
    85  		if !strings.HasPrefix(string(k), keyPrefix) {
    86  			return true, nil
    87  		}
    88  		addr, err := unmarshalKey(string(k))
    89  		if err != nil {
    90  			return true, err
    91  		}
    92  
    93  		entry, d, err := b.get(string(k))
    94  		if err != nil {
    95  			return true, err
    96  		}
    97  
    98  		if b.currentTimeFn().Sub(entry.Timestamp) > d && d != 0 {
    99  			// skip to the next item
   100  			return false, nil
   101  		}
   102  
   103  		p := p2p.BlockListedPeer{
   104  			Peer: p2p.Peer{
   105  				Address:  addr,
   106  				FullNode: entry.Full,
   107  			},
   108  			Duration: d,
   109  			Reason:   entry.Reason,
   110  		}
   111  		peers = append(peers, p)
   112  		return false, nil
   113  	}); err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	return peers, nil
   118  }
   119  
   120  func (b *Blocklist) get(key string) (entry, time.Duration, error) {
   121  	var e entry
   122  	err := b.store.Get(key, &e)
   123  	if err != nil {
   124  		return e, -1, err
   125  	}
   126  
   127  	dur, err := time.ParseDuration(e.Duration)
   128  	if err != nil {
   129  		return e, -1, err
   130  	}
   131  
   132  	return e, dur, nil
   133  }
   134  
   135  func generateKey(overlay swarm.Address) string {
   136  	return keyPrefix + overlay.String()
   137  }
   138  
   139  func unmarshalKey(s string) (swarm.Address, error) {
   140  	addr := s[len(keyPrefix):] // trim prefix
   141  	return swarm.ParseHexAddress(addr)
   142  }