Skip to content

Commit

Permalink
added TxDependency Metadata to ExtraData in Block Header in Bor for B…
Browse files Browse the repository at this point in the history
…lock-STM
  • Loading branch information
pratikspatil024 committed Sep 23, 2023
1 parent 71082b0 commit bd1086e
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 18 deletions.
65 changes: 48 additions & 17 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,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 @@ -145,11 +142,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 @@ -477,7 +474,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(header.GetValidatorBytes(c.config))
if !isSprintEnd && signersBytes != 0 {
return errExtraValidators
}
Expand Down Expand Up @@ -517,11 +514,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 @@ -598,7 +595,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t

sort.Sort(valset.ValidatorsByAddress(producerSet))

headerVals, err := valset.ParseValidators(header.Extra[extraVanity : len(header.Extra)-extraSeal])
headerVals, err := valset.ParseValidators(header.GetValidatorBytes(c.config))

if err != nil {
return err
Expand All @@ -622,7 +619,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
// verify the validator list in the last sprint block
if isSprintStart(number, sprintLength) {
// Retrieve the snapshot needed to verify this header and cache it
parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
parentValidatorBytes := parent.GetValidatorBytes(c.config)
validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)

currentValidators := snap.ValidatorSet.Copy().Validators
Expand Down Expand Up @@ -869,11 +866,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 @@ -889,13 +886,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) {
var tempValidatorBytes []byte

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

blockExtraData := &types.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) {
blockExtraData := &types.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 @@ -1116,7 +1147,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)

// Wait until sealing is terminated or delay timeout.
c.logger.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay", common.PrettyDuration(delay), "TxCount", block.Transactions().Len(), "Signer", signer)
Expand Down
2 changes: 1 addition & 1 deletion consensus/bor/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (s *Snapshot) apply(headers []*types.Header, logger log.Logger) (*Snapshot,
if err := validateHeaderExtraField(header.Extra); err != nil {
return nil, err
}
validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
validatorBytes := header.GetValidatorBytes(s.config)

// get validators from headers and use that for new validator set
newVals, _ := valset.ParseValidators(validatorBytes)
Expand Down
51 changes: 51 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ import (
"sync/atomic"

"github.com/gballet/go-verkle"
"github.com/ledgerwatch/erigon-lib/chain"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/common/hexutility"
rlp2 "github.com/ledgerwatch/erigon-lib/rlp"
"github.com/ledgerwatch/log/v3"

"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/hexutil"
Expand All @@ -41,8 +43,22 @@ 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
)

// 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
}

// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
Expand Down Expand Up @@ -1492,6 +1508,41 @@ func (b *Block) ParentBeaconBlockRoot() *libcommon.Hash { return b.header.Parent
func (b *Block) Header() *Header { return CopyHeader(b.header) }
func (b *Block) HeaderNoCopy() *Header { return b.header }

// Returns the Block-STM Transaction Dependency from the block header
func (b *Block) GetTxDependency() [][]uint64 {
if len(b.header.Extra) < ExtraVanityLength+ExtraSealLength {
log.Error("length of extra less is than vanity and seal")
return nil
}

var blockExtraData BlockExtraData
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
}

func (h *Header) GetValidatorBytes(config *chain.BorConfig) []byte {
if !config.IsParallelUniverse(h.Number) {
return h.Extra[ExtraVanityLength : len(h.Extra)-ExtraSealLength]
}

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

var blockExtraData BlockExtraData
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
}

// Body returns the non-header content of the block.
func (b *Block) Body() *Body {
bd := &Body{Transactions: b.transactions, Uncles: b.uncles, Withdrawals: b.withdrawals}
Expand Down
55 changes: 55 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,60 @@ import (
"github.com/ledgerwatch/erigon/rlp"
)

// This is a replica of `(h *Header) 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 BlockExtraData
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 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 := block.GetTxDependency()

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) {
blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0")
Expand Down

0 comments on commit bd1086e

Please sign in to comment.