Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recheck consensus test #72

Merged
merged 15 commits into from
Nov 4, 2024
180 changes: 107 additions & 73 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package consensus
// uses rpc
// uses config for networks
// uses common for datatypes

import (
"bytes"
"encoding/hex"
Expand All @@ -21,12 +22,15 @@ import (
"github.com/BlocSoc-iitr/selene/config/checkpoints"
"github.com/BlocSoc-iitr/selene/consensus/consensus_core"
"github.com/BlocSoc-iitr/selene/consensus/rpc"

"github.com/BlocSoc-iitr/selene/utils"
"github.com/BlocSoc-iitr/selene/utils/bls"
beacon "github.com/ethereum/go-ethereum/beacon/types"
geth "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
"github.com/pkg/errors"
bls "github.com/protolambda/bls12-381-util"
)

// Error definitions
Expand Down Expand Up @@ -298,32 +302,26 @@ func (in *Inner) get_execution_payload(slot *uint64) (*consensus_core.ExecutionP
}

block := <-blockChan
blockHash, err := utils.TreeHashRoot(block.Body.ToBytes())
Gethblock, err := beacon.BlockFromJSON("capella", block.Body.Hash)
if err != nil {
return nil, err
}
blockHash := Gethblock.Root()
latestSlot := in.Store.OptimisticHeader.Slot
finalizedSlot := in.Store.FinalizedHeader.Slot

var verifiedBlockHash []byte
var errGettingBlockHash error
var verifiedBlockHash geth.Hash

if *slot == latestSlot {
verifiedBlockHash, errGettingBlockHash = utils.TreeHashRoot(in.Store.OptimisticHeader.ToBytes())
if errGettingBlockHash != nil {
return nil, ErrPayloadNotFound
}
verifiedBlockHash = toGethHeader(&in.Store.OptimisticHeader).Hash()
} else if *slot == finalizedSlot {
verifiedBlockHash, errGettingBlockHash = utils.TreeHashRoot(in.Store.FinalizedHeader.ToBytes())
if errGettingBlockHash != nil {
return nil, ErrPayloadNotFound
}
verifiedBlockHash = toGethHeader(&in.Store.FinalizedHeader).Hash()
} else {
return nil, ErrPayloadNotFound
}

// Compare the hashes
if !bytes.Equal(verifiedBlockHash, blockHash) {
if !bytes.Equal(verifiedBlockHash[:], blockHash.Bytes()) {
return nil, fmt.Errorf("%w: expected %v but got %v", ErrInvalidHeaderHash, verifiedBlockHash, blockHash)
}

Expand Down Expand Up @@ -448,7 +446,6 @@ func (in *Inner) sync(checkpoint [32]byte) error {
// Perform bootstrap with the given checkpoint
in.bootstrap(checkpoint)


currentPeriod := utils.CalcSyncPeriod(in.Store.FinalizedHeader.Slot)

errorChan := make(chan error, 1)
Expand All @@ -471,9 +468,11 @@ func (in *Inner) sync(checkpoint [32]byte) error {

finalityUpdate, err := in.RPC.GetFinalityUpdate()
if err != nil {

errorChan <- err
return
}

if err := in.verify_finality_update(&finalityUpdate); err != nil {
errorChan <- err
return
Expand Down Expand Up @@ -563,7 +562,6 @@ func (in *Inner) bootstrap(checkpoint [32]byte) {
bootstrapChan := make(chan consensus_core.Bootstrap, 1)
go func() {
bootstrap, errInBootstrap := in.RPC.GetBootstrap(checkpoint)

if errInBootstrap != nil {
log.Printf("failed to fetch bootstrap: %v", errInBootstrap)
errorChan <- errInBootstrap
Expand All @@ -577,13 +575,10 @@ func (in *Inner) bootstrap(checkpoint [32]byte) {
}
bootstrap := <-bootstrapChan



isValid := in.is_valid_checkpoint(bootstrap.Header.Slot)
if !isValid {
if in.Config.StrictCheckpointAge {
log.Printf("checkpoint too old, consider using a more recent checkpoint")
return
panic("checkpoint too old, consider using a more recent checkpoint")
} else {
log.Printf("checkpoint too old, consider using a more recent checkpoint")
}
Expand All @@ -600,11 +595,8 @@ func verify_bootstrap(checkpoint [32]byte, bootstrap consensus_core.Bootstrap) {
return
}

headerHash, err := utils.TreeHashRoot(bootstrap.Header.ToBytes())
if err != nil {
log.Println("failed to hash header")
return
}
headerHash := toGethHeader(&bootstrap.Header).Hash()

HeaderValid := bytes.Equal(headerHash[:], checkpoint[:])

if !HeaderValid {
Expand Down Expand Up @@ -666,16 +658,15 @@ func (in *Inner) verify_generic_update(update *GenericUpdate, expectedCurrentSlo
if !isFinalityProofValid(&update.AttestedHeader, &update.FinalizedHeader, update.FinalityBranch) {
return ErrInvalidFinalityProof
}
} else if update.FinalizedHeader != (consensus_core.Header{}) {
} else if (update.FinalizedHeader != (consensus_core.Header{}) && update.FinalityBranch == nil) || (update.FinalizedHeader == (consensus_core.Header{}) && update.FinalityBranch != nil) {
return ErrInvalidFinalityProof
}

// Validate next sync committee and its branch
if update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch != nil {
if !isNextCommitteeProofValid(&update.AttestedHeader, update.NextSyncCommittee, *update.NextSyncCommitteeBranch) {
return ErrInvalidNextSyncCommitteeProof
}
} else if update.NextSyncCommittee != nil {
} else if (update.NextSyncCommittee != nil && update.NextSyncCommitteeBranch == nil) || (update.NextSyncCommittee == nil && update.NextSyncCommitteeBranch != nil) {
return ErrInvalidNextSyncCommitteeProof
}

Expand All @@ -686,16 +677,15 @@ func (in *Inner) verify_generic_update(update *GenericUpdate, expectedCurrentSlo
} else {
syncCommittee = in.Store.NextSyncCommitee
}
pks, err := utils.GetParticipatingKeys(syncCommittee, update.SyncAggregate.SyncCommitteeBits)
_, err := utils.GetParticipatingKeys(syncCommittee, [64]byte(update.SyncAggregate.SyncCommitteeBits))
if err != nil {
return fmt.Errorf("failed to get participating keys: %w", err)
}

forkVersion := utils.CalculateForkVersion(&forks, update.SignatureSlot)
forkDataRoot := utils.ComputeForkDataRoot(forkVersion, consensus_core.Bytes32(in.Config.Chain.GenesisRoot))

forkDataRoot := utils.ComputeForkDataRoot(forkVersion, consensus_core.Bytes32(genesisRoots))

if !verifySyncCommitteeSignature(pks, &update.AttestedHeader, &update.SyncAggregate.SyncCommitteeSignature, forkDataRoot) {
if !verifySyncCommitteeSignature(syncCommittee.Pubkeys, &update.AttestedHeader, &update.SyncAggregate, forkDataRoot) {
return ErrInvalidSignature
}

Expand All @@ -715,6 +705,9 @@ func (in *Inner) verify_update(update *consensus_core.Update) error {
return in.verify_generic_update(&genUpdate, in.expected_current_slot(), &in.Store, in.Config.Chain.GenesisRoot, in.Config.Forks)
}
func (in *Inner) verify_finality_update(update *consensus_core.FinalityUpdate) error {
if update == nil {
return ErrInvalidUpdate
}
genUpdate := GenericUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
Expand Down Expand Up @@ -795,11 +788,9 @@ func (in *Inner) apply_generic_update(store *LightClientStore, update *GenericUp
}

if store.FinalizedHeader.Slot%32 == 0 {
checkpoint, err := utils.TreeHashRoot(store.FinalizedHeader.ToBytes())
if err != nil {
return nil
}
return &checkpoint
checkpoint := toGethHeader(&store.FinalizedHeader).Hash()
checkpointBytes := checkpoint.Bytes()
return &checkpointBytes
}
}
}
Expand Down Expand Up @@ -895,38 +886,57 @@ func (in *Inner) safety_threshold() uint64 {
func verifySyncCommitteeSignature(
pks []consensus_core.BLSPubKey, // Public keys slice
attestedHeader *consensus_core.Header, // Attested header
signature *consensus_core.SignatureBytes, // Signature bytes
signature *consensus_core.SyncAggregate, // Signature bytes
forkDataRoot consensus_core.Bytes32, // Fork data root
) bool {
// Collect public keys as references (or suitable Go struct)
collectedPks := make([]*consensus_core.BLSPubKey, len(pks))
for i := range pks {
collectedPks[i] = &pks[i]
}

// Compute headerRoot
headerRoot, err := utils.TreeHashRoot(attestedHeader.ToBytes())
if err != nil {
if signature == nil {
fmt.Println("no signature")
return false
}
var headerRootBytes consensus_core.Bytes32
copy(headerRootBytes[:], headerRoot[:])
// Compute signingRoot
signingRoot := ComputeCommitteeSignRoot(headerRootBytes, forkDataRoot)
var g2Points []*bls.G2Point
for _, pk := range collectedPks {
var g2Point bls.G2Point
errWhileCoonvertingtoG2 := g2Point.Unmarshal(pk[:])

if errWhileCoonvertingtoG2 != nil {

// Create a slice to hold the collected public keys.
collectedPks := make([]*bls.Pubkey, 0, len(pks))
for i := range pks {
var pksinBytes [48]byte = [48]byte(pks[i])
dkey := new(bls.Pubkey)
err := dkey.Deserialize(&pksinBytes)
if err != nil {
fmt.Println("error deserializing public key:", err)
return false
}

// Include the public key only if the corresponding SyncCommitteeBits bit is set.
if signature.SyncCommitteeBits[i/8]&(byte(1)<<(i%8)) != 0 {
collectedPks = append(collectedPks, dkey)
}
}

// Compute signingRoot.
signingRoot := ComputeCommitteeSignRoot(toGethHeader(attestedHeader), forkDataRoot)

var sig bls.Signature
signatureForUnmarshalling := [96]byte(signature.SyncCommitteeSignature)

// Deserialize the signature.
if err := sig.Deserialize(&signatureForUnmarshalling); err != nil {
fmt.Println("error deserializing signature:", err)
return false
}

return utils.IsAggregateValid(*signature, signingRoot, g2Points)
// Check if we have collected any public keys before proceeding.
if len(collectedPks) == 0 {
fmt.Println("no valid public keys collected")
return false
}



return utils.FastAggregateVerify(collectedPks, signingRoot[:], &sig)

}

func ComputeCommitteeSignRoot(header consensus_core.Bytes32, fork consensus_core.Bytes32) consensus_core.Bytes32 {
func ComputeCommitteeSignRoot(header *beacon.Header, fork consensus_core.Bytes32) consensus_core.Bytes32 {
// Domain type for the sync committee
domainType := [4]byte{7, 0, 0, 0}

Expand Down Expand Up @@ -960,27 +970,18 @@ func (in *Inner) is_valid_checkpoint(blockHashSlot uint64) bool {
}

func isFinalityProofValid(attestedHeader *consensus_core.Header, finalizedHeader *consensus_core.Header, finalityBranch []consensus_core.Bytes32) bool {
finalityBranchForProof, err := utils.BranchToNodes(finalityBranch)
if err != nil {
return false
}
return utils.IsProofValid(attestedHeader, finalizedHeader.ToBytes(), finalityBranchForProof, 6, 41)

return utils.IsProofValid(attestedHeader, toGethHeader(finalizedHeader).Hash(), finalityBranch, 6, 105)
}

func isCurrentCommitteeProofValid(attestedHeader *consensus_core.Header, currentCommittee *consensus_core.SyncCommittee, currentCommitteeBranch []consensus_core.Bytes32) bool {
CurrentCommitteeForProof, err := utils.BranchToNodes(currentCommitteeBranch)
if err != nil {
return false
}
return utils.IsProofValid(attestedHeader, currentCommittee.ToBytes(), CurrentCommitteeForProof, 5, 22)

return utils.IsProofValid(attestedHeader, toGethSyncCommittee(currentCommittee).Root(), currentCommitteeBranch, 5, 54)
}

func isNextCommitteeProofValid(attestedHeader *consensus_core.Header, currentCommittee *consensus_core.SyncCommittee, currentCommitteeBranch []consensus_core.Bytes32) bool {
currentCommitteeBranchForProof, err := utils.BranchToNodes(currentCommitteeBranch)
if err != nil {
return false
}
return utils.IsProofValid(attestedHeader, currentCommittee.ToBytes(), currentCommitteeBranchForProof, 5, 23)
func isNextCommitteeProofValid(attestedHeader *consensus_core.Header, nextCommittee *consensus_core.SyncCommittee, nextCommitteeBranch []consensus_core.Bytes32) bool {

return utils.IsProofValid(attestedHeader, toGethSyncCommittee(nextCommittee).Root(), nextCommitteeBranch, 5, 55)
}

func PayloadToBlock(value *consensus_core.ExecutionPayload) (*common.Block, error) {
Expand Down Expand Up @@ -1142,3 +1143,36 @@ func SomeGasPrice(gasFeeCap, gasTipCap *big.Int, baseFeePerGas uint64) *big.Int
}
return maxGasPrice
}

func toGethHeader(header *consensus_core.Header) *beacon.Header {
return &beacon.Header{
Slot: header.Slot,
ProposerIndex: header.ProposerIndex,
ParentRoot: [32]byte(header.ParentRoot),
StateRoot: [32]byte(header.StateRoot),
BodyRoot: [32]byte(header.BodyRoot),
}
}

type jsonSyncCommittee struct {
Pubkeys []hexutil.Bytes
Aggregate hexutil.Bytes
}

func toGethSyncCommittee(committee *consensus_core.SyncCommittee) *beacon.SerializedSyncCommittee {
jsoncommittee := &jsonSyncCommittee{
Aggregate: committee.AggregatePubkey[:],
}

for _, pubkey := range committee.Pubkeys {
jsoncommittee.Pubkeys = append(jsoncommittee.Pubkeys, pubkey[:])
}

var s beacon.SerializedSyncCommittee

for i, key := range jsoncommittee.Pubkeys {
copy(s[i*48:], key[:])
}
copy(s[512*48:], jsoncommittee.Aggregate[:])
return &s
}
Loading
Loading