Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 97 additions & 15 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ var (
"0": 64,
} // Default number of blocks after which to checkpoint and reset the pending votes

extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal

uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.

// diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
Expand Down Expand Up @@ -154,11 +151,11 @@ func Ecrecover(header *types.Header, sigcache *lru.ARCCache[libcommon.Hash, libc
return address, nil
}
// Retrieve the signature from the header extra-data
if len(header.Extra) < extraSeal {
if len(header.Extra) < types.ExtraSealLength {
return libcommon.Address{}, errMissingSignature
}

signature := header.Extra[len(header.Extra)-extraSeal:]
signature := header.Extra[len(header.Extra)-types.ExtraSealLength:]

// Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(SealHash(header, c).Bytes(), signature)
Expand Down Expand Up @@ -542,7 +539,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
isSprintEnd := isSprintStart(number+1, c.config.CalculateSprint(number))

// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
signersBytes := len(header.Extra) - extraVanity - extraSeal
signersBytes := len(GetValidatorBytes(header, c.config))
if !isSprintEnd && signersBytes != 0 {
return errExtraValidators
}
Expand Down Expand Up @@ -584,11 +581,11 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
// ValidateHeaderExtraField validates that the extra-data contains both the vanity and signature.
// header.Extra = header.Vanity + header.ProducerBytes (optional) + header.Seal
func ValidateHeaderExtraField(extraBytes []byte) error {
if len(extraBytes) < extraVanity {
if len(extraBytes) < types.ExtraVanityLength {
return errMissingVanity
}

if len(extraBytes) < extraVanity+extraSeal {
if len(extraBytes) < types.ExtraVanityLength+types.ExtraSealLength {
return errMissingSignature
}

Expand Down Expand Up @@ -917,11 +914,11 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s
header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.authorizedSigner.Load().signer))

// Ensure the extra data has all it's components
if len(header.Extra) < extraVanity {
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
if len(header.Extra) < types.ExtraVanityLength {
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, types.ExtraVanityLength-len(header.Extra))...)
}

header.Extra = header.Extra[:extraVanity]
header.Extra = header.Extra[:types.ExtraVanityLength]

// get validator set if number
// Note: headers.Extra has producer set and not validator set. The bor
Expand All @@ -941,13 +938,47 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s
// sort validator by address
sort.Sort(valset.ValidatorsByAddress(newValidators))

for _, validator := range newValidators {
header.Extra = append(header.Extra, validator.HeaderBytes()...)
if c.config.IsParallelUniverse(header.Number.Uint64()) {
var tempValidatorBytes []byte

for _, validator := range newValidators {
tempValidatorBytes = append(tempValidatorBytes, validator.HeaderBytes()...)
}

blockExtraData := &BlockExtraData{
ValidatorBytes: tempValidatorBytes,
TxDependency: nil,
}

blockExtraDataBytes, err := rlp.EncodeToBytes(blockExtraData)
if err != nil {
log.Error("error while encoding block extra data: %v", err)
return fmt.Errorf("error while encoding block extra data: %v", err)
}

header.Extra = append(header.Extra, blockExtraDataBytes...)
} else {
for _, validator := range newValidators {
header.Extra = append(header.Extra, validator.HeaderBytes()...)
}
}
} else if c.config.IsParallelUniverse(header.Number.Uint64()) {
blockExtraData := &BlockExtraData{
ValidatorBytes: nil,
TxDependency: nil,
}

blockExtraDataBytes, err := rlp.EncodeToBytes(blockExtraData)
if err != nil {
log.Error("error while encoding block extra data: %v", err)
return fmt.Errorf("error while encoding block extra data: %v", err)
}

header.Extra = append(header.Extra, blockExtraDataBytes...)
}

// add extra seal space
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
header.Extra = append(header.Extra, make([]byte, types.ExtraSealLength)...)

// Mix digest is reserved for now, set to empty
header.MixDigest = libcommon.Hash{}
Expand Down Expand Up @@ -1161,7 +1192,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
if err != nil {
return err
}
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
copy(header.Extra[len(header.Extra)-types.ExtraSealLength:], sighash)

go func() {
// Wait until sealing is terminated or delay timeout.
Expand Down Expand Up @@ -1576,3 +1607,54 @@ func getUpdatedValidatorSet(oldValidatorSet *valset.ValidatorSet, newVals []*val
func isSprintStart(number, sprint uint64) bool {
return number%sprint == 0
}

// In bor, RLP encoding of BlockExtraData will be stored in the Extra field in the header
type BlockExtraData struct {
// Validator bytes of bor
ValidatorBytes []byte

// length of TxDependency -> n (n = number of transactions in the block)
// length of TxDependency[i] -> k (k = a whole number)
// k elements in TxDependency[i] -> transaction indexes on which transaction i is dependent on
TxDependency [][]uint64
}

// Returns the Block-STM Transaction Dependency from the block header
func GetTxDependency(b *types.Block) [][]uint64 {
tempExtra := b.Extra()

if len(tempExtra) < types.ExtraVanityLength+types.ExtraSealLength {
log.Error("length of extra less is than vanity and seal")
return nil
}

var blockExtraData BlockExtraData

if err := rlp.DecodeBytes(tempExtra[types.ExtraVanityLength:len(tempExtra)-types.ExtraSealLength], &blockExtraData); err != nil {
log.Error("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.TxDependency
}

func GetValidatorBytes(h *types.Header, config *chain.BorConfig) []byte {
tempExtra := h.Extra

if !config.IsParallelUniverse(h.Number.Uint64()) {
return tempExtra[types.ExtraVanityLength : len(tempExtra)-types.ExtraSealLength]
}

if len(tempExtra) < types.ExtraVanityLength+types.ExtraSealLength {
log.Error("length of extra less is than vanity and seal")
return nil
}

var blockExtraData BlockExtraData
if err := rlp.DecodeBytes(tempExtra[types.ExtraVanityLength:len(tempExtra)-types.ExtraSealLength], &blockExtraData); err != nil {
log.Error("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.ValidatorBytes
}
2 changes: 1 addition & 1 deletion consensus/bor/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (s *Snapshot) Apply(parent *types.Header, headers []*types.Header, logger l
if err := ValidateHeaderExtraField(header.Extra); err != nil {
return snap, err
}
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
validatorBytes := GetValidatorBytes(header, s.config)

// get validators from headers and use that for new validator set
newVals, _ := valset.ParseValidators(validatorBytes)
Expand Down
6 changes: 5 additions & 1 deletion core/types/block.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that these functions should be of the form

bor.GetTxDependency(block *types.Block)
bor.GetValidatorBytes(config *chain.BorConfig, header *types.Header)

This means that the bor specific code is contained in the bor package - and does not complicate the core package

Copy link
Contributor Author

@pratikspatil024 pratikspatil024 Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/ledgerwatch/erigon-lib/common/hexutil"
"io"
"math/big"
"reflect"
"sync/atomic"

"github.com/ledgerwatch/erigon-lib/common/hexutil"

"github.com/gballet/go-verkle"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
Expand All @@ -40,6 +41,9 @@ import (
var (
EmptyRootHash = libcommon.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
EmptyUncleHash = rlpHash([]*Header(nil))

ExtraVanityLength = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
ExtraSealLength = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
)

// A BlockNonce is a 64-bit hash which proves (combined with the
Expand Down
81 changes: 81 additions & 0 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
types2 "github.com/ledgerwatch/erigon-lib/types"
"github.com/ledgerwatch/log/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand All @@ -39,6 +40,86 @@ import (
"github.com/ledgerwatch/erigon/rlp"
)

// the following 2 functions are replica for the test
// This is a replica of `bor.GetValidatorBytes` function
// This was needed because currently, `IsParallelUniverse` will always return false.
func GetValidatorBytesTest(h *Header) []byte {
if len(h.Extra) < ExtraVanityLength+ExtraSealLength {
log.Error("length of extra is less than vanity and seal")
return nil
}

var blockExtraData BlockExtraDataTest
if err := rlp.DecodeBytes(h.Extra[ExtraVanityLength:len(h.Extra)-ExtraSealLength], &blockExtraData); err != nil {
log.Error("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.ValidatorBytes
}

func GetTxDependencyTest(b *Block) [][]uint64 {
if len(b.header.Extra) < ExtraVanityLength+ExtraSealLength {
log.Error("length of extra less is than vanity and seal")
return nil
}

var blockExtraData BlockExtraDataTest
if err := rlp.DecodeBytes(b.header.Extra[ExtraVanityLength:len(b.header.Extra)-ExtraSealLength], &blockExtraData); err != nil {
log.Error("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.TxDependency
}

type BlockExtraDataTest struct {
// Validator bytes of bor
ValidatorBytes []byte

// length of TxDependency -> n (n = number of transactions in the block)
// length of TxDependency[i] -> k (k = a whole number)
// k elements in TxDependency[i] -> transaction indexes on which transaction i is dependent on
TxDependency [][]uint64
}

func TestTxDependencyBlockDecoding(t *testing.T) {
t.Parallel()

blockEnc := common.FromHex("f90270f9026ba00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8825208845506eb07b8710000000000000000000000000000000000000000000000000000000000000000cf8776616c20736574c6c20201c201800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498880000000000000000c0c0")

var block Block

if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
t.Fatal("decode error: ", err)
}
check := func(f string, got, want interface{}) {
if !reflect.DeepEqual(got, want) {
t.Errorf("%s mismatch: got %v, want %v", f, got, want)
}
}

check("Coinbase", block.Coinbase(), libcommon.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), libcommon.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), libcommon.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Time", block.Time(), uint64(1426516743))

validatorBytes := GetValidatorBytesTest(block.header)
txDependency := GetTxDependencyTest(&block)

check("validatorBytes", validatorBytes, []byte("val set"))
check("txDependency", txDependency, [][]uint64{{2, 1}, {1, 0}})

ourBlockEnc, err := rlp.EncodeToBytes(&block)

if err != nil {
t.Fatal("encode error: ", err)
}
if !bytes.Equal(ourBlockEnc, blockEnc) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
}
}

// from bcValidBlockTest.json, "SimpleTx"
func TestBlockEncoding(t *testing.T) {
t.Parallel()
Expand Down
13 changes: 13 additions & 0 deletions erigon-lib/chain/chain_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,8 @@ type BorConfig struct {
AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already in agra)
StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to`

ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes)

sprints sprints
}

Expand Down Expand Up @@ -561,6 +563,17 @@ func (c *BorConfig) IsIndore(number uint64) bool {
return isForked(c.IndoreBlock, number)
}

// TODO: modify this function once the block number is finalized
func (c *BorConfig) IsParallelUniverse(number uint64) bool {
if c.ParallelUniverseBlock != nil {
if c.ParallelUniverseBlock.Cmp(big.NewInt(0)) == 0 {
return false
}
}

return isForked(c.ParallelUniverseBlock, number)
}

func (c *BorConfig) CalculateStateSyncDelay(number uint64) uint64 {
return borKeyValueConfigHelper(c.StateSyncConfirmationDelay, number)
}
Expand Down
5 changes: 3 additions & 2 deletions eth/stagedsync/stage_bor_heimdall.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func BorHeimdallForward(
if !mine && header != nil {
sprintLength := cfg.chainConfig.Bor.CalculateSprint(blockNum)
if blockNum > zerothSpanEnd && ((blockNum+1)%sprintLength == 0) {
if err = checkHeaderExtraData(u, ctx, chain, blockNum, header); err != nil {
if err = checkHeaderExtraData(u, ctx, chain, blockNum, header, cfg.chainConfig.Bor); err != nil {
return err
}
}
Expand Down Expand Up @@ -322,6 +322,7 @@ func checkHeaderExtraData(
chain consensus.ChainHeaderReader,
blockNum uint64,
header *types.Header,
config *chain.BorConfig,
) error {
var spanID uint64
if blockNum+1 > zerothSpanEnd {
Expand All @@ -339,7 +340,7 @@ func checkHeaderExtraData(

sort.Sort(valset.ValidatorsByAddress(producerSet))

headerVals, err := valset.ParseValidators(header.Extra[extraVanity : len(header.Extra)-extraSeal])
headerVals, err := valset.ParseValidators(bor.GetValidatorBytes(header, config))
if err != nil {
return err
}
Expand Down