--- /dev/null
+package protocol
+
+import (
+ "testing"
+ "time"
+
+ "github.com/vapor/protocol/bc"
+ "github.com/vapor/protocol/bc/types"
+ "github.com/vapor/testutil"
+)
+
+var testBlocks = []*types.Block{
+ &types.Block{BlockHeader: types.BlockHeader{
+ PreviousBlockHash: bc.Hash{V0: 1},
+ Timestamp: 0,
+ }},
+ &types.Block{BlockHeader: types.BlockHeader{
+ PreviousBlockHash: bc.Hash{V0: 1},
+ Timestamp: 1,
+ }},
+ &types.Block{BlockHeader: types.BlockHeader{
+ PreviousBlockHash: bc.Hash{V0: 2},
+ Timestamp: 3,
+ }},
+}
+
+var blockHashes = []bc.Hash{}
+
+func init() {
+ for _, block := range testBlocks {
+ blockHashes = append(blockHashes, block.Hash())
+ }
+}
+
+func TestDeleteLRU(t *testing.T) {
+ now := time.Now()
+ cases := []struct {
+ before *OrphanManage
+ after *OrphanManage
+ }{
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], now},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], now.Add(2)},
+ blockHashes[1]: &orphanBlock{testBlocks[1], now.Add(1)},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0], &blockHashes[1]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], now.Add(2)},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ },
+ }
+
+ for i, c := range cases {
+ c.before.deleteLRU()
+ if !testutil.DeepEqual(c.before, c.after) {
+ t.Errorf("case %d: got %v want %v", i, c.before, c.after)
+ }
+ }
+}
+
+func TestOrphanManageAdd(t *testing.T) {
+ cases := []struct {
+ before *OrphanManage
+ after *OrphanManage
+ addOrphan *types.Block
+ }{
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ addOrphan: testBlocks[0],
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ addOrphan: testBlocks[0],
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ blockHashes[1]: &orphanBlock{testBlocks[1], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0], &blockHashes[1]},
+ },
+ },
+ addOrphan: testBlocks[1],
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ blockHashes[2]: &orphanBlock{testBlocks[2], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ bc.Hash{V0: 2}: []*bc.Hash{&blockHashes[2]},
+ },
+ },
+ addOrphan: testBlocks[2],
+ },
+ }
+
+ for i, c := range cases {
+ c.before.Add(c.addOrphan)
+ for _, orphan := range c.before.orphan {
+ orphan.expiration = time.Time{}
+ }
+ if !testutil.DeepEqual(c.before, c.after) {
+ t.Errorf("case %d: got %v want %v", i, c.before, c.after)
+ }
+ }
+}
+
+func TestOrphanManageDelete(t *testing.T) {
+ cases := []struct {
+ before *OrphanManage
+ after *OrphanManage
+ remove *bc.Hash
+ }{
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ remove: &blockHashes[1],
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ remove: &blockHashes[0],
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ blockHashes[1]: &orphanBlock{testBlocks[1], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0], &blockHashes[1]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{testBlocks[0], time.Time{}},
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ remove: &blockHashes[1],
+ },
+ }
+
+ for i, c := range cases {
+ c.before.delete(c.remove)
+ if !testutil.DeepEqual(c.before, c.after) {
+ t.Errorf("case %d: got %v want %v", i, c.before, c.after)
+ }
+ }
+}
+
+func TestOrphanManageExpire(t *testing.T) {
+ cases := []struct {
+ before *OrphanManage
+ after *OrphanManage
+ }{
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{
+ testBlocks[0],
+ time.Unix(1633479700, 0),
+ },
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ },
+ },
+ {
+ before: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{
+ testBlocks[0],
+ time.Unix(1633479702, 0),
+ },
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ after: &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{
+ blockHashes[0]: &orphanBlock{
+ testBlocks[0],
+ time.Unix(1633479702, 0),
+ },
+ },
+ prevOrphans: map[bc.Hash][]*bc.Hash{
+ bc.Hash{V0: 1}: []*bc.Hash{&blockHashes[0]},
+ },
+ },
+ },
+ }
+
+ for i, c := range cases {
+ c.before.orphanExpire(time.Unix(1633479701, 0))
+ if !testutil.DeepEqual(c.before, c.after) {
+ t.Errorf("case %d: got %v want %v", i, c.before, c.after)
+ }
+ }
+}
+
+func TestOrphanManageNumLimit(t *testing.T) {
+ cases := []struct {
+ addOrphanBlockNum int
+ expectOrphanBlockNum int
+ }{
+ {
+ addOrphanBlockNum: 10,
+ expectOrphanBlockNum: 10,
+ },
+ {
+ addOrphanBlockNum: numOrphanBlockLimit,
+ expectOrphanBlockNum: numOrphanBlockLimit,
+ },
+ {
+ addOrphanBlockNum: numOrphanBlockLimit + 1,
+ expectOrphanBlockNum: numOrphanBlockLimit,
+ },
+ {
+ addOrphanBlockNum: numOrphanBlockLimit + 10,
+ expectOrphanBlockNum: numOrphanBlockLimit,
+ },
+ }
+
+ for i, c := range cases {
+ orphanManage := &OrphanManage{
+ orphan: map[bc.Hash]*orphanBlock{},
+ prevOrphans: map[bc.Hash][]*bc.Hash{},
+ }
+ for num := 0; num < c.addOrphanBlockNum; num++ {
+ orphanManage.Add(&types.Block{BlockHeader: types.BlockHeader{Height: uint64(num)}})
+ }
+ if len(orphanManage.orphan) != c.expectOrphanBlockNum {
+ t.Errorf("case %d: got %d want %d", i, len(orphanManage.orphan), c.expectOrphanBlockNum)
+ }
+ }
+}