github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/eth1_data.go (about)

     1  package blocks
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  
     8  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
     9  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    10  	"github.com/prysmaticlabs/prysm/shared/copyutil"
    11  	"github.com/prysmaticlabs/prysm/shared/params"
    12  )
    13  
    14  // ProcessEth1DataInBlock is an operation performed on each
    15  // beacon block to ensure the ETH1 data votes are processed
    16  // into the beacon state.
    17  //
    18  // Official spec definition:
    19  //   def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
    20  //    state.eth1_data_votes.append(body.eth1_data)
    21  //    if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
    22  //        state.eth1_data = body.eth1_data
    23  func ProcessEth1DataInBlock(_ context.Context, beaconState iface.BeaconState, eth1Data *ethpb.Eth1Data) (iface.BeaconState, error) {
    24  	if beaconState == nil || beaconState.IsNil() {
    25  		return nil, errors.New("nil state")
    26  	}
    27  	if err := beaconState.AppendEth1DataVotes(eth1Data); err != nil {
    28  		return nil, err
    29  	}
    30  	hasSupport, err := Eth1DataHasEnoughSupport(beaconState, eth1Data)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	if hasSupport {
    35  		if err := beaconState.SetEth1Data(eth1Data); err != nil {
    36  			return nil, err
    37  		}
    38  	}
    39  	return beaconState, nil
    40  }
    41  
    42  // AreEth1DataEqual checks equality between two eth1 data objects.
    43  func AreEth1DataEqual(a, b *ethpb.Eth1Data) bool {
    44  	if a == nil && b == nil {
    45  		return true
    46  	}
    47  	if a == nil || b == nil {
    48  		return false
    49  	}
    50  	return a.DepositCount == b.DepositCount &&
    51  		bytes.Equal(a.BlockHash, b.BlockHash) &&
    52  		bytes.Equal(a.DepositRoot, b.DepositRoot)
    53  }
    54  
    55  // Eth1DataHasEnoughSupport returns true when the given eth1data has more than 50% votes in the
    56  // eth1 voting period. A vote is cast by including eth1data in a block and part of state processing
    57  // appends eth1data to the state in the Eth1DataVotes list. Iterating through this list checks the
    58  // votes to see if they match the eth1data.
    59  func Eth1DataHasEnoughSupport(beaconState iface.ReadOnlyBeaconState, data *ethpb.Eth1Data) (bool, error) {
    60  	voteCount := uint64(0)
    61  	data = copyutil.CopyETH1Data(data)
    62  
    63  	for _, vote := range beaconState.Eth1DataVotes() {
    64  		if AreEth1DataEqual(vote, data) {
    65  			voteCount++
    66  		}
    67  	}
    68  
    69  	// If 50+% majority converged on the same eth1data, then it has enough support to update the
    70  	// state.
    71  	support := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))
    72  	return voteCount*2 > uint64(support), nil
    73  }