github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/v2/field_trie.go (about)

     1  package v2
     2  
     3  import (
     4  	"reflect"
     5  	"sync"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  )
    12  
    13  // FieldTrie is the representation of the representative
    14  // trie of the particular field.
    15  type FieldTrie struct {
    16  	*sync.RWMutex
    17  	reference   *stateutil.Reference
    18  	fieldLayers [][]*[32]byte
    19  	field       fieldIndex
    20  }
    21  
    22  // NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
    23  // trie according to the given parameters. Depending on whether the field is a basic/composite array
    24  // which is either fixed/variable length, it will appropriately determine the trie.
    25  func NewFieldTrie(field fieldIndex, elements interface{}, length uint64) (*FieldTrie, error) {
    26  	if elements == nil {
    27  		return &FieldTrie{
    28  			field:     field,
    29  			reference: stateutil.NewRef(1),
    30  			RWMutex:   new(sync.RWMutex),
    31  		}, nil
    32  	}
    33  	datType, ok := fieldMap[field]
    34  	if !ok {
    35  		return nil, errors.Errorf("unrecognized field in trie")
    36  	}
    37  	fieldRoots, err := fieldConverters(field, []uint64{}, elements, true)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	switch datType {
    42  	case basicArray:
    43  		return &FieldTrie{
    44  			fieldLayers: stateutil.ReturnTrieLayer(fieldRoots, length),
    45  			field:       field,
    46  			reference:   stateutil.NewRef(1),
    47  			RWMutex:     new(sync.RWMutex),
    48  		}, nil
    49  	case compositeArray:
    50  		return &FieldTrie{
    51  			fieldLayers: stateutil.ReturnTrieLayerVariable(fieldRoots, length),
    52  			field:       field,
    53  			reference:   stateutil.NewRef(1),
    54  			RWMutex:     new(sync.RWMutex),
    55  		}, nil
    56  	default:
    57  		return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(datType).Name())
    58  	}
    59  
    60  }
    61  
    62  // RecomputeTrie rebuilds the affected branches in the trie according to the provided
    63  // changed indices and elements. This recomputes the trie according to the particular
    64  // field the trie is based on.
    65  func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]byte, error) {
    66  	f.Lock()
    67  	defer f.Unlock()
    68  	var fieldRoot [32]byte
    69  	if len(indices) == 0 {
    70  		return f.TrieRoot()
    71  	}
    72  	datType, ok := fieldMap[f.field]
    73  	if !ok {
    74  		return [32]byte{}, errors.Errorf("unrecognized field in trie")
    75  	}
    76  	fieldRoots, err := fieldConverters(f.field, indices, elements, false)
    77  	if err != nil {
    78  		return [32]byte{}, err
    79  	}
    80  	switch datType {
    81  	case basicArray:
    82  		fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayer(fieldRoots, indices, f.fieldLayers)
    83  		if err != nil {
    84  			return [32]byte{}, err
    85  		}
    86  		return fieldRoot, nil
    87  	case compositeArray:
    88  		fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayerVariable(fieldRoots, indices, f.fieldLayers)
    89  		if err != nil {
    90  			return [32]byte{}, err
    91  		}
    92  		return stateutil.AddInMixin(fieldRoot, uint64(len(f.fieldLayers[0])))
    93  	default:
    94  		return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(datType).Name())
    95  	}
    96  
    97  }
    98  
    99  // CopyTrie copies the references to the elements the trie
   100  // is built on.
   101  func (f *FieldTrie) CopyTrie() *FieldTrie {
   102  	if f.fieldLayers == nil {
   103  		return &FieldTrie{
   104  			field:     f.field,
   105  			reference: stateutil.NewRef(1),
   106  			RWMutex:   new(sync.RWMutex),
   107  		}
   108  	}
   109  	dstFieldTrie := make([][]*[32]byte, len(f.fieldLayers))
   110  	for i, layer := range f.fieldLayers {
   111  		dstFieldTrie[i] = make([]*[32]byte, len(layer))
   112  		copy(dstFieldTrie[i], layer)
   113  	}
   114  	return &FieldTrie{
   115  		fieldLayers: dstFieldTrie,
   116  		field:       f.field,
   117  		reference:   stateutil.NewRef(1),
   118  		RWMutex:     new(sync.RWMutex),
   119  	}
   120  }
   121  
   122  // TrieRoot returns the corresponding root of the trie.
   123  func (f *FieldTrie) TrieRoot() ([32]byte, error) {
   124  	datType, ok := fieldMap[f.field]
   125  	if !ok {
   126  		return [32]byte{}, errors.Errorf("unrecognized field in trie")
   127  	}
   128  	switch datType {
   129  	case basicArray:
   130  		return *f.fieldLayers[len(f.fieldLayers)-1][0], nil
   131  	case compositeArray:
   132  		trieRoot := *f.fieldLayers[len(f.fieldLayers)-1][0]
   133  		return stateutil.AddInMixin(trieRoot, uint64(len(f.fieldLayers[0])))
   134  	default:
   135  		return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(datType).Name())
   136  	}
   137  }
   138  
   139  // this converts the corresponding field and the provided elements to the appropriate roots.
   140  func fieldConverters(field fieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
   141  	switch field {
   142  	case blockRoots, stateRoots, randaoMixes:
   143  		val, ok := elements.([][]byte)
   144  		if !ok {
   145  			return nil, errors.Errorf("Wanted type of %v but got %v",
   146  				reflect.TypeOf([][]byte{}).Name(), reflect.TypeOf(elements).Name())
   147  		}
   148  		return stateutil.HandleByteArrays(val, indices, convertAll)
   149  	case eth1DataVotes:
   150  		val, ok := elements.([]*ethpb.Eth1Data)
   151  		if !ok {
   152  			return nil, errors.Errorf("Wanted type of %v but got %v",
   153  				reflect.TypeOf([]*ethpb.Eth1Data{}).Name(), reflect.TypeOf(elements).Name())
   154  		}
   155  		return v1.HandleEth1DataSlice(val, indices, convertAll)
   156  	case validators:
   157  		val, ok := elements.([]*ethpb.Validator)
   158  		if !ok {
   159  			return nil, errors.Errorf("Wanted type of %v but got %v",
   160  				reflect.TypeOf([]*ethpb.Validator{}).Name(), reflect.TypeOf(elements).Name())
   161  		}
   162  		return stateutil.HandleValidatorSlice(val, indices, convertAll)
   163  	default:
   164  		return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name())
   165  	}
   166  }