Skip to content
Open
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
21 changes: 17 additions & 4 deletions consensus/istanbul/qbft/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package qbftengine

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math/big"
"reflect"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -76,7 +79,9 @@ func writeCommittedSeals(committedSeals [][]byte) ApplyQBFTExtra {
// writeRoundNumber writes the extra-data field of a block header with given round.
func writeRoundNumber(round *big.Int) ApplyQBFTExtra {
return func(qbftExtra *types.QBFTExtra) error {
qbftExtra.Round = uint32(round.Uint64())
a := make([]byte, 4)
binary.BigEndian.PutUint32(a, uint32(round.Uint64()))
qbftExtra.Round = a
return nil
}
}
Expand Down Expand Up @@ -436,7 +441,7 @@ func (e *Engine) Signers(header *types.Header) ([]common.Address, error) {
return []common.Address{}, err
}
committedSeal := extra.CommittedSeal
proposalSeal := PrepareCommittedSeal(header, extra.Round)
proposalSeal := PrepareCommittedSeal(header, binary.BigEndian.Uint32(extra.Round))

var addrs []common.Address
// 1. Get committed seals from current header
Expand Down Expand Up @@ -531,7 +536,7 @@ func getExtra(header *types.Header) (*types.QBFTExtra, error) {
VanityData: vanity,
Validators: []common.Address{},
CommittedSeal: [][]byte{},
Round: 0,
Round: make([]byte, 0),
Vote: nil,
}, nil
}
Expand All @@ -545,7 +550,15 @@ func setExtra(h *types.Header, qbftExtra *types.QBFTExtra) error {
if err != nil {
return err
}

// security check
t := &types.QBFTExtra{}
err = rlp.DecodeBytes(payload, t)
if err != nil {
return err
}
if !reflect.DeepEqual(t, qbftExtra) {
return errors.New("encoding of QBFT extra mismatch")
}
h.Extra = payload
return nil
}
Expand Down
188 changes: 101 additions & 87 deletions consensus/istanbul/qbft/engine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package qbftengine

import (
"bytes"
"encoding/binary"
"math/big"
"reflect"
"testing"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
istanbulcommon "github.com/ethereum/go-ethereum/consensus/istanbul/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"
)

func TestPrepareExtra(t *testing.T) {
Expand All @@ -19,7 +21,7 @@ func TestPrepareExtra(t *testing.T) {
validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6"))
validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440"))

expectedResult := hexutil.MustDecode("0xf87aa00000000000000000000000000000000000000000000000000000000000000000f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c080c0")
expectedResult := "0xf87aa00000000000000000000000000000000000000000000000000000000000000000f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b4408080c0"

h := &types.Header{}
err := ApplyHeaderQBFTExtra(
Expand All @@ -29,109 +31,121 @@ func TestPrepareExtra(t *testing.T) {
if err != nil {
t.Errorf("error mismatch: have %v, want: nil", err)
}
if !reflect.DeepEqual(h.Extra, expectedResult) {
t.Errorf("payload mismatch: have %v, want %v", h.Extra, expectedResult)
}
result := hexutil.Encode(h.Extra)
assert.Equal(t, expectedResult, result)
}

func TestWriteCommittedSeals(t *testing.T) {
istRawData := hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c080c0")
expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...)
expectedIstExtra := &types.QBFTExtra{
VanityData: []byte{},
Validators: []common.Address{
common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
},
CommittedSeal: [][]byte{expectedCommittedSeal},
Round: 0,
Vote: nil,
}

h := &types.Header{
Extra: istRawData,
}

// normal case
err := ApplyHeaderQBFTExtra(
h,
writeCommittedSeals([][]byte{expectedCommittedSeal}),
)
if err != nil {
t.Errorf("error mismatch: have %v, want: nil", err)
}

// verify istanbul extra-data
istExtra, err := getExtra(h)
if err != nil {
t.Errorf("error mismatch: have %v, want nil", err)
}
if !reflect.DeepEqual(istExtra, expectedIstExtra) {
t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
}

// invalid seal
unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...)
err = ApplyHeaderQBFTExtra(
h,
writeCommittedSeals([][]byte{unexpectedCommittedSeal}),
)
if err != istanbulcommon.ErrInvalidCommittedSeals {
t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrInvalidCommittedSeals)
for _, istRawData := range [][]byte{
hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c080c0"),
hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b4408080c0"),
} {
expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...)
expectedIstExtra := &types.QBFTExtra{
VanityData: []byte{},
Validators: []common.Address{
common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
},
CommittedSeal: [][]byte{expectedCommittedSeal},
Round: make([]byte, 0),
Vote: nil,
}

h := &types.Header{
Extra: istRawData,
}

// normal case
err := ApplyHeaderQBFTExtra(
h,
writeCommittedSeals([][]byte{expectedCommittedSeal}),
)
if err != nil {
t.Errorf("error mismatch: have %v, want: nil", err)
}

// verify istanbul extra-data
istExtra, err := getExtra(h)
if err != nil {
t.Errorf("error mismatch: have %v, want nil", err)
}
if !reflect.DeepEqual(istExtra, expectedIstExtra) {
t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
}

// invalid seal
unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...)
err = ApplyHeaderQBFTExtra(
h,
writeCommittedSeals([][]byte{unexpectedCommittedSeal}),
)
if err != istanbulcommon.ErrInvalidCommittedSeals {
t.Errorf("error mismatch: have %v, want %v", err, istanbulcommon.ErrInvalidCommittedSeals)
}
}
}

func TestWriteRoundNumber(t *testing.T) {
istRawData := hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c005c0")
expectedIstExtra := &types.QBFTExtra{
VanityData: []byte{},
Validators: []common.Address{
common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
},
CommittedSeal: [][]byte{},
Round: 5,
Vote: nil,
}

var expectedErr error

h := &types.Header{
Extra: istRawData,
}

// normal case
err := ApplyHeaderQBFTExtra(
h,
writeRoundNumber(big.NewInt(5)),
)
if err != expectedErr {
t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
}

// verify istanbul extra-data
istExtra, err := getExtra(h)
if err != nil {
t.Errorf("error mismatch: have %v, want nil", err)
}
if !reflect.DeepEqual(istExtra, expectedIstExtra) {
t.Errorf("extra data mismatch: have %v, want %v", istExtra.VanityData, expectedIstExtra.VanityData)
testExtraData := [][]byte{
hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b4408005c0"),
hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c005c0"),
}
for _, istRawData := range testExtraData {
round := make([]byte, 4)
binary.BigEndian.PutUint32(round, 5)
expectedIstExtra := &types.QBFTExtra{
VanityData: []byte{},
Validators: []common.Address{
common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
},
CommittedSeal: [][]byte{},
Round: round,
Vote: nil,
}

var expectedErr error

h := &types.Header{
Extra: istRawData,
}

// normal case
err := ApplyHeaderQBFTExtra(
h,
writeRoundNumber(big.NewInt(5)),
)
if err != expectedErr {
t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
}

// verify istanbul extra-data
istExtra, err := getExtra(h)
if err != nil {
t.Errorf("error mismatch: have %v, want nil", err)
} else if istExtra != nil && !reflect.DeepEqual(istExtra, expectedIstExtra) {
t.Errorf("extra data mismatch: have %v, want %v", istExtra.VanityData, expectedIstExtra.VanityData)
} else if istExtra == nil {
t.Errorf("extra data is nil")
}
assert.Equal(t, uint32(5), binary.BigEndian.Uint32(istExtra.Round))
}
}

func TestWriteValidatorVote(t *testing.T) {
vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)
istRawData := hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b440c005c0")
istRawData := hexutil.MustDecode("0xf85a80f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b4408005c0")
vote := &types.ValidatorVote{RecipientAddress: common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f06777123456")), VoteType: types.QBFTAuthVote}
expectedIstExtra := &types.QBFTExtra{
VanityData: vanity,
Validators: []common.Address{},
CommittedSeal: [][]byte{},
Round: 0,
Round: make([]byte, 0),
Vote: vote,
}

Expand Down
2 changes: 1 addition & 1 deletion consensus/istanbul/testutils/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func appendValidators(genesis *core.Genesis, addrs []common.Address) {
Validators: addrs,
Vote: nil,
CommittedSeal: [][]byte{},
Round: 0,
Round: make([]byte, 0),
}

istPayload, err := rlp.EncodeToBytes(&ist)
Expand Down
3 changes: 3 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ type headerMarshaling struct {
func (h *Header) Hash() common.Hash {
// If the mix digest is equivalent to the predefined Istanbul digest, use Istanbul
// specific hash calculation.
if h.Number == nil || h.Number.Uint64() == 0 {
return rlpHash(h)
}
if h.MixDigest == IstanbulDigest {
// Seal is reserved in extra-data. To prove block is signed by the proposer.
if istanbulHeader := FilteredHeader(h); istanbulHeader != nil {
Expand Down
Loading