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 }