mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
State: Move compute field roots functions next to implementation (#8615)
This commit is contained in:
@@ -32,7 +32,6 @@ go_library(
|
||||
"//beacon-chain/core/state/interop:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
@@ -137,7 +136,7 @@ func OptimizedGenesisBeaconState(genesisTime uint64, preState iface.BeaconState,
|
||||
|
||||
slashings := make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)
|
||||
|
||||
genesisValidatorsRoot, err := stateutil.ValidatorRegistryRoot(preState.Validators())
|
||||
genesisValidatorsRoot, err := stateTrie.ValidatorRegistryRoot(preState.Validators())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not hash tree root genesis validators %v", err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ go_library(
|
||||
srcs = [
|
||||
"cloners.go",
|
||||
"doc.go",
|
||||
"field_root_attestation.go",
|
||||
"field_root_block_header.go",
|
||||
"field_root_eth1.go",
|
||||
"field_root_validator.go",
|
||||
"field_root_vector.go",
|
||||
"field_roots.go",
|
||||
"field_trie.go",
|
||||
"getters.go",
|
||||
"setters.go",
|
||||
@@ -31,10 +37,12 @@ go_library(
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/htrutils:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package stateutil
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -13,34 +13,94 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// PendingAttestationRoot describes a method from which the hash tree root
|
||||
// of a pending attestation is returned.
|
||||
func PendingAttestationRoot(hasher htrutils.HashFn, att *pb.PendingAttestation) ([32]byte, error) {
|
||||
var fieldRoots [][32]byte
|
||||
func (h *stateRootHasher) epochAttestationsRoot(atts []*pb.PendingAttestation) ([32]byte, error) {
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
roots := make([][]byte, len(atts))
|
||||
for i := 0; i < len(atts); i++ {
|
||||
pendingRoot, err := h.pendingAttestationRoot(hasher, atts[i])
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not attestation merkleization")
|
||||
}
|
||||
roots[i] = pendingRoot[:]
|
||||
}
|
||||
|
||||
attsRootsRoot, err := htrutils.BitwiseMerkleize(
|
||||
hasher,
|
||||
roots,
|
||||
uint64(len(roots)),
|
||||
uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)),
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not compute epoch attestations merkleization")
|
||||
}
|
||||
attsLenBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(attsLenBuf, binary.LittleEndian, uint64(len(atts))); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal epoch attestations length")
|
||||
}
|
||||
// We need to mix in the length of the slice.
|
||||
attsLenRoot := make([]byte, 32)
|
||||
copy(attsLenRoot, attsLenBuf.Bytes())
|
||||
res := htrutils.MixInLength(attsRootsRoot, attsLenRoot)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *stateRootHasher) pendingAttestationRoot(hasher htrutils.HashFn, att *pb.PendingAttestation) ([32]byte, error) {
|
||||
// Marshal attestation to determine if it exists in the cache.
|
||||
enc := make([]byte, 2192)
|
||||
fieldRoots := make([][]byte, 4)
|
||||
|
||||
if att != nil {
|
||||
copy(enc[0:2048], att.AggregationBits)
|
||||
|
||||
inclusionBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inclusionBuf, uint64(att.InclusionDelay))
|
||||
copy(enc[2048:2056], inclusionBuf)
|
||||
|
||||
attDataBuf := marshalAttestationData(att.Data)
|
||||
copy(enc[2056:2184], attDataBuf)
|
||||
|
||||
proposerBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerBuf, uint64(att.ProposerIndex))
|
||||
copy(enc[2184:2192], proposerBuf)
|
||||
|
||||
// Check if it exists in cache:
|
||||
if h.rootsCache != nil {
|
||||
if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok {
|
||||
return found.([32]byte), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Bitfield.
|
||||
aggregationRoot, err := htrutils.BitlistRoot(hasher, att.AggregationBits, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
aggregationRoot, err := htrutils.BitlistRoot(hasher, att.AggregationBits, 2048)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
fieldRoots[0] = aggregationRoot[:]
|
||||
|
||||
// Attestation data.
|
||||
attDataRoot, err := attestationDataRoot(hasher, att.Data)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
inclusionBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inclusionBuf, uint64(att.InclusionDelay))
|
||||
fieldRoots[1] = attDataRoot[:]
|
||||
|
||||
// Inclusion delay.
|
||||
inclusionRoot := bytesutil.ToBytes32(inclusionBuf)
|
||||
fieldRoots[2] = inclusionRoot[:]
|
||||
|
||||
proposerBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerBuf, uint64(att.ProposerIndex))
|
||||
// Proposer index.
|
||||
proposerRoot := bytesutil.ToBytes32(proposerBuf)
|
||||
|
||||
fieldRoots = [][32]byte{aggregationRoot, attDataRoot, inclusionRoot, proposerRoot}
|
||||
fieldRoots[3] = proposerRoot[:]
|
||||
}
|
||||
return htrutils.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
|
||||
res, err := htrutils.BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
if h.rootsCache != nil {
|
||||
h.rootsCache.Set(string(enc), res, 32)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func marshalAttestationData(data *ethpb.AttestationData) []byte {
|
||||
@@ -117,91 +177,32 @@ func attestationDataRoot(hasher htrutils.HashFn, data *ethpb.AttestationData) ([
|
||||
return htrutils.BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
|
||||
func (h *stateRootHasher) pendingAttestationRoot(hasher htrutils.HashFn, att *pb.PendingAttestation) ([32]byte, error) {
|
||||
// Marshal attestation to determine if it exists in the cache.
|
||||
enc := make([]byte, 2192)
|
||||
fieldRoots := make([][]byte, 4)
|
||||
|
||||
// pendingAttestationRoot describes a method from which the hash tree root
|
||||
// of a pending attestation is returned.
|
||||
func pendingAttestationRoot(hasher htrutils.HashFn, att *pb.PendingAttestation) ([32]byte, error) {
|
||||
var fieldRoots [][32]byte
|
||||
if att != nil {
|
||||
copy(enc[0:2048], att.AggregationBits)
|
||||
|
||||
inclusionBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inclusionBuf, uint64(att.InclusionDelay))
|
||||
copy(enc[2048:2056], inclusionBuf)
|
||||
|
||||
attDataBuf := marshalAttestationData(att.Data)
|
||||
copy(enc[2056:2184], attDataBuf)
|
||||
|
||||
proposerBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerBuf, uint64(att.ProposerIndex))
|
||||
copy(enc[2184:2192], proposerBuf)
|
||||
|
||||
// Check if it exists in cache:
|
||||
if h.rootsCache != nil {
|
||||
if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok {
|
||||
return found.([32]byte), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Bitfield.
|
||||
aggregationRoot, err := htrutils.BitlistRoot(hasher, att.AggregationBits, 2048)
|
||||
aggregationRoot, err := htrutils.BitlistRoot(hasher, att.AggregationBits, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
fieldRoots[0] = aggregationRoot[:]
|
||||
|
||||
// Attestation data.
|
||||
attDataRoot, err := attestationDataRoot(hasher, att.Data)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
fieldRoots[1] = attDataRoot[:]
|
||||
|
||||
inclusionBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inclusionBuf, uint64(att.InclusionDelay))
|
||||
// Inclusion delay.
|
||||
inclusionRoot := bytesutil.ToBytes32(inclusionBuf)
|
||||
fieldRoots[2] = inclusionRoot[:]
|
||||
|
||||
proposerBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerBuf, uint64(att.ProposerIndex))
|
||||
// Proposer index.
|
||||
proposerRoot := bytesutil.ToBytes32(proposerBuf)
|
||||
fieldRoots[3] = proposerRoot[:]
|
||||
}
|
||||
res, err := htrutils.BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
if h.rootsCache != nil {
|
||||
h.rootsCache.Set(string(enc), res, 32)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *stateRootHasher) epochAttestationsRoot(atts []*pb.PendingAttestation) ([32]byte, error) {
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
roots := make([][]byte, len(atts))
|
||||
for i := 0; i < len(atts); i++ {
|
||||
pendingRoot, err := h.pendingAttestationRoot(hasher, atts[i])
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not attestation merkleization")
|
||||
}
|
||||
roots[i] = pendingRoot[:]
|
||||
fieldRoots = [][32]byte{aggregationRoot, attDataRoot, inclusionRoot, proposerRoot}
|
||||
}
|
||||
|
||||
attsRootsRoot, err := htrutils.BitwiseMerkleize(
|
||||
hasher,
|
||||
roots,
|
||||
uint64(len(roots)),
|
||||
uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)),
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not compute epoch attestations merkleization")
|
||||
}
|
||||
attsLenBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(attsLenBuf, binary.LittleEndian, uint64(len(atts))); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal epoch attestations length")
|
||||
}
|
||||
// We need to mix in the length of the slice.
|
||||
attsLenRoot := make([]byte, 32)
|
||||
copy(attsLenRoot, attsLenBuf.Bytes())
|
||||
res := htrutils.MixInLength(attsRootsRoot, attsLenRoot)
|
||||
return res, nil
|
||||
return htrutils.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
34
beacon-chain/state/field_root_block_header.go
Normal file
34
beacon-chain/state/field_root_block_header.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/htrutils"
|
||||
)
|
||||
|
||||
// blockHeaderRoot computes the HashTreeRoot Merkleization of
|
||||
// a BeaconBlockHeader struct according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func blockHeaderRoot(header *ethpb.BeaconBlockHeader) ([32]byte, error) {
|
||||
fieldRoots := make([][]byte, 5)
|
||||
if header != nil {
|
||||
headerSlotBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(headerSlotBuf, uint64(header.Slot))
|
||||
headerSlotRoot := bytesutil.ToBytes32(headerSlotBuf)
|
||||
fieldRoots[0] = headerSlotRoot[:]
|
||||
proposerIdxBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerIdxBuf, uint64(header.ProposerIndex))
|
||||
proposerIndexRoot := bytesutil.ToBytes32(proposerIdxBuf)
|
||||
fieldRoots[1] = proposerIndexRoot[:]
|
||||
parentRoot := bytesutil.ToBytes32(header.ParentRoot)
|
||||
fieldRoots[2] = parentRoot[:]
|
||||
stateRoot := bytesutil.ToBytes32(header.StateRoot)
|
||||
fieldRoots[3] = stateRoot[:]
|
||||
bodyRoot := bytesutil.ToBytes32(header.BodyRoot)
|
||||
fieldRoots[4] = bodyRoot[:]
|
||||
}
|
||||
return htrutils.BitwiseMerkleize(hashutil.CustomSHA256Hasher(), fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package stateutil
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -13,34 +13,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// BlockHeaderRoot computes the HashTreeRoot Merkleization of
|
||||
// eth1Root computes the HashTreeRoot Merkleization of
|
||||
// a BeaconBlockHeader struct according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func BlockHeaderRoot(header *ethpb.BeaconBlockHeader) ([32]byte, error) {
|
||||
fieldRoots := make([][]byte, 5)
|
||||
if header != nil {
|
||||
headerSlotBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(headerSlotBuf, uint64(header.Slot))
|
||||
headerSlotRoot := bytesutil.ToBytes32(headerSlotBuf)
|
||||
fieldRoots[0] = headerSlotRoot[:]
|
||||
proposerIdxBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(proposerIdxBuf, uint64(header.ProposerIndex))
|
||||
proposerIndexRoot := bytesutil.ToBytes32(proposerIdxBuf)
|
||||
fieldRoots[1] = proposerIndexRoot[:]
|
||||
parentRoot := bytesutil.ToBytes32(header.ParentRoot)
|
||||
fieldRoots[2] = parentRoot[:]
|
||||
stateRoot := bytesutil.ToBytes32(header.StateRoot)
|
||||
fieldRoots[3] = stateRoot[:]
|
||||
bodyRoot := bytesutil.ToBytes32(header.BodyRoot)
|
||||
fieldRoots[4] = bodyRoot[:]
|
||||
}
|
||||
return htrutils.BitwiseMerkleize(hashutil.CustomSHA256Hasher(), fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
|
||||
// Eth1Root computes the HashTreeRoot Merkleization of
|
||||
// a BeaconBlockHeader struct according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func Eth1Root(hasher htrutils.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) {
|
||||
func eth1Root(hasher htrutils.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) {
|
||||
enc := make([]byte, 0, 96)
|
||||
fieldRoots := make([][]byte, 3)
|
||||
for i := 0; i < len(fieldRoots); i++ {
|
||||
@@ -78,15 +54,15 @@ func Eth1Root(hasher htrutils.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// Eth1DataVotesRoot computes the HashTreeRoot Merkleization of
|
||||
// eth1DataVotesRoot computes the HashTreeRoot Merkleization of
|
||||
// a list of Eth1Data structs according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func Eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) {
|
||||
func eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) {
|
||||
eth1VotesRoots := make([][]byte, 0)
|
||||
enc := make([]byte, len(eth1DataVotes)*32)
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
for i := 0; i < len(eth1DataVotes); i++ {
|
||||
eth1, err := Eth1Root(hasher, eth1DataVotes[i])
|
||||
eth1, err := eth1Root(hasher, eth1DataVotes[i])
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not compute eth1data merkleization")
|
||||
}
|
||||
@@ -125,16 +101,3 @@ func Eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) {
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// AddInMixin describes a method from which a lenth mixin is added to the
|
||||
// provided root.
|
||||
func AddInMixin(root [32]byte, length uint64) ([32]byte, error) {
|
||||
rootBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(rootBuf, binary.LittleEndian, length); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal eth1data votes length")
|
||||
}
|
||||
// We need to mix in the length of the slice.
|
||||
rootBufRoot := make([]byte, 32)
|
||||
copy(rootBufRoot, rootBuf.Bytes())
|
||||
return htrutils.MixInLength(root, rootBufRoot), nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package stateutil
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -13,97 +13,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of
|
||||
// a list of validator structs according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) {
|
||||
if featureconfig.Get().EnableSSZCache {
|
||||
return cachedHasher.validatorRegistryRoot(vals)
|
||||
}
|
||||
return nocachedHasher.validatorRegistryRoot(vals)
|
||||
}
|
||||
|
||||
// ValidatorBalancesRoot computes the HashTreeRoot Merkleization of
|
||||
// a list of validator uint64 balances according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func ValidatorBalancesRoot(balances []uint64) ([32]byte, error) {
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
balancesMarshaling := make([][]byte, 0)
|
||||
for i := 0; i < len(balances); i++ {
|
||||
balanceBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(balanceBuf, balances[i])
|
||||
balancesMarshaling = append(balancesMarshaling, balanceBuf)
|
||||
}
|
||||
balancesChunks, err := htrutils.Pack(balancesMarshaling)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not pack balances into chunks")
|
||||
}
|
||||
maxBalCap := params.BeaconConfig().ValidatorRegistryLimit
|
||||
elemSize := uint64(8)
|
||||
balLimit := (maxBalCap*elemSize + 31) / 32
|
||||
if balLimit == 0 {
|
||||
if len(balances) == 0 {
|
||||
balLimit = 1
|
||||
} else {
|
||||
balLimit = uint64(len(balances))
|
||||
}
|
||||
}
|
||||
balancesRootsRoot, err := htrutils.BitwiseMerkleize(hasher, balancesChunks, uint64(len(balancesChunks)), balLimit)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not compute balances merkleization")
|
||||
}
|
||||
balancesRootsBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(balancesRootsBuf, binary.LittleEndian, uint64(len(balances))); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal balances length")
|
||||
}
|
||||
balancesRootsBufRoot := make([]byte, 32)
|
||||
copy(balancesRootsBufRoot, balancesRootsBuf.Bytes())
|
||||
return htrutils.MixInLength(balancesRootsRoot, balancesRootsBufRoot), nil
|
||||
}
|
||||
|
||||
// ValidatorRoot describes a method from which the hash tree root
|
||||
// of a validator is returned.
|
||||
func ValidatorRoot(hasher htrutils.HashFn, validator *ethpb.Validator) ([32]byte, error) {
|
||||
var fieldRoots [][32]byte
|
||||
if validator != nil {
|
||||
pubkey := bytesutil.ToBytes48(validator.PublicKey)
|
||||
withdrawCreds := bytesutil.ToBytes32(validator.WithdrawalCredentials)
|
||||
effectiveBalanceBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(effectiveBalanceBuf[:8], validator.EffectiveBalance)
|
||||
// Slashed.
|
||||
slashBuf := [32]byte{}
|
||||
if validator.Slashed {
|
||||
slashBuf[0] = uint8(1)
|
||||
} else {
|
||||
slashBuf[0] = uint8(0)
|
||||
}
|
||||
activationEligibilityBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(activationEligibilityBuf[:8], uint64(validator.ActivationEligibilityEpoch))
|
||||
|
||||
activationBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(activationBuf[:8], uint64(validator.ActivationEpoch))
|
||||
|
||||
exitBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(exitBuf[:8], uint64(validator.ExitEpoch))
|
||||
|
||||
withdrawalBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch))
|
||||
|
||||
// Public key.
|
||||
pubKeyChunks, err := htrutils.Pack([][]byte{pubkey[:]})
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
pubKeyRoot, err := htrutils.BitwiseMerkleize(hasher, pubKeyChunks, uint64(len(pubKeyChunks)), uint64(len(pubKeyChunks)))
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
fieldRoots = [][32]byte{pubKeyRoot, withdrawCreds, effectiveBalanceBuf, slashBuf, activationEligibilityBuf,
|
||||
activationBuf, exitBuf, withdrawalBuf}
|
||||
}
|
||||
return htrutils.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
|
||||
func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) {
|
||||
hashKeyElements := make([]byte, len(validators)*32)
|
||||
roots := make([][32]byte, len(validators))
|
||||
@@ -229,3 +138,94 @@ func (h *stateRootHasher) validatorRoot(hasher htrutils.HashFn, validator *ethpb
|
||||
}
|
||||
return valRoot, nil
|
||||
}
|
||||
|
||||
// validatorBalancesRoot computes the HashTreeRoot Merkleization of
|
||||
// a list of validator uint64 balances according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func validatorBalancesRoot(balances []uint64) ([32]byte, error) {
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
balancesMarshaling := make([][]byte, 0)
|
||||
for i := 0; i < len(balances); i++ {
|
||||
balanceBuf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(balanceBuf, balances[i])
|
||||
balancesMarshaling = append(balancesMarshaling, balanceBuf)
|
||||
}
|
||||
balancesChunks, err := htrutils.Pack(balancesMarshaling)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not pack balances into chunks")
|
||||
}
|
||||
maxBalCap := params.BeaconConfig().ValidatorRegistryLimit
|
||||
elemSize := uint64(8)
|
||||
balLimit := (maxBalCap*elemSize + 31) / 32
|
||||
if balLimit == 0 {
|
||||
if len(balances) == 0 {
|
||||
balLimit = 1
|
||||
} else {
|
||||
balLimit = uint64(len(balances))
|
||||
}
|
||||
}
|
||||
balancesRootsRoot, err := htrutils.BitwiseMerkleize(hasher, balancesChunks, uint64(len(balancesChunks)), balLimit)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not compute balances merkleization")
|
||||
}
|
||||
balancesRootsBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(balancesRootsBuf, binary.LittleEndian, uint64(len(balances))); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal balances length")
|
||||
}
|
||||
balancesRootsBufRoot := make([]byte, 32)
|
||||
copy(balancesRootsBufRoot, balancesRootsBuf.Bytes())
|
||||
return htrutils.MixInLength(balancesRootsRoot, balancesRootsBufRoot), nil
|
||||
}
|
||||
|
||||
// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of
|
||||
// a list of validator structs according to the eth2
|
||||
// Simple Serialize specification.
|
||||
func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) {
|
||||
if featureconfig.Get().EnableSSZCache {
|
||||
return cachedHasher.validatorRegistryRoot(vals)
|
||||
}
|
||||
return nocachedHasher.validatorRegistryRoot(vals)
|
||||
}
|
||||
|
||||
// ValidatorRoot describes a method from which the hash tree root
|
||||
// of a validator is returned.
|
||||
func ValidatorRoot(hasher htrutils.HashFn, validator *ethpb.Validator) ([32]byte, error) {
|
||||
var fieldRoots [][32]byte
|
||||
if validator != nil {
|
||||
pubkey := bytesutil.ToBytes48(validator.PublicKey)
|
||||
withdrawCreds := bytesutil.ToBytes32(validator.WithdrawalCredentials)
|
||||
effectiveBalanceBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(effectiveBalanceBuf[:8], validator.EffectiveBalance)
|
||||
// Slashed.
|
||||
slashBuf := [32]byte{}
|
||||
if validator.Slashed {
|
||||
slashBuf[0] = uint8(1)
|
||||
} else {
|
||||
slashBuf[0] = uint8(0)
|
||||
}
|
||||
activationEligibilityBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(activationEligibilityBuf[:8], uint64(validator.ActivationEligibilityEpoch))
|
||||
|
||||
activationBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(activationBuf[:8], uint64(validator.ActivationEpoch))
|
||||
|
||||
exitBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(exitBuf[:8], uint64(validator.ExitEpoch))
|
||||
|
||||
withdrawalBuf := [32]byte{}
|
||||
binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch))
|
||||
|
||||
// Public key.
|
||||
pubKeyChunks, err := htrutils.Pack([][]byte{pubkey[:]})
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
pubKeyRoot, err := htrutils.BitwiseMerkleize(hasher, pubKeyChunks, uint64(len(pubKeyChunks)), uint64(len(pubKeyChunks)))
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
fieldRoots = [][32]byte{pubKeyRoot, withdrawCreds, effectiveBalanceBuf, slashBuf, activationEligibilityBuf,
|
||||
activationBuf, exitBuf, withdrawalBuf}
|
||||
}
|
||||
return htrutils.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
|
||||
}
|
||||
@@ -1,22 +1,12 @@
|
||||
// Package stateutil defines utility functions to compute state roots
|
||||
// using advanced merkle branch caching techniques.package stateutil
|
||||
package stateutil
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/htrutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var (
|
||||
leavesCache = make(map[string][][32]byte, params.BeaconConfig().BeaconStateFieldCount)
|
||||
layersCache = make(map[string][][][32]byte, params.BeaconConfig().BeaconStateFieldCount)
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
// RootsArrayHashTreeRoot computes the Merkle root of arrays of 32-byte hashes, such as [64][32]byte
|
||||
@@ -87,53 +77,6 @@ func (h *stateRootHasher) arraysRoot(input [][]byte, length uint64, fieldName st
|
||||
return res, 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 = merkleizeTrieLeaves(layers, hashLayer, hasher)
|
||||
root := hashLayer[0]
|
||||
if h.rootsCache != nil {
|
||||
layersCache[fieldName] = layers
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
func merkleizeTrieLeaves(layers [][][32]byte, hashLayer [][32]byte,
|
||||
hasher func([]byte) [32]byte) ([][][32]byte, [][32]byte) {
|
||||
// We keep track of the hash layers of a Merkle trie until we reach
|
||||
// the top layer of length 1, which contains the single root element.
|
||||
// [Root] -> Top layer has length 1.
|
||||
// [E] [F] -> This layer has length 2.
|
||||
// [A] [B] [C] [D] -> The bottom layer has length 4 (needs to be a power of two).
|
||||
i := 1
|
||||
chunkBuffer := bytes.NewBuffer([]byte{})
|
||||
chunkBuffer.Grow(64)
|
||||
for len(hashLayer) > 1 && i < len(layers) {
|
||||
layer := make([][32]byte, len(hashLayer)/2)
|
||||
for j := 0; j < len(hashLayer); j += 2 {
|
||||
chunkBuffer.Write(hashLayer[j][:])
|
||||
chunkBuffer.Write(hashLayer[j+1][:])
|
||||
hashedChunk := hasher(chunkBuffer.Bytes())
|
||||
layer[j/2] = hashedChunk
|
||||
chunkBuffer.Reset()
|
||||
}
|
||||
hashLayer = layer
|
||||
layers[i] = hashLayer
|
||||
i++
|
||||
}
|
||||
return layers, hashLayer
|
||||
}
|
||||
|
||||
func recomputeRoot(idx int, chunks [][32]byte, fieldName string, hasher func([]byte) [32]byte) ([32]byte, error) {
|
||||
items, ok := layersCache[fieldName]
|
||||
if !ok {
|
||||
@@ -181,3 +124,50 @@ func recomputeRoot(idx int, chunks [][32]byte, fieldName string, hasher func([]b
|
||||
}
|
||||
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 = merkleizeTrieLeaves(layers, hashLayer, hasher)
|
||||
root := hashLayer[0]
|
||||
if h.rootsCache != nil {
|
||||
layersCache[fieldName] = layers
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
func merkleizeTrieLeaves(layers [][][32]byte, hashLayer [][32]byte,
|
||||
hasher func([]byte) [32]byte) ([][][32]byte, [][32]byte) {
|
||||
// We keep track of the hash layers of a Merkle trie until we reach
|
||||
// the top layer of length 1, which contains the single root element.
|
||||
// [Root] -> Top layer has length 1.
|
||||
// [E] [F] -> This layer has length 2.
|
||||
// [A] [B] [C] [D] -> The bottom layer has length 4 (needs to be a power of two).
|
||||
i := 1
|
||||
chunkBuffer := bytes.NewBuffer([]byte{})
|
||||
chunkBuffer.Grow(64)
|
||||
for len(hashLayer) > 1 && i < len(layers) {
|
||||
layer := make([][32]byte, len(hashLayer)/2)
|
||||
for j := 0; j < len(hashLayer); j += 2 {
|
||||
chunkBuffer.Write(hashLayer[j][:])
|
||||
chunkBuffer.Write(hashLayer[j+1][:])
|
||||
hashedChunk := hasher(chunkBuffer.Bytes())
|
||||
layer[j/2] = hashedChunk
|
||||
chunkBuffer.Reset()
|
||||
}
|
||||
hashLayer = layer
|
||||
layers[i] = hashLayer
|
||||
i++
|
||||
}
|
||||
return layers, hashLayer
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
// Package stateutil defines utility functions to compute state roots
|
||||
// using advanced merkle branch caching techniques.
|
||||
package stateutil
|
||||
package state
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/pkg/errors"
|
||||
@@ -15,6 +14,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var (
|
||||
leavesCache = make(map[string][][32]byte, params.BeaconConfig().BeaconStateFieldCount)
|
||||
layersCache = make(map[string][][][32]byte, params.BeaconConfig().BeaconStateFieldCount)
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
const cacheSize = 100000
|
||||
|
||||
var nocachedHasher *stateRootHasher
|
||||
@@ -39,16 +44,16 @@ type stateRootHasher struct {
|
||||
rootsCache *ristretto.Cache
|
||||
}
|
||||
|
||||
// ComputeFieldRoots returns the hash tree root computations of every field in
|
||||
// computeFieldRoots returns the hash tree root computations of every field in
|
||||
// the beacon state as a list of 32 byte roots.
|
||||
func ComputeFieldRoots(state *pb.BeaconState) ([][]byte, error) {
|
||||
func computeFieldRoots(state *pb.BeaconState) ([][]byte, error) {
|
||||
if featureconfig.Get().EnableSSZCache {
|
||||
return cachedHasher.computeFieldRoots(state)
|
||||
return cachedHasher.computeFieldRootsWithHasher(state)
|
||||
}
|
||||
return nocachedHasher.computeFieldRoots(state)
|
||||
return nocachedHasher.computeFieldRootsWithHasher(state)
|
||||
}
|
||||
|
||||
func (h *stateRootHasher) computeFieldRoots(state *pb.BeaconState) ([][]byte, error) {
|
||||
func (h *stateRootHasher) computeFieldRootsWithHasher(state *pb.BeaconState) ([][]byte, error) {
|
||||
if state == nil {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
@@ -76,7 +81,7 @@ func (h *stateRootHasher) computeFieldRoots(state *pb.BeaconState) ([][]byte, er
|
||||
fieldRoots[3] = forkHashTreeRoot[:]
|
||||
|
||||
// BeaconBlockHeader data structure root.
|
||||
headerHashTreeRoot, err := BlockHeaderRoot(state.LatestBlockHeader)
|
||||
headerHashTreeRoot, err := blockHeaderRoot(state.LatestBlockHeader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute block header merkleization")
|
||||
}
|
||||
@@ -104,14 +109,14 @@ func (h *stateRootHasher) computeFieldRoots(state *pb.BeaconState) ([][]byte, er
|
||||
fieldRoots[7] = historicalRootsRt[:]
|
||||
|
||||
// Eth1Data data structure root.
|
||||
eth1HashTreeRoot, err := Eth1Root(hasher, state.Eth1Data)
|
||||
eth1HashTreeRoot, err := eth1Root(hasher, state.Eth1Data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute eth1data merkleization")
|
||||
}
|
||||
fieldRoots[8] = eth1HashTreeRoot[:]
|
||||
|
||||
// Eth1DataVotes slice root.
|
||||
eth1VotesRoot, err := Eth1DataVotesRoot(state.Eth1DataVotes)
|
||||
eth1VotesRoot, err := eth1DataVotesRoot(state.Eth1DataVotes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute eth1data votes merkleization")
|
||||
}
|
||||
@@ -131,7 +136,7 @@ func (h *stateRootHasher) computeFieldRoots(state *pb.BeaconState) ([][]byte, er
|
||||
fieldRoots[11] = validatorsRoot[:]
|
||||
|
||||
// Balances slice root.
|
||||
balancesRoot, err := ValidatorBalancesRoot(state.Balances)
|
||||
balancesRoot, err := validatorBalancesRoot(state.Balances)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute validator balances merkleization")
|
||||
}
|
||||
@@ -210,7 +210,7 @@ func handleEth1DataSlice(val []*ethpb.Eth1Data, indices []uint64, convertAll boo
|
||||
roots := make([][32]byte, 0, length)
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
rootCreator := func(input *ethpb.Eth1Data) error {
|
||||
newRoot, err := stateutil.Eth1Root(hasher, input)
|
||||
newRoot, err := eth1Root(hasher, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func handleValidatorSlice(val []*ethpb.Validator, indices []uint64, convertAll b
|
||||
roots := make([][32]byte, 0, length)
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
rootCreator := func(input *ethpb.Validator) error {
|
||||
newRoot, err := stateutil.ValidatorRoot(hasher, input)
|
||||
newRoot, err := ValidatorRoot(hasher, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -286,7 +286,7 @@ func handlePendingAttestation(val []*pb.PendingAttestation, indices []uint64, co
|
||||
roots := make([][32]byte, 0, length)
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
rootCreator := func(input *pb.PendingAttestation) error {
|
||||
newRoot, err := stateutil.PendingAttestationRoot(hasher, input)
|
||||
newRoot, err := pendingAttestationRoot(hasher, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -19,7 +18,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
|
||||
// 5 represents the enum value of state roots
|
||||
trie, err := state.NewFieldTrie(5, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
require.NoError(t, err)
|
||||
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "StateRoots")
|
||||
root, err := state.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "StateRoots")
|
||||
require.NoError(t, err)
|
||||
newRoot, err := trie.TrieRoot()
|
||||
require.NoError(t, err)
|
||||
@@ -47,7 +46,7 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
|
||||
require.NoError(t, newState.UpdateValidatorAtIndex(types.ValidatorIndex(changedIdx[0]), changedVals[0]))
|
||||
require.NoError(t, newState.UpdateValidatorAtIndex(types.ValidatorIndex(changedIdx[1]), changedVals[1]))
|
||||
|
||||
expectedRoot, err := stateutil.ValidatorRegistryRoot(newState.Validators())
|
||||
expectedRoot, err := state.ValidatorRegistryRoot(newState.Validators())
|
||||
require.NoError(t, err)
|
||||
root, err := trie.RecomputeTrie(changedIdx, newState.Validators())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -183,7 +183,7 @@ func (b *BeaconState) HashTreeRoot(ctx context.Context) ([32]byte, error) {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
if b.merkleLayers == nil || len(b.merkleLayers) == 0 {
|
||||
fieldRoots, err := stateutil.ComputeFieldRoots(b.state)
|
||||
fieldRoots, err := computeFieldRoots(b.state)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
@@ -269,7 +269,7 @@ func (b *BeaconState) rootSelector(field fieldIndex) ([32]byte, error) {
|
||||
case fork:
|
||||
return htrutils.ForkRoot(b.state.Fork)
|
||||
case latestBlockHeader:
|
||||
return stateutil.BlockHeaderRoot(b.state.LatestBlockHeader)
|
||||
return blockHeaderRoot(b.state.LatestBlockHeader)
|
||||
case blockRoots:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.state.BlockRoots, uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
@@ -295,7 +295,7 @@ func (b *BeaconState) rootSelector(field fieldIndex) ([32]byte, error) {
|
||||
case historicalRoots:
|
||||
return htrutils.HistoricalRootsRoot(b.state.HistoricalRoots)
|
||||
case eth1Data:
|
||||
return stateutil.Eth1Root(hasher, b.state.Eth1Data)
|
||||
return eth1Root(hasher, b.state.Eth1Data)
|
||||
case eth1DataVotes:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.state.Eth1DataVotes, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))))
|
||||
@@ -319,7 +319,7 @@ func (b *BeaconState) rootSelector(field fieldIndex) ([32]byte, error) {
|
||||
}
|
||||
return b.recomputeFieldTrie(validators, b.state.Validators)
|
||||
case balances:
|
||||
return stateutil.ValidatorBalancesRoot(b.state.Balances)
|
||||
return validatorBalancesRoot(b.state.Balances)
|
||||
case randaoMixes:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.state.RandaoMixes, uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
|
||||
@@ -4,14 +4,9 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"arrays.go",
|
||||
"attestations.go",
|
||||
"blocks.go",
|
||||
"reference.go",
|
||||
"state_root.go",
|
||||
"trie_helpers.go",
|
||||
"validator_map_handler.go",
|
||||
"validators.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil",
|
||||
visibility = [
|
||||
@@ -28,14 +23,9 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/htrutils:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
@@ -53,6 +43,7 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
|
||||
@@ -2,7 +2,9 @@ package stateutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/htrutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
@@ -33,6 +35,32 @@ func ReturnTrieLayer(elements [][32]byte, length uint64) [][]*[32]byte {
|
||||
return refLayers
|
||||
}
|
||||
|
||||
func merkleizeTrieLeaves(layers [][][32]byte, hashLayer [][32]byte,
|
||||
hasher func([]byte) [32]byte) ([][][32]byte, [][32]byte) {
|
||||
// We keep track of the hash layers of a Merkle trie until we reach
|
||||
// the top layer of length 1, which contains the single root element.
|
||||
// [Root] -> Top layer has length 1.
|
||||
// [E] [F] -> This layer has length 2.
|
||||
// [A] [B] [C] [D] -> The bottom layer has length 4 (needs to be a power of two).
|
||||
i := 1
|
||||
chunkBuffer := bytes.NewBuffer([]byte{})
|
||||
chunkBuffer.Grow(64)
|
||||
for len(hashLayer) > 1 && i < len(layers) {
|
||||
layer := make([][32]byte, len(hashLayer)/2)
|
||||
for j := 0; j < len(hashLayer); j += 2 {
|
||||
chunkBuffer.Write(hashLayer[j][:])
|
||||
chunkBuffer.Write(hashLayer[j+1][:])
|
||||
hashedChunk := hasher(chunkBuffer.Bytes())
|
||||
layer[j/2] = hashedChunk
|
||||
chunkBuffer.Reset()
|
||||
}
|
||||
hashLayer = layer
|
||||
layers[i] = hashLayer
|
||||
i++
|
||||
}
|
||||
return layers, hashLayer
|
||||
}
|
||||
|
||||
// ReturnTrieLayerVariable returns the representation of a merkle trie when
|
||||
// provided with the elements of a variable sized trie and the corresponding depth of
|
||||
// it.
|
||||
@@ -213,3 +241,16 @@ func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte
|
||||
}
|
||||
return root, layers, nil
|
||||
}
|
||||
|
||||
// AddInMixin describes a method from which a lenth mixin is added to the
|
||||
// provided root.
|
||||
func AddInMixin(root [32]byte, length uint64) ([32]byte, error) {
|
||||
rootBuf := new(bytes.Buffer)
|
||||
if err := binary.Write(rootBuf, binary.LittleEndian, length); err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not marshal eth1data votes length")
|
||||
}
|
||||
// We need to mix in the length of the slice.
|
||||
rootBufRoot := make([]byte, 32)
|
||||
copy(rootBufRoot, rootBuf.Bytes())
|
||||
return htrutils.MixInLength(root, rootBufRoot), nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
@@ -16,7 +17,7 @@ import (
|
||||
|
||||
func TestReturnTrieLayer_OK(t *testing.T) {
|
||||
newState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
|
||||
root, err := state.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
|
||||
require.NoError(t, err)
|
||||
blockRts := newState.BlockRoots()
|
||||
roots := make([][32]byte, 0, len(blockRts))
|
||||
@@ -30,13 +31,13 @@ func TestReturnTrieLayer_OK(t *testing.T) {
|
||||
|
||||
func TestReturnTrieLayerVariable_OK(t *testing.T) {
|
||||
newState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
root, err := stateutil.ValidatorRegistryRoot(newState.Validators())
|
||||
root, err := state.ValidatorRegistryRoot(newState.Validators())
|
||||
require.NoError(t, err)
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
validators := newState.Validators()
|
||||
roots := make([][32]byte, 0, len(validators))
|
||||
for _, val := range validators {
|
||||
rt, err := stateutil.ValidatorRoot(hasher, val)
|
||||
rt, err := state.ValidatorRoot(hasher, val)
|
||||
require.NoError(t, err)
|
||||
roots = append(roots, rt)
|
||||
}
|
||||
@@ -61,7 +62,7 @@ func TestRecomputeFromLayer_FixedSizedArray(t *testing.T) {
|
||||
require.NoError(t, newState.UpdateBlockRootAtIndex(changedIdx[0], changedRoots[0]))
|
||||
require.NoError(t, newState.UpdateBlockRootAtIndex(changedIdx[1], changedRoots[1]))
|
||||
|
||||
expectedRoot, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
|
||||
expectedRoot, err := state.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
|
||||
require.NoError(t, err)
|
||||
root, _, err := stateutil.RecomputeFromLayer(changedRoots, changedIdx, layers)
|
||||
require.NoError(t, err)
|
||||
@@ -74,7 +75,7 @@ func TestRecomputeFromLayer_VariableSizedArray(t *testing.T) {
|
||||
hasher := hashutil.CustomSHA256Hasher()
|
||||
roots := make([][32]byte, 0, len(validators))
|
||||
for _, val := range validators {
|
||||
rt, err := stateutil.ValidatorRoot(hasher, val)
|
||||
rt, err := state.ValidatorRoot(hasher, val)
|
||||
require.NoError(t, err)
|
||||
roots = append(roots, rt)
|
||||
}
|
||||
@@ -95,11 +96,11 @@ func TestRecomputeFromLayer_VariableSizedArray(t *testing.T) {
|
||||
require.NoError(t, newState.UpdateValidatorAtIndex(types.ValidatorIndex(changedIdx[0]), changedVals[0]))
|
||||
require.NoError(t, newState.UpdateValidatorAtIndex(types.ValidatorIndex(changedIdx[1]), changedVals[1]))
|
||||
|
||||
expectedRoot, err := stateutil.ValidatorRegistryRoot(newState.Validators())
|
||||
expectedRoot, err := state.ValidatorRegistryRoot(newState.Validators())
|
||||
require.NoError(t, err)
|
||||
roots = make([][32]byte, 0, len(changedVals))
|
||||
for _, val := range changedVals {
|
||||
rt, err := stateutil.ValidatorRoot(hasher, val)
|
||||
rt, err := state.ValidatorRoot(hasher, val)
|
||||
require.NoError(t, err)
|
||||
roots = append(roots, rt)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user