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

Moved TxDependency Metadata to ExtraData in Block Header #930

Merged
merged 13 commits into from
Jul 19, 2023
54 changes: 36 additions & 18 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,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.

validatorHeaderBytesLength = common.AddressLength + 20 // address + power
Expand Down Expand Up @@ -120,11 +117,11 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig
return address.(common.Address), nil
}
// Retrieve the signature from the header extra-data
if len(header.Extra) < extraSeal {
if len(header.Extra) < types.ExtraSealLength {
return common.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 @@ -355,7 +352,8 @@ 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 @@ -400,11 +398,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 @@ -475,8 +473,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t

sort.Sort(valset.ValidatorsByAddress(newValidators))

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 @@ -494,7 +491,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t

// verify the validator list in the last sprint block
if IsSprintStart(number, c.config.CalculateSprint(number)) {
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 @@ -731,11 +728,11 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
header.Difficulty = new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, currentSigner.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
if IsSprintStart(number+1, c.config.CalculateSprint(number)) {
Expand All @@ -747,13 +744,34 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
// 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()...)
}
}
}

// 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 = common.Hash{}
Expand Down Expand Up @@ -1053,7 +1071,7 @@ func Sign(signFn SignerFn, signer common.Address, header *types.Header, c *param
return err
}

copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
copy(header.Extra[len(header.Extra)-types.ExtraSealLength:], sighash)

return nil
}
Expand Down
7 changes: 6 additions & 1 deletion consensus/bor/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,12 @@
return nil, err
}

validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
var validatorBytes []byte
if s.config.IsParallelUniverse(header.Number) {
validatorBytes = header.GetValidatorBytes()

Check failure on line 155 in consensus/bor/snapshot.go

View workflow job for this annotation

GitHub Actions / tests (ubuntu-20.04)

not enough arguments in call to header.GetValidatorBytes
} else {
validatorBytes = header.Extra[types.ExtraVanityLength : len(header.Extra)-types.ExtraSealLength]
}

// get validators from headers and use that for new validator set
newVals, _ := valset.ParseValidators(validatorBytes)
Expand Down
8 changes: 5 additions & 3 deletions core/parallel_state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,11 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat

coinbase, _ := p.bc.Engine().Author(header)

deps := GetDeps(block.Header().TxDependency)
blockTxDependency := block.GetTxDependency()

if block.Header().TxDependency != nil {
deps := GetDeps(blockTxDependency)

if blockTxDependency != nil {
metadata = true
}

Expand All @@ -308,7 +310,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
shouldDelayFeeCal = false
}

if len(header.TxDependency) != len(block.Transactions()) {
if len(blockTxDependency) != len(block.Transactions()) {
task := &ExecutionTask{
msg: msg,
config: p.config,
Expand Down
63 changes: 49 additions & 14 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)

var (
EmptyRootHash = common.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 Expand Up @@ -87,18 +92,23 @@ type Header struct {
// BaseFee was added by EIP-1559 and is ignored in legacy headers.
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`

// 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 `json:"txDependency" rlp:"optional"`

/*
TODO (MariusVanDerWijden) Add this field once needed
// Random was added during the merge and contains the BeaconState randomness
Random common.Hash `json:"random" rlp:"optional"`
*/
}

// Used for Encoding and Decoding of the Extra Data Field
type BlockExtraData struct {
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
}

// field type overrides for gencodec
type headerMarshaling struct {
Difficulty *hexutil.Big
Expand Down Expand Up @@ -258,14 +268,6 @@ func CopyHeader(h *Header) *Header {
copy(cpy.Extra, h.Extra)
}

if len(h.TxDependency) > 0 {
cpy.TxDependency = make([][]uint64, len(h.TxDependency))

for i, dep := range h.TxDependency {
cpy.TxDependency[i] = make([]uint64, len(dep))
copy(cpy.TxDependency[i], dep)
}
}
return &cpy
}

Expand Down Expand Up @@ -321,7 +323,40 @@ func (b *Block) TxHash() common.Hash { return b.header.TxHash }
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) TxDependency() [][]uint64 { return b.header.TxDependency }

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.Debug("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.TxDependency
}

func (h *Header) GetValidatorBytes(config *params.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.Debug("error while decoding block extra data", "err", err)
return nil
}

return blockExtraData.ValidatorBytes
}

func (b *Block) BaseFee() *big.Int {
if b.header.BaseFee == nil {
Expand Down
19 changes: 9 additions & 10 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ func TestBlockEncoding(t *testing.T) {
}
}

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

blockEnc := common.FromHex("f90268f90201a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c480c6c20201c20180f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0")
blockEnc := common.FromHex("f90270f9026ba00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8825208845506eb07b8710000000000000000000000000000000000000000000000000000000000000000cf8776616c20736574c6c20201c201800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498880000000000000000c0c0")

var block Block

Expand All @@ -91,17 +91,16 @@ func TestTxDependencyBlockEncoding(t *testing.T) {
check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Hash", block.Hash(), common.HexToHash("0xc6d8dc8995c0a4374bb9f87bd0dd8c0761e6e026a71edbfed5e961c9e55dbd6a"))
check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
check("Time", block.Time(), uint64(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
check("TxDependency", block.TxDependency(), [][]uint64{{2, 1}, {1, 0}})

tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil)
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
validatorBytes := block.header.GetValidatorBytes(&params.BorConfig{
ParallelUniverseBlock: big.NewInt(0),
})
txDependency := block.GetTxDependency()

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

check("len(Transactions)", len(block.Transactions()), 1)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
ourBlockEnc, err := rlp.EncodeToBytes(&block)

if err != nil {
Expand Down