github.com/bencicandrej/quorum@v2.2.6-0.20190909091323-878cab86f711+incompatible/consensus/istanbul/backend/engine_test.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package backend
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/consensus"
    30  	"github.com/ethereum/go-ethereum/consensus/istanbul"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/core/vm"
    34  	"github.com/ethereum/go-ethereum/crypto"
    35  	"github.com/ethereum/go-ethereum/ethdb"
    36  	"github.com/ethereum/go-ethereum/params"
    37  	"github.com/ethereum/go-ethereum/rlp"
    38  )
    39  
    40  // in this test, we can set n to 1, and it means we can process Istanbul and commit a
    41  // block by one node. Otherwise, if n is larger than 1, we have to generate
    42  // other fake events to process Istanbul.
    43  func newBlockChain(n int) (*core.BlockChain, *backend) {
    44  	genesis, nodeKeys := getGenesisAndKeys(n)
    45  	memDB := ethdb.NewMemDatabase()
    46  	config := istanbul.DefaultConfig
    47  	// Use the first key as private key
    48  	b, _ := New(config, nodeKeys[0], memDB).(*backend)
    49  	genesis.MustCommit(memDB)
    50  	blockchain, err := core.NewBlockChain(memDB, nil, genesis.Config, b, vm.Config{}, nil)
    51  	if err != nil {
    52  		panic(err)
    53  	}
    54  	b.Start(blockchain, blockchain.CurrentBlock, blockchain.HasBadBlock)
    55  	snap, err := b.snapshot(blockchain, 0, common.Hash{}, nil)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	if snap == nil {
    60  		panic("failed to get snapshot")
    61  	}
    62  	proposerAddr := snap.ValSet.GetProposer().Address()
    63  
    64  	// find proposer key
    65  	for _, key := range nodeKeys {
    66  		addr := crypto.PubkeyToAddress(key.PublicKey)
    67  		if addr.String() == proposerAddr.String() {
    68  			b.privateKey = key
    69  			b.address = addr
    70  		}
    71  	}
    72  
    73  	return blockchain, b
    74  }
    75  
    76  func getGenesisAndKeys(n int) (*core.Genesis, []*ecdsa.PrivateKey) {
    77  	// Setup validators
    78  	var nodeKeys = make([]*ecdsa.PrivateKey, n)
    79  	var addrs = make([]common.Address, n)
    80  	for i := 0; i < n; i++ {
    81  		nodeKeys[i], _ = crypto.GenerateKey()
    82  		addrs[i] = crypto.PubkeyToAddress(nodeKeys[i].PublicKey)
    83  	}
    84  
    85  	// generate genesis block
    86  	genesis := core.DefaultGenesisBlock()
    87  	genesis.Config = params.TestChainConfig
    88  	// force enable Istanbul engine
    89  	genesis.Config.Istanbul = &params.IstanbulConfig{}
    90  	genesis.Config.Ethash = nil
    91  	genesis.Difficulty = defaultDifficulty
    92  	genesis.Nonce = emptyNonce.Uint64()
    93  	genesis.Mixhash = types.IstanbulDigest
    94  
    95  	appendValidators(genesis, addrs)
    96  	return genesis, nodeKeys
    97  }
    98  
    99  func appendValidators(genesis *core.Genesis, addrs []common.Address) {
   100  
   101  	if len(genesis.ExtraData) < types.IstanbulExtraVanity {
   102  		genesis.ExtraData = append(genesis.ExtraData, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)...)
   103  	}
   104  	genesis.ExtraData = genesis.ExtraData[:types.IstanbulExtraVanity]
   105  
   106  	ist := &types.IstanbulExtra{
   107  		Validators:    addrs,
   108  		Seal:          []byte{},
   109  		CommittedSeal: [][]byte{},
   110  	}
   111  
   112  	istPayload, err := rlp.EncodeToBytes(&ist)
   113  	if err != nil {
   114  		panic("failed to encode istanbul extra")
   115  	}
   116  	genesis.ExtraData = append(genesis.ExtraData, istPayload...)
   117  }
   118  
   119  func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header {
   120  	header := &types.Header{
   121  		ParentHash: parent.Hash(),
   122  		Number:     parent.Number().Add(parent.Number(), common.Big1),
   123  		GasLimit:   core.CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
   124  		GasUsed:    0,
   125  		Extra:      parent.Extra(),
   126  		Time:       new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)),
   127  		Difficulty: defaultDifficulty,
   128  	}
   129  	return header
   130  }
   131  
   132  func makeBlock(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
   133  	block := makeBlockWithoutSeal(chain, engine, parent)
   134  	stopCh := make(chan struct{})
   135  	resultCh := make(chan *types.Block, 10)
   136  	go engine.Seal(chain, block, resultCh, stopCh)
   137  	blk := <-resultCh
   138  	return blk
   139  }
   140  
   141  func makeBlockWithoutSeal(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
   142  	header := makeHeader(parent, engine.config)
   143  	engine.Prepare(chain, header)
   144  	state, _, _ := chain.StateAt(parent.Root())
   145  	block, _ := engine.Finalize(chain, header, state, nil, nil, nil)
   146  	return block
   147  }
   148  
   149  func TestPrepare(t *testing.T) {
   150  	chain, engine := newBlockChain(1)
   151  	header := makeHeader(chain.Genesis(), engine.config)
   152  	err := engine.Prepare(chain, header)
   153  	if err != nil {
   154  		t.Errorf("error mismatch: have %v, want nil", err)
   155  	}
   156  	header.ParentHash = common.StringToHash("1234567890")
   157  	err = engine.Prepare(chain, header)
   158  	if err != consensus.ErrUnknownAncestor {
   159  		t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrUnknownAncestor)
   160  	}
   161  }
   162  
   163  func TestSealStopChannel(t *testing.T) {
   164  	chain, engine := newBlockChain(4)
   165  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   166  	stop := make(chan struct{}, 1)
   167  	eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{})
   168  	eventLoop := func() {
   169  		select {
   170  		case ev := <-eventSub.Chan():
   171  			_, ok := ev.Data.(istanbul.RequestEvent)
   172  			if !ok {
   173  				t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
   174  			}
   175  			stop <- struct{}{}
   176  		}
   177  		eventSub.Unsubscribe()
   178  	}
   179  	go eventLoop()
   180  	resultCh := make(chan *types.Block, 10)
   181  	go func() {
   182  		err := engine.Seal(chain, block, resultCh, stop)
   183  		if err != nil {
   184  			t.Errorf("error mismatch: have %v, want nil", err)
   185  		}
   186  	}()
   187  
   188  	finalBlock := <-resultCh
   189  	if finalBlock != nil {
   190  		t.Errorf("block mismatch: have %v, want nil", finalBlock)
   191  	}
   192  }
   193  
   194  func TestSealCommittedOtherHash(t *testing.T) {
   195  	chain, engine := newBlockChain(4)
   196  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   197  	otherBlock := makeBlockWithoutSeal(chain, engine, block)
   198  	eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{})
   199  	eventLoop := func() {
   200  		select {
   201  		case ev := <-eventSub.Chan():
   202  			_, ok := ev.Data.(istanbul.RequestEvent)
   203  			if !ok {
   204  				t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
   205  			}
   206  			engine.Commit(otherBlock, [][]byte{})
   207  		}
   208  		eventSub.Unsubscribe()
   209  	}
   210  	go eventLoop()
   211  	seal := func() {
   212  		engine.Seal(chain, block, nil, make(chan struct{}))
   213  		t.Error("seal should not be completed")
   214  	}
   215  	go seal()
   216  
   217  	const timeoutDura = 2 * time.Second
   218  	timeout := time.NewTimer(timeoutDura)
   219  	select {
   220  	case <-timeout.C:
   221  		// wait 2 seconds to ensure we cannot get any blocks from Istanbul
   222  	}
   223  }
   224  
   225  func TestSealCommitted(t *testing.T) {
   226  	chain, engine := newBlockChain(1)
   227  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   228  	expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block)
   229  	resultCh := make(chan *types.Block, 10)
   230  	go func() {
   231  		err := engine.Seal(chain, block, resultCh, make(chan struct{}))
   232  
   233  		if err != nil {
   234  			t.Errorf("error mismatch: have %v, want %v", err, expectedBlock)
   235  		}
   236  	}()
   237  
   238  	finalBlock := <-resultCh
   239  	if finalBlock.Hash() != expectedBlock.Hash() {
   240  		t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash())
   241  	}
   242  }
   243  
   244  func TestVerifyHeader(t *testing.T) {
   245  	chain, engine := newBlockChain(1)
   246  
   247  	// errEmptyCommittedSeals case
   248  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   249  	block, _ = engine.updateBlock(chain.Genesis().Header(), block)
   250  	err := engine.VerifyHeader(chain, block.Header(), false)
   251  	if err != errEmptyCommittedSeals {
   252  		t.Errorf("error mismatch: have %v, want %v", err, errEmptyCommittedSeals)
   253  	}
   254  
   255  	// short extra data
   256  	header := block.Header()
   257  	header.Extra = []byte{}
   258  	err = engine.VerifyHeader(chain, header, false)
   259  	if err != errInvalidExtraDataFormat {
   260  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat)
   261  	}
   262  	// incorrect extra format
   263  	header.Extra = []byte("0000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000000")
   264  	err = engine.VerifyHeader(chain, header, false)
   265  	if err != errInvalidExtraDataFormat {
   266  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat)
   267  	}
   268  
   269  	// non zero MixDigest
   270  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   271  	header = block.Header()
   272  	header.MixDigest = common.StringToHash("123456789")
   273  	err = engine.VerifyHeader(chain, header, false)
   274  	if err != errInvalidMixDigest {
   275  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidMixDigest)
   276  	}
   277  
   278  	// invalid uncles hash
   279  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   280  	header = block.Header()
   281  	header.UncleHash = common.StringToHash("123456789")
   282  	err = engine.VerifyHeader(chain, header, false)
   283  	if err != errInvalidUncleHash {
   284  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidUncleHash)
   285  	}
   286  
   287  	// invalid difficulty
   288  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   289  	header = block.Header()
   290  	header.Difficulty = big.NewInt(2)
   291  	err = engine.VerifyHeader(chain, header, false)
   292  	if err != errInvalidDifficulty {
   293  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidDifficulty)
   294  	}
   295  
   296  	// invalid timestamp
   297  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   298  	header = block.Header()
   299  	header.Time = new(big.Int).Add(chain.Genesis().Time(), new(big.Int).SetUint64(engine.config.BlockPeriod-1))
   300  	err = engine.VerifyHeader(chain, header, false)
   301  	if err != errInvalidTimestamp {
   302  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidTimestamp)
   303  	}
   304  
   305  	// future block
   306  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   307  	header = block.Header()
   308  	header.Time = new(big.Int).Add(big.NewInt(now().Unix()), new(big.Int).SetUint64(10))
   309  	err = engine.VerifyHeader(chain, header, false)
   310  	if err != consensus.ErrFutureBlock {
   311  		t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock)
   312  	}
   313  
   314  	// invalid nonce
   315  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   316  	header = block.Header()
   317  	copy(header.Nonce[:], hexutil.MustDecode("0x111111111111"))
   318  	header.Number = big.NewInt(int64(engine.config.Epoch))
   319  	err = engine.VerifyHeader(chain, header, false)
   320  	if err != errInvalidNonce {
   321  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidNonce)
   322  	}
   323  }
   324  
   325  func TestVerifySeal(t *testing.T) {
   326  	chain, engine := newBlockChain(1)
   327  	genesis := chain.Genesis()
   328  	// cannot verify genesis
   329  	err := engine.VerifySeal(chain, genesis.Header())
   330  	if err != errUnknownBlock {
   331  		t.Errorf("error mismatch: have %v, want %v", err, errUnknownBlock)
   332  	}
   333  
   334  	block := makeBlock(chain, engine, genesis)
   335  	// change block content
   336  	header := block.Header()
   337  	header.Number = big.NewInt(4)
   338  	block1 := block.WithSeal(header)
   339  	err = engine.VerifySeal(chain, block1.Header())
   340  	if err != errUnauthorized {
   341  		t.Errorf("error mismatch: have %v, want %v", err, errUnauthorized)
   342  	}
   343  
   344  	// unauthorized users but still can get correct signer address
   345  	engine.privateKey, _ = crypto.GenerateKey()
   346  	err = engine.VerifySeal(chain, block.Header())
   347  	if err != nil {
   348  		t.Errorf("error mismatch: have %v, want nil", err)
   349  	}
   350  }
   351  
   352  func TestVerifyHeaders(t *testing.T) {
   353  	chain, engine := newBlockChain(1)
   354  	genesis := chain.Genesis()
   355  
   356  	// success case
   357  	headers := []*types.Header{}
   358  	blocks := []*types.Block{}
   359  	size := 100
   360  
   361  	for i := 0; i < size; i++ {
   362  		var b *types.Block
   363  		if i == 0 {
   364  			b = makeBlockWithoutSeal(chain, engine, genesis)
   365  			b, _ = engine.updateBlock(genesis.Header(), b)
   366  		} else {
   367  			b = makeBlockWithoutSeal(chain, engine, blocks[i-1])
   368  			b, _ = engine.updateBlock(blocks[i-1].Header(), b)
   369  		}
   370  		blocks = append(blocks, b)
   371  		headers = append(headers, blocks[i].Header())
   372  	}
   373  	now = func() time.Time {
   374  		return time.Unix(headers[size-1].Time.Int64(), 0)
   375  	}
   376  	_, results := engine.VerifyHeaders(chain, headers, nil)
   377  	const timeoutDura = 2 * time.Second
   378  	timeout := time.NewTimer(timeoutDura)
   379  	index := 0
   380  OUT1:
   381  	for {
   382  		select {
   383  		case err := <-results:
   384  			if err != nil {
   385  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals {
   386  					t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err)
   387  					break OUT1
   388  				}
   389  			}
   390  			index++
   391  			if index == size {
   392  				break OUT1
   393  			}
   394  		case <-timeout.C:
   395  			break OUT1
   396  		}
   397  	}
   398  	// abort cases
   399  	abort, results := engine.VerifyHeaders(chain, headers, nil)
   400  	timeout = time.NewTimer(timeoutDura)
   401  	index = 0
   402  OUT2:
   403  	for {
   404  		select {
   405  		case err := <-results:
   406  			if err != nil {
   407  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals {
   408  					t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err)
   409  					break OUT2
   410  				}
   411  			}
   412  			index++
   413  			if index == 5 {
   414  				abort <- struct{}{}
   415  			}
   416  			if index >= size {
   417  				t.Errorf("verifyheaders should be aborted")
   418  				break OUT2
   419  			}
   420  		case <-timeout.C:
   421  			break OUT2
   422  		}
   423  	}
   424  	// error header cases
   425  	headers[2].Number = big.NewInt(100)
   426  	abort, results = engine.VerifyHeaders(chain, headers, nil)
   427  	timeout = time.NewTimer(timeoutDura)
   428  	index = 0
   429  	errors := 0
   430  	expectedErrors := 2
   431  OUT3:
   432  	for {
   433  		select {
   434  		case err := <-results:
   435  			if err != nil {
   436  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals {
   437  					errors++
   438  				}
   439  			}
   440  			index++
   441  			if index == size {
   442  				if errors != expectedErrors {
   443  					t.Errorf("error mismatch: have %v, want %v", err, expectedErrors)
   444  				}
   445  				break OUT3
   446  			}
   447  		case <-timeout.C:
   448  			break OUT3
   449  		}
   450  	}
   451  }
   452  
   453  func TestPrepareExtra(t *testing.T) {
   454  	validators := make([]common.Address, 4)
   455  	validators[0] = common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a"))
   456  	validators[1] = common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212"))
   457  	validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6"))
   458  	validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440"))
   459  
   460  	vanity := make([]byte, types.IstanbulExtraVanity)
   461  	expectedResult := append(vanity, hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")...)
   462  
   463  	h := &types.Header{
   464  		Extra: vanity,
   465  	}
   466  
   467  	payload, err := prepareExtra(h, validators)
   468  	if err != nil {
   469  		t.Errorf("error mismatch: have %v, want: nil", err)
   470  	}
   471  	if !reflect.DeepEqual(payload, expectedResult) {
   472  		t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult)
   473  	}
   474  
   475  	// append useless information to extra-data
   476  	h.Extra = append(vanity, make([]byte, 15)...)
   477  
   478  	payload, err = prepareExtra(h, validators)
   479  	if !reflect.DeepEqual(payload, expectedResult) {
   480  		t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult)
   481  	}
   482  }
   483  
   484  func TestWriteSeal(t *testing.T) {
   485  	vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)
   486  	istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")
   487  	expectedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...)
   488  	expectedIstExtra := &types.IstanbulExtra{
   489  		Validators: []common.Address{
   490  			common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
   491  			common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
   492  			common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
   493  			common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
   494  		},
   495  		Seal:          expectedSeal,
   496  		CommittedSeal: [][]byte{},
   497  	}
   498  	var expectedErr error
   499  
   500  	h := &types.Header{
   501  		Extra: append(vanity, istRawData...),
   502  	}
   503  
   504  	// normal case
   505  	err := writeSeal(h, expectedSeal)
   506  	if err != expectedErr {
   507  		t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
   508  	}
   509  
   510  	// verify istanbul extra-data
   511  	istExtra, err := types.ExtractIstanbulExtra(h)
   512  	if err != nil {
   513  		t.Errorf("error mismatch: have %v, want nil", err)
   514  	}
   515  	if !reflect.DeepEqual(istExtra, expectedIstExtra) {
   516  		t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
   517  	}
   518  
   519  	// invalid seal
   520  	unexpectedSeal := append(expectedSeal, make([]byte, 1)...)
   521  	err = writeSeal(h, unexpectedSeal)
   522  	if err != errInvalidSignature {
   523  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature)
   524  	}
   525  }
   526  
   527  func TestWriteCommittedSeals(t *testing.T) {
   528  	vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)
   529  	istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")
   530  	expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...)
   531  	expectedIstExtra := &types.IstanbulExtra{
   532  		Validators: []common.Address{
   533  			common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
   534  			common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
   535  			common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
   536  			common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
   537  		},
   538  		Seal:          []byte{},
   539  		CommittedSeal: [][]byte{expectedCommittedSeal},
   540  	}
   541  	var expectedErr error
   542  
   543  	h := &types.Header{
   544  		Extra: append(vanity, istRawData...),
   545  	}
   546  
   547  	// normal case
   548  	err := writeCommittedSeals(h, [][]byte{expectedCommittedSeal})
   549  	if err != expectedErr {
   550  		t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
   551  	}
   552  
   553  	// verify istanbul extra-data
   554  	istExtra, err := types.ExtractIstanbulExtra(h)
   555  	if err != nil {
   556  		t.Errorf("error mismatch: have %v, want nil", err)
   557  	}
   558  	if !reflect.DeepEqual(istExtra, expectedIstExtra) {
   559  		t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
   560  	}
   561  
   562  	// invalid seal
   563  	unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...)
   564  	err = writeCommittedSeals(h, [][]byte{unexpectedCommittedSeal})
   565  	if err != errInvalidCommittedSeals {
   566  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidCommittedSeals)
   567  	}
   568  }