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

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