package v1 import ( "github.com/pkg/errors" types "github.com/prysmaticlabs/eth2-types" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/htrutils" "github.com/prysmaticlabs/prysm/shared/interfaces/version" "github.com/prysmaticlabs/prysm/shared/params" ) // GenesisTime of the beacon state as a uint64. func (b *BeaconState) GenesisTime() uint64 { if !b.hasInnerState() { return 0 } b.lock.RLock() defer b.lock.RUnlock() return b.genesisTime() } // genesisTime of the beacon state as a uint64. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) genesisTime() uint64 { if !b.hasInnerState() { return 0 } return b.state.GenesisTime } // GenesisValidatorRoot of the beacon state. func (b *BeaconState) GenesisValidatorRoot() []byte { if !b.hasInnerState() { return nil } if b.state.GenesisValidatorsRoot == nil { return params.BeaconConfig().ZeroHash[:] } b.lock.RLock() defer b.lock.RUnlock() return b.genesisValidatorRoot() } // genesisValidatorRoot of the beacon state. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) genesisValidatorRoot() []byte { if !b.hasInnerState() { return nil } if b.state.GenesisValidatorsRoot == nil { return params.BeaconConfig().ZeroHash[:] } root := make([]byte, 32) copy(root, b.state.GenesisValidatorsRoot) return root } // Version of the beacon state. func (b *BeaconState) Version() int { return version.Phase0 } // Slot of the current beacon chain state. func (b *BeaconState) Slot() types.Slot { if !b.hasInnerState() { return 0 } b.lock.RLock() defer b.lock.RUnlock() return b.slot() } // slot of the current beacon chain state. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) slot() types.Slot { if !b.hasInnerState() { return 0 } return b.state.Slot } // Fork version of the beacon chain. func (b *BeaconState) Fork() *pbp2p.Fork { if !b.hasInnerState() { return nil } if b.state.Fork == nil { return nil } b.lock.RLock() defer b.lock.RUnlock() return b.fork() } // fork version of the beacon chain. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) fork() *pbp2p.Fork { if !b.hasInnerState() { return nil } if b.state.Fork == nil { return nil } prevVersion := make([]byte, len(b.state.Fork.PreviousVersion)) copy(prevVersion, b.state.Fork.PreviousVersion) currVersion := make([]byte, len(b.state.Fork.CurrentVersion)) copy(currVersion, b.state.Fork.CurrentVersion) return &pbp2p.Fork{ PreviousVersion: prevVersion, CurrentVersion: currVersion, Epoch: b.state.Fork.Epoch, } } // HistoricalRoots based on epochs stored in the beacon state. func (b *BeaconState) HistoricalRoots() [][]byte { if !b.hasInnerState() { return nil } if b.state.HistoricalRoots == nil { return nil } b.lock.RLock() defer b.lock.RUnlock() return b.historicalRoots() } // historicalRoots based on epochs stored in the beacon state. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) historicalRoots() [][]byte { if !b.hasInnerState() { return nil } return b.safeCopy2DByteSlice(b.state.HistoricalRoots) } // balancesLength returns the length of the balances slice. // This assumes that a lock is already held on BeaconState. func (b *BeaconState) balancesLength() int { if !b.hasInnerState() { return 0 } if b.state.Balances == nil { return 0 } return len(b.state.Balances) } // RootsArrayHashTreeRoot computes the Merkle root of arrays of 32-byte hashes, such as [64][32]byte // according to the Simple Serialize specification of Ethereum. func RootsArrayHashTreeRoot(vals [][]byte, length uint64, fieldName string) ([32]byte, error) { if featureconfig.Get().EnableSSZCache { return cachedHasher.arraysRoot(vals, length, fieldName) } return nocachedHasher.arraysRoot(vals, length, fieldName) } func (h *stateRootHasher) arraysRoot(input [][]byte, length uint64, fieldName string) ([32]byte, error) { lock.Lock() defer lock.Unlock() hashFunc := hashutil.CustomSHA256Hasher() if _, ok := layersCache[fieldName]; !ok && h.rootsCache != nil { depth := htrutils.Depth(length) layersCache[fieldName] = make([][][32]byte, depth+1) } leaves := make([][32]byte, length) for i, chunk := range input { copy(leaves[i][:], chunk) } bytesProcessed := 0 changedIndices := make([]int, 0) prevLeaves, ok := leavesCache[fieldName] if len(prevLeaves) == 0 || h.rootsCache == nil { prevLeaves = leaves } for i := 0; i < len(leaves); i++ { // We check if any items changed since the roots were last recomputed. notEqual := leaves[i] != prevLeaves[i] if ok && h.rootsCache != nil && notEqual { changedIndices = append(changedIndices, i) } bytesProcessed += 32 } if len(changedIndices) > 0 && h.rootsCache != nil { var rt [32]byte var err error // If indices did change since last computation, we only recompute // the modified branches in the cached Merkle tree for this state field. chunks := leaves // We need to ensure we recompute indices of the Merkle tree which // changed in-between calls to this function. This check adds an offset // to the recomputed indices to ensure we do so evenly. maxChangedIndex := changedIndices[len(changedIndices)-1] if maxChangedIndex+2 == len(chunks) && maxChangedIndex%2 != 0 { changedIndices = append(changedIndices, maxChangedIndex+1) } for i := 0; i < len(changedIndices); i++ { rt, err = recomputeRoot(changedIndices[i], chunks, fieldName, hashFunc) if err != nil { return [32]byte{}, err } } leavesCache[fieldName] = chunks return rt, nil } res := h.merkleizeWithCache(leaves, length, fieldName, hashFunc) if h.rootsCache != nil { leavesCache[fieldName] = leaves } return res, nil } func recomputeRoot(idx int, chunks [][32]byte, fieldName string, hasher func([]byte) [32]byte) ([32]byte, error) { items, ok := layersCache[fieldName] if !ok { return [32]byte{}, errors.New("could not recompute root as there was no cache found") } if items == nil { return [32]byte{}, errors.New("could not recompute root as there were no items found in the layers cache") } layers := items root := chunks[idx] layers[0] = chunks // The merkle tree structure looks as follows: // [[r1, r2, r3, r4], [parent1, parent2], [root]] // Using information about the index which changed, idx, we recompute // only its branch up the tree. currentIndex := idx for i := 0; i < len(layers)-1; i++ { isLeft := currentIndex%2 == 0 neighborIdx := currentIndex ^ 1 neighbor := [32]byte{} if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) { neighbor = layers[i][neighborIdx] } if isLeft { parentHash := hasher(append(root[:], neighbor[:]...)) root = parentHash } else { parentHash := hasher(append(neighbor[:], root[:]...)) root = parentHash } parentIdx := currentIndex / 2 // Update the cached layers at the parent index. if len(layers[i+1]) == 0 { layers[i+1] = append(layers[i+1], root) } else { layers[i+1][parentIdx] = root } currentIndex = parentIdx } layersCache[fieldName] = layers // If there is only a single leaf, we return it (the identity element). if len(layers[0]) == 1 { return layers[0][0], nil } return root, nil } func (h *stateRootHasher) merkleizeWithCache(leaves [][32]byte, length uint64, fieldName string, hasher func([]byte) [32]byte) [32]byte { if len(leaves) == 1 { return leaves[0] } hashLayer := leaves layers := make([][][32]byte, htrutils.Depth(length)+1) if items, ok := layersCache[fieldName]; ok && h.rootsCache != nil { if len(items[0]) == len(leaves) { layers = items } } layers[0] = hashLayer layers, hashLayer = stateutil.MerkleizeTrieLeaves(layers, hashLayer, hasher) root := hashLayer[0] if h.rootsCache != nil { layersCache[fieldName] = layers } return root }