github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/backend/pbft_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/bigzoro/my_simplechain/common"
    28  	"github.com/bigzoro/my_simplechain/common/hexutil"
    29  	"github.com/bigzoro/my_simplechain/consensus"
    30  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    31  	"github.com/bigzoro/my_simplechain/core"
    32  	"github.com/bigzoro/my_simplechain/core/rawdb"
    33  	"github.com/bigzoro/my_simplechain/core/types"
    34  	"github.com/bigzoro/my_simplechain/core/vm"
    35  	"github.com/bigzoro/my_simplechain/crypto"
    36  	"github.com/bigzoro/my_simplechain/params"
    37  	"github.com/bigzoro/my_simplechain/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 := rawdb.NewMemoryDatabase()
    46  	config := pbft.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  	b.SetSealer(testSealer{})
    74  
    75  	return blockchain, b
    76  }
    77  
    78  func getGenesisAndKeys(n int) (*core.Genesis, []*ecdsa.PrivateKey) {
    79  	// Setup validators
    80  	var nodeKeys = make([]*ecdsa.PrivateKey, n)
    81  	var addrs = make([]common.Address, n)
    82  	for i := 0; i < n; i++ {
    83  		nodeKeys[i], _ = crypto.GenerateKey()
    84  		addrs[i] = crypto.PubkeyToAddress(nodeKeys[i].PublicKey)
    85  	}
    86  
    87  	// generate genesis block
    88  	genesis := core.DefaultGenesisBlock()
    89  	genesis.Config = params.TestChainConfig
    90  	// force enable Istanbul engine
    91  	genesis.Config.Istanbul = &params.IstanbulConfig{}
    92  	genesis.Config.Ethash = nil
    93  	genesis.Difficulty = defaultDifficulty
    94  	genesis.Nonce = emptyNonce.Uint64()
    95  	genesis.Mixhash = types.PbftDigest
    96  
    97  	appendValidators(genesis, addrs)
    98  	return genesis, nodeKeys
    99  }
   100  
   101  func appendValidators(genesis *core.Genesis, addrs []common.Address) {
   102  
   103  	if len(genesis.ExtraData) < types.ByzantineExtraVanity {
   104  		genesis.ExtraData = append(genesis.ExtraData, bytes.Repeat([]byte{0x00}, types.ByzantineExtraVanity)...)
   105  	}
   106  	genesis.ExtraData = genesis.ExtraData[:types.ByzantineExtraVanity]
   107  
   108  	ist := &types.ByzantineExtra{
   109  		Validators:    addrs,
   110  		Seal:          []byte{},
   111  		CommittedSeal: [][]byte{},
   112  	}
   113  
   114  	istPayload, err := rlp.EncodeToBytes(&ist)
   115  	if err != nil {
   116  		panic("failed to encode istanbul extra")
   117  	}
   118  	genesis.ExtraData = append(genesis.ExtraData, istPayload...)
   119  }
   120  
   121  func makeHeader(parent *types.Block, config *pbft.Config) *types.Header {
   122  	header := &types.Header{
   123  		ParentHash: parent.Hash(),
   124  		Number:     parent.Number().Add(parent.Number(), common.Big1),
   125  		GasLimit:   core.CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
   126  		GasUsed:    0,
   127  		Extra:      parent.Extra(),
   128  		Time:       parent.Time() + config.BlockPeriod,
   129  		Difficulty: defaultDifficulty,
   130  	}
   131  	return header
   132  }
   133  
   134  func makeBlock(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
   135  	block := makeBlockWithoutSeal(chain, engine, parent)
   136  	stopCh := make(chan struct{})
   137  	resultCh := make(chan *types.Block, 10)
   138  	go engine.Seal(chain, block, resultCh, stopCh)
   139  	blk := <-resultCh
   140  	return blk
   141  }
   142  
   143  func makeBlockWithoutSeal(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
   144  	header := makeHeader(parent, engine.config)
   145  	engine.Prepare(chain, header)
   146  	state, _ := chain.StateAt(parent.Root())
   147  	block, _ := engine.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
   148  	return block
   149  }
   150  
   151  func TestPrepare(t *testing.T) {
   152  	chain, engine := newBlockChain(1)
   153  	header := makeHeader(chain.Genesis(), engine.config)
   154  	err := engine.Prepare(chain, header)
   155  	if err != nil {
   156  		t.Errorf("error mismatch: have %v, want nil", err)
   157  	}
   158  	header.ParentHash = common.BytesToHash([]byte("1234567890"))
   159  	err = engine.Prepare(chain, header)
   160  	if err != consensus.ErrUnknownAncestor {
   161  		t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrUnknownAncestor)
   162  	}
   163  }
   164  
   165  func TestSealStopChannel(t *testing.T) {
   166  	chain, engine := newBlockChain(4)
   167  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   168  	stop := make(chan struct{}, 1)
   169  	eventSub := engine.EventMux().Subscribe(pbft.RequestEvent{})
   170  	eventLoop := func() {
   171  		ev := <-eventSub.Chan()
   172  		_, ok := ev.Data.(pbft.RequestEvent)
   173  		if !ok {
   174  			t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
   175  		}
   176  		stop <- struct{}{}
   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  	expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.ByzantineExtraSeal-3)...)
   199  
   200  	eventSub := engine.EventMux().Subscribe(pbft.RequestEvent{})
   201  	blockOutputChannel := make(chan *types.Block)
   202  	stopChannel := make(chan struct{})
   203  
   204  	go func() {
   205  		ev := <-eventSub.Chan()
   206  		if _, ok := ev.Data.(pbft.RequestEvent); !ok {
   207  			t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
   208  		}
   209  		if err := engine.Commit(otherBlock, [][]byte{expectedCommittedSeal}); err != nil {
   210  			t.Error(err.Error())
   211  		}
   212  		eventSub.Unsubscribe()
   213  	}()
   214  
   215  	go func() {
   216  		if err := engine.Seal(chain, block, blockOutputChannel, stopChannel); err != nil {
   217  			t.Error(err.Error())
   218  		}
   219  	}()
   220  
   221  	select {
   222  	case <-blockOutputChannel:
   223  		t.Error("Wrong block found!")
   224  	default:
   225  		//no block found, stop the sealing
   226  		close(stopChannel)
   227  	}
   228  
   229  	output := <-blockOutputChannel
   230  	if output != nil {
   231  		t.Error("Block not nil!")
   232  	}
   233  }
   234  
   235  func TestSealCommitted(t *testing.T) {
   236  	chain, engine := newBlockChain(1)
   237  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   238  	expectedBlock, _ := engine.signBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block)
   239  	resultCh := make(chan *types.Block, 10)
   240  	go func() {
   241  		err := engine.Seal(chain, block, resultCh, make(chan struct{}))
   242  
   243  		if err != nil {
   244  			t.Errorf("error mismatch: have %v, want %v", err, expectedBlock)
   245  		}
   246  	}()
   247  
   248  	finalBlock := <-resultCh
   249  	if finalBlock.Hash() != expectedBlock.Hash() {
   250  		t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash())
   251  	}
   252  }
   253  
   254  func TestVerifyHeader(t *testing.T) {
   255  	chain, engine := newBlockChain(1)
   256  
   257  	// errEmptyCommittedSeals case
   258  	block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
   259  	block, _ = engine.signBlock(chain.Genesis().Header(), block)
   260  	err := engine.VerifyHeader(chain, block.Header(), true)
   261  	if err != errEmptyCommittedSeals {
   262  		t.Errorf("error mismatch: have %v, want %v", err, errEmptyCommittedSeals)
   263  	}
   264  
   265  	// short extra data
   266  	header := block.Header()
   267  	header.Extra = []byte{}
   268  	err = engine.VerifyHeader(chain, header, false)
   269  	if err != errInvalidExtraDataFormat {
   270  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat)
   271  	}
   272  	// incorrect extra format
   273  	header.Extra = []byte("0000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000000")
   274  	err = engine.VerifyHeader(chain, header, false)
   275  	if err != errInvalidExtraDataFormat {
   276  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat)
   277  	}
   278  
   279  	// non zero MixDigest
   280  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   281  	header = block.Header()
   282  	header.MixDigest = common.BytesToHash([]byte("123456789"))
   283  	err = engine.VerifyHeader(chain, header, false)
   284  	if err != errInvalidMixDigest {
   285  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidMixDigest)
   286  	}
   287  
   288  	// invalid uncles hash
   289  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   290  	header = block.Header()
   291  	header.UncleHash = common.BytesToHash([]byte("123456789"))
   292  	err = engine.VerifyHeader(chain, header, false)
   293  	if err != errInvalidUncleHash {
   294  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidUncleHash)
   295  	}
   296  
   297  	// invalid difficulty
   298  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   299  	header = block.Header()
   300  	header.Difficulty = big.NewInt(2)
   301  	err = engine.VerifyHeader(chain, header, false)
   302  	if err != errInvalidDifficulty {
   303  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidDifficulty)
   304  	}
   305  
   306  	// invalid timestamp
   307  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   308  	header = block.Header()
   309  	header.Time = chain.Genesis().Time() + engine.config.BlockPeriod - 1
   310  	err = engine.VerifyHeader(chain, header, false)
   311  	if err != errInvalidTimestamp {
   312  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidTimestamp)
   313  	}
   314  
   315  	// future block
   316  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   317  	header = block.Header()
   318  	header.Time = uint64(now().Unix()) + 10
   319  	err = engine.VerifyHeader(chain, header, false)
   320  	if err != consensus.ErrFutureBlock {
   321  		t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock)
   322  	}
   323  
   324  	// invalid nonce
   325  	block = makeBlockWithoutSeal(chain, engine, chain.Genesis())
   326  	header = block.Header()
   327  	copy(header.Nonce[:], hexutil.MustDecode("0x111111111111"))
   328  	header.Number = big.NewInt(int64(engine.config.Epoch))
   329  	err = engine.VerifyHeader(chain, header, false)
   330  	if err != errInvalidNonce {
   331  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidNonce)
   332  	}
   333  }
   334  
   335  func TestVerifySeal(t *testing.T) {
   336  	chain, engine := newBlockChain(1)
   337  	genesis := chain.Genesis()
   338  	// cannot verify genesis
   339  	err := engine.VerifySeal(chain, genesis.Header())
   340  	if err != errUnknownBlock {
   341  		t.Errorf("error mismatch: have %v, want %v", err, errUnknownBlock)
   342  	}
   343  
   344  	block := makeBlock(chain, engine, genesis)
   345  	// change block content
   346  	header := block.Header()
   347  	header.Number = big.NewInt(4)
   348  	block1 := block.WithSeal(header)
   349  	err = engine.VerifySeal(chain, block1.Header())
   350  	if err != errUnauthorized {
   351  		t.Errorf("error mismatch: have %v, want %v", err, errUnauthorized)
   352  	}
   353  
   354  	// unauthorized users but still can get correct signer address
   355  	engine.privateKey, _ = crypto.GenerateKey()
   356  	err = engine.VerifySeal(chain, block.Header())
   357  	if err != nil {
   358  		t.Errorf("error mismatch: have %v, want nil", err)
   359  	}
   360  }
   361  
   362  func TestVerifyHeaders(t *testing.T) {
   363  	chain, engine := newBlockChain(1)
   364  	genesis := chain.Genesis()
   365  
   366  	// success case
   367  	headers := []*types.Header{}
   368  	blocks := []*types.Block{}
   369  	size := 100
   370  
   371  	for i := 0; i < size; i++ {
   372  		var b *types.Block
   373  		if i == 0 {
   374  			b = makeBlockWithoutSeal(chain, engine, genesis)
   375  			b, _ = engine.signBlock(genesis.Header(), b)
   376  		} else {
   377  			b = makeBlockWithoutSeal(chain, engine, blocks[i-1])
   378  			b, _ = engine.signBlock(blocks[i-1].Header(), b)
   379  		}
   380  		blocks = append(blocks, b)
   381  		headers = append(headers, blocks[i].Header())
   382  	}
   383  	now = func() time.Time {
   384  		return time.Unix(int64(headers[size-1].Time), 0)
   385  	}
   386  	_, results := engine.VerifyHeaders(chain, headers, nil)
   387  	const timeoutDura = 2 * time.Second
   388  	timeout := time.NewTimer(timeoutDura)
   389  	index := 0
   390  OUT1:
   391  	for {
   392  		select {
   393  		case err := <-results:
   394  			if err != nil {
   395  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals && err != consensus.ErrUnknownAncestor {
   396  					t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals|ErrUnknownAncestor", err)
   397  					break OUT1
   398  				}
   399  			}
   400  			index++
   401  			if index == size {
   402  				break OUT1
   403  			}
   404  		case <-timeout.C:
   405  			break OUT1
   406  		}
   407  	}
   408  	// abort cases
   409  	_, results = engine.VerifyHeaders(chain, headers, nil)
   410  	timeout = time.NewTimer(timeoutDura)
   411  OUT2:
   412  	for {
   413  		select {
   414  		case err := <-results:
   415  			if err != nil {
   416  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals && err != consensus.ErrUnknownAncestor {
   417  					t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals|ErrUnknownAncestor", err)
   418  					break OUT2
   419  				}
   420  			}
   421  		case <-timeout.C:
   422  			break OUT2
   423  		}
   424  	}
   425  	// error header cases
   426  	headers[2].Number = big.NewInt(100)
   427  	_, results = engine.VerifyHeaders(chain, headers, nil)
   428  	timeout = time.NewTimer(timeoutDura)
   429  	index = 0
   430  	errors := 0
   431  	expectedErrors := 0
   432  OUT3:
   433  	for {
   434  		select {
   435  		case err := <-results:
   436  			if err != nil {
   437  				if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals && err != consensus.ErrUnknownAncestor {
   438  					errors++
   439  				}
   440  			}
   441  			index++
   442  			if index == size {
   443  				if errors != expectedErrors {
   444  					t.Errorf("error mismatch: have %v, want %v", errors, expectedErrors)
   445  				}
   446  				break OUT3
   447  			}
   448  		case <-timeout.C:
   449  			break OUT3
   450  		}
   451  	}
   452  }
   453  
   454  func TestPrepareExtra(t *testing.T) {
   455  	validators := make([]common.Address, 4)
   456  	validators[0] = common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a"))
   457  	validators[1] = common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212"))
   458  	validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6"))
   459  	validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440"))
   460  
   461  	vanity := make([]byte, types.ByzantineExtraVanity)
   462  	expectedResult := append(vanity, hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")...)
   463  
   464  	h := &types.Header{
   465  		Extra: vanity,
   466  	}
   467  
   468  	payload, err := prepareExtra(h, validators)
   469  	if err != nil {
   470  		t.Errorf("error mismatch: have %v, want: nil", err)
   471  	}
   472  	if !reflect.DeepEqual(payload, expectedResult) {
   473  		t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult)
   474  	}
   475  
   476  	// append useless information to extra-data
   477  	h.Extra = append(vanity, make([]byte, 15)...)
   478  
   479  	payload, _ = prepareExtra(h, validators)
   480  	if !reflect.DeepEqual(payload, expectedResult) {
   481  		t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult)
   482  	}
   483  }
   484  
   485  func TestWriteSeal(t *testing.T) {
   486  	vanity := bytes.Repeat([]byte{0x00}, types.ByzantineExtraVanity)
   487  	istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")
   488  	expectedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.ByzantineExtraSeal-3)...)
   489  	expectedIstExtra := &types.ByzantineExtra{
   490  		Validators: []common.Address{
   491  			common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
   492  			common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
   493  			common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
   494  			common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
   495  		},
   496  		Seal:          expectedSeal,
   497  		CommittedSeal: [][]byte{},
   498  	}
   499  	var expectedErr error
   500  
   501  	h := &types.Header{
   502  		Extra: append(vanity, istRawData...),
   503  	}
   504  
   505  	// normal case
   506  	err := writeSeal(h, expectedSeal)
   507  	if err != expectedErr {
   508  		t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
   509  	}
   510  
   511  	// verify istanbul extra-data
   512  	istExtra, err := types.ExtractByzantineExtra(h)
   513  	if err != nil {
   514  		t.Errorf("error mismatch: have %v, want nil", err)
   515  	}
   516  	if !reflect.DeepEqual(istExtra, expectedIstExtra) {
   517  		t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
   518  	}
   519  
   520  	// invalid seal
   521  	unexpectedSeal := append(expectedSeal, make([]byte, 1)...)
   522  	err = writeSeal(h, unexpectedSeal)
   523  	if err != errInvalidSignature {
   524  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature)
   525  	}
   526  }
   527  
   528  func TestWriteCommittedSeals(t *testing.T) {
   529  	vanity := bytes.Repeat([]byte{0x00}, types.ByzantineExtraVanity)
   530  	istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")
   531  	expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.ByzantineExtraSeal-3)...)
   532  	expectedIstExtra := &types.ByzantineExtra{
   533  		Validators: []common.Address{
   534  			common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")),
   535  			common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")),
   536  			common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")),
   537  			common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")),
   538  		},
   539  		Seal:          []byte{},
   540  		CommittedSeal: [][]byte{expectedCommittedSeal},
   541  	}
   542  	var expectedErr error
   543  
   544  	h := &types.Header{
   545  		Extra: append(vanity, istRawData...),
   546  	}
   547  
   548  	// normal case
   549  	err := writeCommittedSeals(h, [][]byte{expectedCommittedSeal})
   550  	if err != expectedErr {
   551  		t.Errorf("error mismatch: have %v, want %v", err, expectedErr)
   552  	}
   553  
   554  	// verify istanbul extra-data
   555  	istExtra, err := types.ExtractByzantineExtra(h)
   556  	if err != nil {
   557  		t.Errorf("error mismatch: have %v, want nil", err)
   558  	}
   559  	if !reflect.DeepEqual(istExtra, expectedIstExtra) {
   560  		t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra)
   561  	}
   562  
   563  	// invalid seal
   564  	unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...)
   565  	err = writeCommittedSeals(h, [][]byte{unexpectedCommittedSeal})
   566  	if err != errInvalidCommittedSeals {
   567  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidCommittedSeals)
   568  	}
   569  }