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 }