github.com/prysmaticlabs/prysm@v1.4.4/slasher/db/kv/attester_slashings.go (about)

     1  package kv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/pkg/errors"
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    10  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    11  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    12  	slashertypes "github.com/prysmaticlabs/prysm/slasher/db/types"
    13  	bolt "go.etcd.io/bbolt"
    14  	"go.opencensus.io/trace"
    15  	"google.golang.org/protobuf/proto"
    16  )
    17  
    18  func unmarshalAttSlashing(enc []byte) (*ethpb.AttesterSlashing, error) {
    19  	protoSlashing := &ethpb.AttesterSlashing{}
    20  	err := proto.Unmarshal(enc, protoSlashing)
    21  	if err != nil {
    22  		return nil, errors.Wrap(err, "failed to unmarshal encoding")
    23  	}
    24  	return protoSlashing, nil
    25  }
    26  
    27  func unmarshalAttSlashings(encoded [][]byte) ([]*ethpb.AttesterSlashing, error) {
    28  	attesterSlashings := make([]*ethpb.AttesterSlashing, len(encoded))
    29  	for i, enc := range encoded {
    30  		ps, err := unmarshalAttSlashing(enc)
    31  		if err != nil {
    32  			return nil, err
    33  		}
    34  		attesterSlashings[i] = ps
    35  	}
    36  	return attesterSlashings, nil
    37  }
    38  
    39  // AttesterSlashings accepts a status and returns all slashings with this status.
    40  // returns empty []*ethpb.AttesterSlashing if no slashing has been found with this status.
    41  func (s *Store) AttesterSlashings(ctx context.Context, status slashertypes.SlashingStatus) ([]*ethpb.AttesterSlashing, error) {
    42  	ctx, span := trace.StartSpan(ctx, "slasherDB.AttesterSlashings")
    43  	defer span.End()
    44  	encoded := make([][]byte, 0)
    45  	err := s.view(func(tx *bolt.Tx) error {
    46  		c := tx.Bucket(slashingBucket).Cursor()
    47  		prefix := encodeType(slashertypes.SlashingType(slashertypes.Attestation))
    48  		for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
    49  			if v[0] == byte(status) {
    50  				encoded = append(encoded, v[1:])
    51  			}
    52  		}
    53  		return nil
    54  	})
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	return unmarshalAttSlashings(encoded)
    59  }
    60  
    61  // DeleteAttesterSlashing deletes an attester slashing proof from db.
    62  func (s *Store) DeleteAttesterSlashing(ctx context.Context, attesterSlashing *ethpb.AttesterSlashing) error {
    63  	ctx, span := trace.StartSpan(ctx, "slasherDB.deleteAttesterSlashing")
    64  	defer span.End()
    65  	root, err := hashutil.HashProto(attesterSlashing)
    66  	if err != nil {
    67  		return errors.Wrap(err, "failed to get hash root of attesterSlashing")
    68  	}
    69  	return s.update(func(tx *bolt.Tx) error {
    70  		bucket := tx.Bucket(slashingBucket)
    71  		k := encodeTypeRoot(slashertypes.SlashingType(slashertypes.Attestation), root)
    72  		if err != nil {
    73  			return errors.Wrap(err, "failed to get key for for attester slashing.")
    74  		}
    75  		if err := bucket.Delete(k); err != nil {
    76  			return errors.Wrap(err, "failed to delete the slashing proof from slashing bucket")
    77  		}
    78  		return nil
    79  	})
    80  }
    81  
    82  // HasAttesterSlashing returns true and slashing status if a slashing is found in the db.
    83  func (s *Store) HasAttesterSlashing(ctx context.Context, slashing *ethpb.AttesterSlashing) (bool, slashertypes.SlashingStatus, error) {
    84  	ctx, span := trace.StartSpan(ctx, "slasherDB.HasAttesterSlashing")
    85  	defer span.End()
    86  	var status slashertypes.SlashingStatus
    87  	var found bool
    88  	root, err := hashutil.HashProto(slashing)
    89  	if err != nil {
    90  		return found, status, errors.Wrap(err, "failed to get hash root of attesterSlashing")
    91  	}
    92  	key := encodeTypeRoot(slashertypes.SlashingType(slashertypes.Attestation), root)
    93  	err = s.view(func(tx *bolt.Tx) error {
    94  		b := tx.Bucket(slashingBucket)
    95  		enc := b.Get(key)
    96  		if enc != nil {
    97  			found = true
    98  			status = slashertypes.SlashingStatus(enc[0])
    99  		}
   100  		return nil
   101  	})
   102  	return found, status, err
   103  }
   104  
   105  // SaveAttesterSlashing accepts a slashing proof and its status and writes it to disk.
   106  func (s *Store) SaveAttesterSlashing(ctx context.Context, status slashertypes.SlashingStatus, slashing *ethpb.AttesterSlashing) error {
   107  	ctx, span := trace.StartSpan(ctx, "slasherDB.SaveAttesterSlashing")
   108  	defer span.End()
   109  	enc, err := proto.Marshal(slashing)
   110  	if err != nil {
   111  		return errors.Wrap(err, "failed to marshal")
   112  	}
   113  	root, err := hashutil.HashProto(slashing)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	key := encodeTypeRoot(slashertypes.SlashingType(slashertypes.Attestation), root)
   118  	return s.update(func(tx *bolt.Tx) error {
   119  		b := tx.Bucket(slashingBucket)
   120  		e := b.Put(key, append([]byte{byte(status)}, enc...))
   121  		return e
   122  	})
   123  }
   124  
   125  // SaveAttesterSlashings accepts a slice of slashing proof and its status and writes it to disk.
   126  func (s *Store) SaveAttesterSlashings(ctx context.Context, status slashertypes.SlashingStatus, slashings []*ethpb.AttesterSlashing) error {
   127  	ctx, span := trace.StartSpan(ctx, "slasherDB.SaveAttesterSlashings")
   128  	defer span.End()
   129  	enc := make([][]byte, len(slashings))
   130  	key := make([][]byte, len(slashings))
   131  	var err error
   132  	for i, slashing := range slashings {
   133  		enc[i], err = proto.Marshal(slashing)
   134  		if err != nil {
   135  			return errors.Wrap(err, "failed to marshal")
   136  		}
   137  		root, err := hashutil.HashProto(slashing)
   138  		if err != nil {
   139  			return err
   140  		}
   141  		key[i] = encodeTypeRoot(slashertypes.SlashingType(slashertypes.Attestation), root)
   142  	}
   143  
   144  	return s.update(func(tx *bolt.Tx) error {
   145  		b := tx.Bucket(slashingBucket)
   146  		for i := 0; i < len(enc); i++ {
   147  			e := b.Put(key[i], append([]byte{byte(status)}, enc[i]...))
   148  			if e != nil {
   149  				return e
   150  			}
   151  		}
   152  		return nil
   153  	})
   154  }
   155  
   156  // GetLatestEpochDetected returns the latest detected epoch from db.
   157  func (s *Store) GetLatestEpochDetected(ctx context.Context) (types.Epoch, error) {
   158  	ctx, span := trace.StartSpan(ctx, "slasherDB.GetLatestEpochDetected")
   159  	defer span.End()
   160  	var epoch types.Epoch
   161  	err := s.view(func(tx *bolt.Tx) error {
   162  		b := tx.Bucket(slashingBucket)
   163  		enc := b.Get([]byte(latestEpochKey))
   164  		if enc == nil {
   165  			epoch = 0
   166  			return nil
   167  		}
   168  		epoch = types.Epoch(bytesutil.FromBytes8(enc))
   169  		return nil
   170  	})
   171  	return epoch, err
   172  }
   173  
   174  // SetLatestEpochDetected sets the latest slashing detected epoch in db.
   175  func (s *Store) SetLatestEpochDetected(ctx context.Context, epoch types.Epoch) error {
   176  	ctx, span := trace.StartSpan(ctx, "slasherDB.SetLatestEpochDetected")
   177  	defer span.End()
   178  	return s.update(func(tx *bolt.Tx) error {
   179  		b := tx.Bucket(slashingBucket)
   180  		err := b.Put([]byte(latestEpochKey), bytesutil.Bytes8(uint64(epoch)))
   181  		return err
   182  	})
   183  }