github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/backend/engine_test.go (about)

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