github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/consensus/cbft/cbft_test.go (about)

     1  package cbft
     2  
     3  import (
     4  	"container/list"
     5  	"crypto/md5"
     6  	"encoding/json"
     7  	"flag"
     8  	"fmt"
     9  	"github.com/PlatONnetwork/PlatON-Go/common"
    10  	"github.com/PlatONnetwork/PlatON-Go/core/types"
    11  	"github.com/PlatONnetwork/PlatON-Go/crypto"
    12  	"github.com/PlatONnetwork/PlatON-Go/log"
    13  	"github.com/PlatONnetwork/PlatON-Go/p2p/discover"
    14  	"github.com/PlatONnetwork/PlatON-Go/params"
    15  	"math/big"
    16  	"os"
    17  	"strconv"
    18  	"testing"
    19  )
    20  
    21  func TestMain(m *testing.M) {
    22  	fmt.Println("test begin ...")
    23  	initTest()
    24  
    25  	flag.Parse()
    26  	exitCode := m.Run()
    27  
    28  	destroyTest()
    29  	fmt.Println("test end ...")
    30  	// Exit
    31  	os.Exit(exitCode)
    32  }
    33  
    34  //var cbftConfig *params.CbftConfig
    35  var forkRootHash common.Hash
    36  var rootBlock *types.Block
    37  var rootNumber uint64
    38  var hash23 common.Hash
    39  var lastMainBlockHash common.Hash
    40  
    41  var discreteBlock *types.Block
    42  var lastMainBlock *types.Block
    43  var lastButOneMainBlock *types.Block
    44  
    45  func TestMarshalJson(t *testing.T){
    46  	obj := NewBlockExt(lastButOneMainBlock, 0)
    47  	obj.inTree = true
    48  	obj.isExecuted = true
    49  	obj.isSigned = true
    50  	obj.isConfirmed = true
    51  	obj.parent = nil
    52  
    53  	t.Log("cbft.highestConfirmed is null", "hash:", obj.Hash)
    54  	fmt.Println("cbft.highestConfirmed:" + obj.Hash)
    55  
    56  	jsons, errs := json.Marshal(obj) //byte[] for json
    57  	if errs != nil {
    58  		fmt.Println(errs.Error())
    59  	}
    60  	fmt.Println("obj:" + string(jsons)) //byte[] to string
    61  }
    62  
    63  func TestBlockSynced_discreteBlock(t *testing.T) {
    64  	doBlockSynced(discreteBlock, t)
    65  }
    66  
    67  func TestBlockSynced_lastMainBlock(t *testing.T) {
    68  	doBlockSynced(lastMainBlock, t)
    69  }
    70  
    71  func TestBlockSynced_lastButOneMainBlock(t *testing.T) {
    72  	doBlockSynced(lastButOneMainBlock, t)
    73  }
    74  
    75  /*func TestBlockSynced_hash23(t *testing.T) {
    76  	doBlockSynced(cbft.findBlockExt(hash23).block, t)
    77  }
    78  */
    79  
    80  func doBlockSynced(currentBlock *types.Block, t *testing.T){
    81  	if currentBlock.NumberU64() > cbft.getRootIrreversible().Number {
    82  		log.Debug("chain has a higher irreversible block", "hash", currentBlock.Hash(), "number", currentBlock.NumberU64())
    83  		newRoot := cbft.findBlockExt(currentBlock.Hash())
    84  		if newRoot == nil || newRoot.block == nil {
    85  			log.Debug("higher irreversible block is not existing in memory", "newTree", newRoot.toJson())
    86  			//the block synced from other peer is a new block in local peer
    87  			//remove all blocks referenced in old tree after being cut off
    88  			cbft.cleanByTailoredTree(cbft.getRootIrreversible())
    89  
    90  			newRoot = NewBlockExt(currentBlock, currentBlock.NumberU64())
    91  			newRoot.inTree = true
    92  			newRoot.isExecuted = true
    93  			newRoot.isSigned = true
    94  			newRoot.isConfirmed = true
    95  			newRoot.Number = currentBlock.NumberU64()
    96  			newRoot.parent = nil
    97  			cbft.saveBlockExt(newRoot.block.Hash(), newRoot)
    98  
    99  			cbft.buildChildNode(newRoot)
   100  
   101  			if len(newRoot.Children) > 0{
   102  				//the new root's children should re-execute base on new state
   103  				for _, child := range newRoot.Children {
   104  					if err := cbft.executeBlockAndDescendantMock(child, newRoot); err != nil {
   105  						log.Error("execute the block error", "err", err)
   106  						break
   107  					}
   108  				}
   109  				//there are some redundancy code for newRoot, but these codes are necessary for other logical blocks
   110  				cbft.signLogicalAndDescendantMock(newRoot)
   111  			}
   112  
   113  		} else if newRoot.block != nil {
   114  			log.Debug("higher irreversible block is existing in memory","newTree", newRoot.toJson())
   115  
   116  			//the block synced from other peer exists in local peer
   117  			newRoot.isExecuted = true
   118  			newRoot.isSigned = true
   119  			newRoot.isConfirmed = true
   120  			newRoot.Number = currentBlock.NumberU64()
   121  
   122  			if newRoot.inTree == false {
   123  				newRoot.inTree = true
   124  
   125  				cbft.setDescendantInTree(newRoot)
   126  
   127  				if len(newRoot.Children) > 0{
   128  					//the new root's children should re-execute base on new state
   129  					for _, child := range newRoot.Children {
   130  						if err := cbft.executeBlockAndDescendantMock(child, newRoot); err != nil {
   131  							log.Error("execute the block error", "err", err)
   132  							break
   133  						}
   134  					}
   135  					//there are some redundancy code for newRoot, but these codes are necessary for other logical blocks
   136  					cbft.signLogicalAndDescendantMock(newRoot)
   137  				}
   138  			}else{
   139  				//cut off old tree from new root,
   140  				tailorTree(newRoot)
   141  			}
   142  
   143  			//remove all blocks referenced in old tree after being cut off
   144  			cbft.cleanByTailoredTree(cbft.getRootIrreversible())
   145  		}
   146  
   147  		//remove all other blocks those their numbers are too low
   148  		cbft.cleanByNumber(newRoot.Number)
   149  
   150  		log.Debug("the cleared new tree in memory", "json", newRoot.toJson())
   151  
   152  		//reset the new root irreversible
   153  		cbft.rootIrreversible.Store(newRoot)
   154  
   155  		log.Debug("reset the new root irreversible by synced", "hash", newRoot.block.Hash(), "number", newRoot.block.NumberU64())
   156  
   157  
   158  		//reset logical path
   159  		highestLogical := cbft.findHighestLogical(newRoot)
   160  		//cbft.setHighestLogical(highestLogical)
   161  		cbft.highestLogical.Store(highestLogical)
   162  
   163  		t.Log("reset the highestLogical by synced", "number", highestLogical.block.NumberU64(),  "newRoot.number", newRoot.block.NumberU64() )
   164  
   165  		//reset highest confirmed block
   166  		highestConfirmed :=cbft.findLastClosestConfirmedIncludingSelf(newRoot)
   167  		cbft.highestConfirmed.Store(highestConfirmed)
   168  		if highestConfirmed != nil {
   169  			t.Log("cbft.highestConfirmed", "number", highestConfirmed.block.NumberU64(),"rcvTime", highestConfirmed.rcvTime)
   170  		} else {
   171  
   172  			t.Log("reset the highestConfirmed by synced failure because findLastClosestConfirmedIncludingSelf() returned nil", "newRoot.number", newRoot.block.NumberU64())
   173  
   174  		}
   175  	}
   176  }
   177  
   178  
   179  
   180  func TestFindLastClosestConfirmedIncludingSelf(t *testing.T) {
   181  
   182  	newRoot := NewBlockExt(rootBlock, 0)
   183  	newRoot.inTree = true
   184  	newRoot.isExecuted = true
   185  	newRoot.isSigned = true
   186  	newRoot.isConfirmed = true
   187  	newRoot.Number = rootBlock.NumberU64()
   188  
   189  	//reorg the block tree
   190  	children := cbft.findChildren(newRoot)
   191  	for _, child := range children {
   192  		child.parent = newRoot
   193  		child.inTree = true
   194  	}
   195  	newRoot.Children = children
   196  
   197  	//save the root in BlockExtMap
   198  	cbft.saveBlockExt(newRoot.block.Hash(), newRoot)
   199  
   200  	//reset the new root irreversible
   201  	cbft.rootIrreversible.Store(newRoot)
   202  	//the new root's children should re-execute base on new state
   203  	for _, child := range newRoot.Children {
   204  		if err := cbft.executeBlockAndDescendant(child, newRoot); err != nil {
   205  			//remove bad block from tree and map
   206  			cbft.removeBadBlock(child)
   207  			break
   208  		}
   209  	}
   210  
   211  	//there are some redundancy code for newRoot, but these codes are necessary for other logical blocks
   212  	cbft.signLogicalAndDescendant(newRoot)
   213  
   214  	//reset logical path
   215  	//highestLogical := cbft.findHighestLogical(newRoot)
   216  	//cbft.setHighestLogical(highestLogical)
   217  	//reset highest confirmed block
   218  	cbft.highestConfirmed.Store(cbft.findLastClosestConfirmedIncludingSelf(newRoot))
   219  
   220  	if cbft.getHighestLogical() != nil {
   221  		t.Log("ok")
   222  	} else {
   223  		t.Log("cbft.highestConfirmed is null")
   224  	}
   225  }
   226  func TestFindClosestConfirmedExcludingSelf(t *testing.T) {
   227  	newRoot := NewBlockExt(rootBlock, 0)
   228  	newRoot.inTree = true
   229  	newRoot.isExecuted = true
   230  	newRoot.isSigned = true
   231  	newRoot.isConfirmed = true
   232  	newRoot.Number = rootBlock.NumberU64()
   233  
   234  	closest := cbft.findClosestConfirmedExcludingSelf(newRoot)
   235  	fmt.Println(closest)
   236  }
   237  
   238  func TestExecuteBlockAndDescendant(t *testing.T) {
   239  	newRoot := NewBlockExt(rootBlock, 0)
   240  	newRoot.inTree = true
   241  	newRoot.isExecuted = true
   242  	newRoot.isSigned = true
   243  	newRoot.isConfirmed = true
   244  	newRoot.Number = rootBlock.NumberU64()
   245  
   246  	//save the root in BlockExtMap
   247  	cbft.saveBlockExt(newRoot.block.Hash(), newRoot)
   248  
   249  	//reset the new root irreversible
   250  	cbft.rootIrreversible.Store(newRoot)
   251  	//reorg the block tree
   252  	cbft.buildChildNode(newRoot)
   253  
   254  	//the new root's children should re-execute base on new state
   255  	for _, child := range newRoot.Children {
   256  		if err := cbft.executeBlockAndDescendant(child, newRoot); err != nil {
   257  			//remove bad block from tree and map
   258  			cbft.removeBadBlock(child)
   259  			break
   260  		}
   261  	}
   262  
   263  	//there are some redundancy code for newRoot, but these codes are necessary for other logical blocks
   264  	cbft.signLogicalAndDescendant(newRoot)
   265  }
   266  
   267  func TestBackTrackBlocksIncludingEnd(t *testing.T) {
   268  	testBackTrackBlocks(t, true)
   269  }
   270  
   271  func TestBackTrackBlocksExcludingEnd(t *testing.T) {
   272  	testBackTrackBlocks(t, false)
   273  }
   274  
   275  func testBackTrackBlocks(t *testing.T, includeEnd bool) {
   276  	end, _ := cbft.blockExtMap.Load(rootBlock.Hash())
   277  	exts := cbft.backTrackBlocks(cbft.getHighestLogical(), end.(*BlockExt), includeEnd)
   278  
   279  	t.Log("len(exts)", len(exts))
   280  }
   281  
   282  func initTest() {
   283  	nodes := initNodes()
   284  	priKey, _ := crypto.HexToECDSA("0x8b54398b67e656dcab213c1b5886845963a9ab0671786eefaf6e241ee9c8074f")
   285  
   286  	cbftConfig := &params.CbftConfig{
   287  		Period:       1,
   288  		Epoch:        250000,
   289  		MaxLatency:   600,
   290  		Duration:     10,
   291  		InitialNodes: nodes,
   292  		NodeID:       nodes[0].ID,
   293  		PrivateKey:   priKey,
   294  	}
   295  
   296  	cbft = &Cbft{
   297  		config: cbftConfig,
   298  		//blockExtMap:   make(map[common.Hash]*BlockExt),
   299  		//signedSet:     make(map[uint64]struct{}),
   300  		netLatencyMap: make(map[discover.NodeID]*list.List),
   301  	}
   302  	buildMain(cbft)
   303  
   304  	buildFork(cbft)
   305  }
   306  
   307  func destroyTest() {
   308  	cbft.Close()
   309  }
   310  
   311  func buildFork(cbft *Cbft) {
   312  
   313  	//sealhash := cbft.SealHash(header)
   314  
   315  	parentHash := forkRootHash
   316  	for i := uint64(3); i <= 5; i++ {
   317  		header := &types.Header{
   318  			ParentHash: parentHash,
   319  			Number:     big.NewInt(int64(i)),
   320  			TxHash:     hash(2, i),
   321  		}
   322  		block := types.NewBlockWithHeader(header)
   323  
   324  		ext := &BlockExt{
   325  			block:       block,
   326  			inTree:      true,
   327  			isExecuted:  true,
   328  			isConfirmed: false,
   329  			rcvTime:    int64(20+i),
   330  			Number:      block.NumberU64(),
   331  			signs:       make([]*common.BlockConfirmSign, 0),
   332  		}
   333  		cbft.blockExtMap.Store(block.Hash(), ext)
   334  
   335  		parentHash = block.Hash()
   336  
   337  		if i == 3 {
   338  			ext.isSigned=false
   339  			ext.isConfirmed=false
   340  			hash23 = block.Hash()
   341  		} else if i == 4 {
   342  			ext.isSigned=true
   343  			ext.isConfirmed=false
   344  		} else if i == 5 {
   345  			ext.isSigned=false
   346  			ext.isConfirmed=false
   347  		}
   348  		cbft.buildIntoTree(ext)
   349  	}
   350  }
   351  
   352  func hash(branch uint64, number uint64) (hash common.Hash) {
   353  	s := "branch" + strconv.FormatUint(branch, 10) + "number" + strconv.FormatUint(number, 10)
   354  	signByte := []byte(s)
   355  	hasher := md5.New()
   356  	hasher.Write(signByte)
   357  	return common.BytesToHash(hasher.Sum(nil))
   358  }
   359  
   360  
   361  
   362  
   363  func buildMain(cbft *Cbft) {
   364  
   365  	//sealhash := cbft.SealHash(header)
   366  
   367  	rootHeader := &types.Header{Number: big.NewInt(0), TxHash: hash(1, 0)}
   368  	rootBlock = types.NewBlockWithHeader(rootHeader)
   369  	rootNumber = 0
   370  
   371  	rootExt := &BlockExt{
   372  		block:       rootBlock,
   373  		inTree:      true,
   374  		isExecuted:  true,
   375  		isSigned:    true,
   376  		isConfirmed: true,
   377  		rcvTime:	 0,
   378  		Number:      rootBlock.NumberU64(),
   379  		signs:       make([]*common.BlockConfirmSign, 0),
   380  	}
   381  
   382  	//hashSet[uint64(0)] = rootBlock.Hash()
   383  	cbft.blockExtMap.Store(rootBlock.Hash(), rootExt)
   384  	cbft.highestConfirmed.Store(rootExt)
   385  	cbft.rootIrreversible.Store(rootExt)
   386  
   387  	parentHash := rootBlock.Hash()
   388  	for i := uint64(1); i <= 5; i++ {
   389  		header := &types.Header{
   390  			ParentHash: parentHash,
   391  			Number:     big.NewInt(int64(i)),
   392  			TxHash:     hash(1, i),
   393  		}
   394  		block := types.NewBlockWithHeader(header)
   395  
   396  		ext := &BlockExt{
   397  			block:       block,
   398  			inTree:      true,
   399  			isExecuted:  true,
   400  			isSigned:    true,
   401  			isConfirmed: false,
   402  			rcvTime:    int64(i),
   403  			Number:      block.NumberU64(),
   404  			signs:       make([]*common.BlockConfirmSign, 0),
   405  		}
   406  		//hashSet[i] = rootBlock.Hash()
   407  		cbft.blockExtMap.Store(block.Hash(), ext)
   408  
   409  		cbft.highestLogical.Store(ext)
   410  
   411  		parentHash = block.Hash()
   412  
   413  		if i == 2 {
   414  			forkRootHash = block.Hash()
   415  			ext.isSigned=false
   416  			ext.isConfirmed=true
   417  		} else if i == 3 {
   418  			ext.isSigned=true
   419  			ext.isConfirmed=false
   420  		} else if i == 4 {
   421  			lastButOneMainBlock = block
   422  
   423  			ext.isSigned=false
   424  			ext.isConfirmed=false
   425  		} else if i == 5 {
   426  			lastMainBlock = block
   427  			ext.isSigned=false
   428  			ext.isConfirmed=false
   429  
   430  		}
   431  		cbft.buildIntoTree(ext)
   432  	}
   433  
   434  	notExistHeader := &types.Header{
   435  		ParentHash: parentHash,
   436  		Number:     big.NewInt(int64(20)),
   437  		TxHash:     hash(1, 20),
   438  	}
   439  	notExistBlock := types.NewBlockWithHeader(notExistHeader)
   440  
   441  
   442  	discreteHeader := &types.Header{
   443  		ParentHash: notExistBlock.Hash(),
   444  		Number:     big.NewInt(int64(6)),
   445  		TxHash:     hash(1, 6),
   446  	}
   447  	discreteBlock = types.NewBlockWithHeader(discreteHeader)
   448  
   449  	discreteExt := &BlockExt{
   450  		block:       discreteBlock,
   451  		inTree:      false,
   452  		isExecuted:  false,
   453  		isSigned:    false,
   454  		isConfirmed: false,
   455  		rcvTime:     int64(220),
   456  		Number:      discreteBlock.NumberU64(),
   457  		signs:       make([]*common.BlockConfirmSign, 0),
   458  	}
   459  	//hashSet[i] = rootBlock.Hash()
   460  	cbft.blockExtMap.Store(discreteBlock.Hash(), discreteExt)
   461  
   462  	parentHash = discreteBlock.Hash()
   463  	for i := 7; i <= 7; i++ {
   464  		header := &types.Header{
   465  			ParentHash: parentHash,
   466  			Number:     big.NewInt(int64(i)),
   467  			TxHash:     hash(1, uint64(i)),
   468  		}
   469  		block := types.NewBlockWithHeader(header)
   470  
   471  		ext := &BlockExt{
   472  			block:       block,
   473  			inTree:      false,
   474  			isExecuted:  false,
   475  			isSigned:    false,
   476  			isConfirmed: false,
   477  			rcvTime:    int64(i),
   478  			Number:      block.NumberU64(),
   479  			signs:       make([]*common.BlockConfirmSign, 0),
   480  		}
   481  		//hashSet[i] = rootBlock.Hash()
   482  		cbft.blockExtMap.Store(block.Hash(), ext)
   483  		parentHash = block.Hash()
   484  	}
   485  
   486  }
   487  
   488  func initNodes() []discover.Node {
   489  	var nodes [3]discover.Node
   490  
   491  	initialNodes := [3]string{
   492  		"1f3a8672348ff6b789e416762ad53e69063138b8eb4d8780101658f24b2369f1a8e09499226b467d8bc0c4e03e1dc903df857eeb3c67733d21b6aaee2840e429",
   493  		"751f4f62fccee84fc290d0c68d673e4b0cc6975a5747d2baccb20f954d59ba3315d7bfb6d831523624d003c8c2d33451129e67c3eef3098f711ef3b3e268fd3c",
   494  		"b6c8c9f99bfebfa4fb174df720b9385dbd398de699ec36750af3f38f8e310d4f0b90447acbef64bdf924c4b59280f3d42bb256e6123b53e9a7e99e4c432549d6",
   495  	}
   496  	nodeIDs := convert(initialNodes[:])
   497  
   498  	for i, node := range nodes {
   499  		node.ID = nodeIDs[i]
   500  	}
   501  
   502  	return nodes[:]
   503  }
   504  func convert(initialNodes []string) []discover.NodeID {
   505  	NodeIDList := make([]discover.NodeID, 0, len(initialNodes))
   506  	for _, value := range initialNodes {
   507  		if nodeID, error := discover.HexID(value); error == nil {
   508  			NodeIDList = append(NodeIDList, nodeID)
   509  		}
   510  	}
   511  	return NodeIDList
   512  }