OSDN Git Service

get consensus node test (#352)
authorPoseidon <shenao.78@163.com>
Wed, 24 Jul 2019 14:08:54 +0000 (22:08 +0800)
committerPaladz <yzhu101@uottawa.ca>
Wed, 24 Jul 2019 14:08:54 +0000 (22:08 +0800)
* get consensus node test

* remove rubish

* unexport federationNode

* remove useless code

* opt code

protocol/consensus_node_manager_test.go [new file with mode: 0644]

diff --git a/protocol/consensus_node_manager_test.go b/protocol/consensus_node_manager_test.go
new file mode 100644 (file)
index 0000000..7251196
--- /dev/null
@@ -0,0 +1,694 @@
+package protocol
+
+import (
+       "testing"
+
+       "github.com/vapor/consensus"
+       "github.com/vapor/crypto/ed25519/chainkd"
+       "github.com/vapor/database/storage"
+       "github.com/vapor/protocol/bc"
+       "github.com/vapor/protocol/bc/types"
+       "github.com/vapor/protocol/state"
+       "github.com/vapor/testutil"
+)
+
+func TestGetConsensusNodes(t *testing.T) {
+       cases := []struct {
+               desc                   string
+               prevSeqConsensusResult *state.ConsensusResult
+               storedBlockHeaders     []*types.BlockHeader
+               storedBlocks           []*types.Block
+               prevBlockHash          bc.Hash
+               bestBlockHeight        uint64
+               wantConsensusNodes     []*state.ConsensusNode
+       }{
+               {
+                       desc: "block hash in main chain",
+                       prevSeqConsensusResult: &state.ConsensusResult{
+                               Seq: 1,
+                               NumOfVote: map[string]uint64{
+                                       "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825": 838063475500000,
+                                       "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093": 474794800000000,
+                                       "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842": 833812985000000,
+                                       "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9": 285918061999999,
+                                       "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef": 1228455289930297,
+                                       "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67": 274387690000000,
+                               },
+                               BlockHash:   testutil.MustDecodeHash("65a92adc3c17657e4f0f032f1de83597dbbc6c29c24626d1533c8215f81c99e6"),
+                               BlockHeight: 1200,
+                       },
+                       storedBlockHeaders: []*types.BlockHeader{
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("7f5d567f2ad9de9af4af6e6cc81943abcd042e5a6329c83708e3578be3b5fc7d"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("65a92adc3c17657e4f0f032f1de83597dbbc6c29c24626d1533c8215f81c99e6"),
+                               },
+                               {
+                                       Height:            1202,
+                                       PreviousBlockHash: testutil.MustDecodeHash("9ff85d12c91ad5500b3dfe80bb0b4d4496ab29aec37f71e839fdd0a1c92a614f"),
+                               },
+                               {
+                                       Height:            1203,
+                                       PreviousBlockHash: testutil.MustDecodeHash("559b02b183e275e79dcfab23c66004264127f461ff8b90b3a336b2f958bf96e2"),
+                               },
+                       },
+                       prevBlockHash:   testutil.MustDecodeHash("f77d1330abc1a58ce5909581e6f2059153e116e9044e284609e07efd5f0b239e"),
+                       bestBlockHeight: 1230,
+                       wantConsensusNodes: []*state.ConsensusNode{
+                               {
+                                       XPub:    mustDecodeXPub("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"),
+                                       VoteNum: 1228455289930297,
+                                       Order:   0,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"),
+                                       VoteNum: 838063475500000,
+                                       Order:   1,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"),
+                                       VoteNum: 833812985000000,
+                                       Order:   2,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"),
+                                       VoteNum: 474794800000000,
+                                       Order:   3,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9"),
+                                       VoteNum: 285918061999999,
+                                       Order:   4,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"),
+                                       VoteNum: 274387690000000,
+                                       Order:   5,
+                               },
+                       },
+               },
+               {
+                       desc: "block hash in main chain, block height in the begin of round",
+                       prevSeqConsensusResult: &state.ConsensusResult{
+                               Seq: 1,
+                               NumOfVote: map[string]uint64{
+                                       "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825": 838063475500000,
+                                       "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093": 474794800000000,
+                                       "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842": 833812985000000,
+                                       "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9": 285918061999999,
+                                       "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef": 1228455289930297,
+                                       "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67": 274387690000000,
+                               },
+                               BlockHash:   testutil.MustDecodeHash("65a92adc3c17657e4f0f032f1de83597dbbc6c29c24626d1533c8215f81c99e6"),
+                               BlockHeight: 1200,
+                       },
+                       storedBlockHeaders: []*types.BlockHeader{
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("7f5d567f2ad9de9af4af6e6cc81943abcd042e5a6329c83708e3578be3b5fc7d"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("65a92adc3c17657e4f0f032f1de83597dbbc6c29c24626d1533c8215f81c99e6"),
+                               },
+                       },
+                       prevBlockHash:   testutil.MustDecodeHash("65a92adc3c17657e4f0f032f1de83597dbbc6c29c24626d1533c8215f81c99e6"),
+                       bestBlockHeight: 1230,
+                       wantConsensusNodes: []*state.ConsensusNode{
+                               {
+                                       XPub:    mustDecodeXPub("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"),
+                                       VoteNum: 1228455289930297,
+                                       Order:   0,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"),
+                                       VoteNum: 838063475500000,
+                                       Order:   1,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"),
+                                       VoteNum: 833812985000000,
+                                       Order:   2,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"),
+                                       VoteNum: 474794800000000,
+                                       Order:   3,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9"),
+                                       VoteNum: 285918061999999,
+                                       Order:   4,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"),
+                                       VoteNum: 274387690000000,
+                                       Order:   5,
+                               },
+                       },
+               },
+               {
+                       desc: "block hash in main chain, the consensus result is incomplete",
+                       prevSeqConsensusResult: &state.ConsensusResult{
+                               Seq: 1,
+                               NumOfVote: map[string]uint64{
+                                       "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825": 838063475500000,
+                                       "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093": 474794800000000,
+                                       "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842": 833812985000000,
+                                       "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9": 285918061999999,
+                                       "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef": 1228455289930297,
+                                       "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67": 274387690000000,
+                               },
+                               BlockHash:      testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                               BlockHeight:    1198,
+                               CoinbaseReward: make(map[string]uint64),
+                       },
+                       storedBlockHeaders: []*types.BlockHeader{
+                               {
+                                       Height:            1198,
+                                       PreviousBlockHash: testutil.MustDecodeHash("4d3ecf28f3045df23764792f41af17fc20518cc8e83673dc2d0ce07bbf084d7d"),
+                               },
+                               {
+                                       Height:            1199,
+                                       PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                               },
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("73a2a6a098727877e288a4520f2d8076d700b561277ed7c3f533e3f176496888"),
+                               },
+                       },
+                       storedBlocks: []*types.Block{
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1199,
+                                               PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 1E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 1E14, []byte{0, 1}, testutil.MustDecodeHexString("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1200,
+                                               PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 3E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 3E14, []byte{0, 1}, testutil.MustDecodeHexString("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                       },
+                       prevBlockHash:   testutil.MustDecodeHash("73a2a6a098727877e288a4520f2d8076d700b561277ed7c3f533e3f176496888"),
+                       bestBlockHeight: 1230,
+                       wantConsensusNodes: []*state.ConsensusNode{
+                               {
+                                       XPub:    mustDecodeXPub("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"),
+                                       VoteNum: 1228455289930297,
+                                       Order:   0,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"),
+                                       VoteNum: 838063475500000,
+                                       Order:   1,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"),
+                                       VoteNum: 833812985000000,
+                                       Order:   2,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9"),
+                                       VoteNum: 585918061999999,
+                                       Order:   3,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"),
+                                       VoteNum: 474794800000000,
+                                       Order:   4,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"),
+                                       VoteNum: 374387690000000,
+                                       Order:   5,
+                               },
+                       },
+               },
+               {
+                       desc: "block hash in fork chain",
+                       prevSeqConsensusResult: &state.ConsensusResult{
+                               Seq: 1,
+                               NumOfVote: map[string]uint64{
+                                       "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825": 838063475500000,
+                                       "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093": 474794800000000,
+                                       "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842": 833812985000000,
+                                       "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9": 285918061999999,
+                                       "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef": 1228455289930297,
+                                       "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67": 274387690000000,
+                               },
+                               BlockHash:      testutil.MustDecodeHash("73a2a6a098727877e288a4520f2d8076d700b561277ed7c3f533e3f176496888"),
+                               BlockHeight:    1200,
+                               CoinbaseReward: map[string]uint64{"0001": 1E8},
+                       },
+                       storedBlockHeaders: []*types.BlockHeader{
+                               // main chain
+                               {
+                                       Height:            1198,
+                                       PreviousBlockHash: testutil.MustDecodeHash("4d3ecf28f3045df23764792f41af17fc20518cc8e83673dc2d0ce07bbf084d7d"),
+                               },
+                               {
+                                       Height:            1199,
+                                       PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                               },
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("73a2a6a098727877e288a4520f2d8076d700b561277ed7c3f533e3f176496888"),
+                               },
+                               {
+                                       Height:            1202,
+                                       PreviousBlockHash: testutil.MustDecodeHash("a5be1d1177eb027327baedb869f902f74850476d0b9432a30391a3165d3af7cc"),
+                               },
+                               // fork chain
+                               {
+                                       Height:            1199,
+                                       PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                                       Timestamp:         1, // in order to make different hash
+                               },
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("cde3d8a99dee1cd44fb37f499c1980338a49ac1b9d5e6f693bd0a6f87c74e4d2"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("f819efb4baecbeb63aff6d4b14b549f1bd35955d461abaa0058a26f74c4f62da"),
+                               },
+                       },
+                       storedBlocks: []*types.Block{
+                               // main chain
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1199,
+                                               PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 1E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 1E14, []byte{0, 1}, testutil.MustDecodeHexString("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1200,
+                                               PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 2E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 2E14, []byte{0, 1}, testutil.MustDecodeHexString("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               // fork chain
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1199,
+                                               PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                                               Timestamp:         1, // in order to make different hash
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 2E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 2E14, []byte{0, 1}, testutil.MustDecodeHexString("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1200,
+                                               PreviousBlockHash: testutil.MustDecodeHash("cde3d8a99dee1cd44fb37f499c1980338a49ac1b9d5e6f693bd0a6f87c74e4d2"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 5E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 5E14, []byte{0, 1}, testutil.MustDecodeHexString("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                       },
+                       prevBlockHash:   testutil.MustDecodeHash("f819efb4baecbeb63aff6d4b14b549f1bd35955d461abaa0058a26f74c4f62da"),
+                       bestBlockHeight: 1230,
+                       wantConsensusNodes: []*state.ConsensusNode{
+                               {
+                                       XPub:    mustDecodeXPub("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"),
+                                       VoteNum: 1728455289930297,
+                                       Order:   0,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"),
+                                       VoteNum: 1038063475500000,
+                                       Order:   1,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"),
+                                       VoteNum: 833812985000000,
+                                       Order:   2,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"),
+                                       VoteNum: 474794800000000,
+                                       Order:   3,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"),
+                                       VoteNum: 174387690000000,
+                                       Order:   4,
+                               },
+                       },
+               },
+               {
+                       desc: "block hash in fork chain, the consensus result is incomplete",
+                       prevSeqConsensusResult: &state.ConsensusResult{
+                               Seq: 1,
+                               NumOfVote: map[string]uint64{
+                                       "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825": 838063475500000,
+                                       "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093": 474794800000000,
+                                       "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842": 833812985000000,
+                                       "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9": 285918061999999,
+                                       "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef": 1228455289930297,
+                                       "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67": 274387690000000,
+                               },
+                               BlockHash:      testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                               BlockHeight:    1198,
+                               CoinbaseReward: map[string]uint64{"0001": 1E8},
+                       },
+                       storedBlockHeaders: []*types.BlockHeader{
+                               // main chain
+                               {
+                                       Height:            1198,
+                                       PreviousBlockHash: testutil.MustDecodeHash("4d3ecf28f3045df23764792f41af17fc20518cc8e83673dc2d0ce07bbf084d7d"),
+                               },
+                               {
+                                       Height:            1199,
+                                       PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                               },
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("73a2a6a098727877e288a4520f2d8076d700b561277ed7c3f533e3f176496888"),
+                               },
+                               {
+                                       Height:            1202,
+                                       PreviousBlockHash: testutil.MustDecodeHash("a5be1d1177eb027327baedb869f902f74850476d0b9432a30391a3165d3af7cc"),
+                               },
+                               // fork chain
+                               {
+                                       Height:            1200,
+                                       PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                                       Timestamp:         1, // in order to make different hash
+                               },
+                               {
+                                       Height:            1201,
+                                       PreviousBlockHash: testutil.MustDecodeHash("d630737ca79f70826946f29e7cad3612662edda01c28b9471ec5b04917cdbf3e"),
+                               },
+                       },
+                       storedBlocks: []*types.Block{
+                               // main chain
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1198,
+                                               PreviousBlockHash: testutil.MustDecodeHash("4d3ecf28f3045df23764792f41af17fc20518cc8e83673dc2d0ce07bbf084d7d"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 1E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 1E14, []byte{0, 1}, testutil.MustDecodeHexString("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1199,
+                                               PreviousBlockHash: testutil.MustDecodeHash("ef24de31371b4d34363011b6c8b065b1acaad9264d9abae2253d584e0d3a8739"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 1E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 1E14, []byte{0, 1}, testutil.MustDecodeHexString("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1200,
+                                               PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 2E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 2E14, []byte{0, 1}, testutil.MustDecodeHexString("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                               // fork chain
+                               {
+                                       BlockHeader: types.BlockHeader{
+                                               Height:            1200,
+                                               PreviousBlockHash: testutil.MustDecodeHash("608d82b3660255186fb2b035cfb2ca86e986433218cd2eca2e79611e855a87d3"),
+                                               Timestamp:         1, // in order to make different hash
+                                       },
+                                       Transactions: []*types.Tx{
+                                               {
+                                                       TxData: types.TxData{
+                                                               Inputs: []*types.TxInput{
+                                                                       types.NewSpendInput(nil, bc.NewHash([32]byte{0, 1}), *consensus.BTMAssetID, 5E14, 0, []byte{0, 1}),
+                                                               },
+                                                               Outputs: []*types.TxOutput{
+                                                                       types.NewVoteOutput(*consensus.BTMAssetID, 5E14, []byte{0, 1}, testutil.MustDecodeHexString("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef")),
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                       },
+                       prevBlockHash:   testutil.MustDecodeHash("d630737ca79f70826946f29e7cad3612662edda01c28b9471ec5b04917cdbf3e"),
+                       bestBlockHeight: 1230,
+                       wantConsensusNodes: []*state.ConsensusNode{
+                               {
+                                       XPub:    mustDecodeXPub("b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"),
+                                       VoteNum: 1728455289930297,
+                                       Order:   0,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"),
+                                       VoteNum: 838063475500000,
+                                       Order:   1,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"),
+                                       VoteNum: 833812985000000,
+                                       Order:   2,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"),
+                                       VoteNum: 474794800000000,
+                                       Order:   3,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"),
+                                       VoteNum: 374387690000000,
+                                       Order:   4,
+                               },
+                               {
+                                       XPub:    mustDecodeXPub("b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9"),
+                                       VoteNum: 285918061999999,
+                                       Order:   5,
+                               },
+                       },
+               },
+       }
+
+       for i, c := range cases {
+               store := newDummyStore()
+               for _, header := range c.storedBlockHeaders {
+                       store.SaveBlockHeader(header)
+               }
+
+               for _, block := range c.storedBlocks {
+                       store.SaveBlock(block, nil)
+               }
+
+               store.SetConsensusResult(c.prevSeqConsensusResult)
+
+               chain := &Chain{
+                       store:           store,
+                       bestBlockHeader: &types.BlockHeader{Height: c.bestBlockHeight},
+               }
+               gotConsensusNodes, err := chain.getConsensusNodes(&c.prevBlockHash)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               wantConsensusNodes := make(map[string]*state.ConsensusNode)
+               for _, node := range c.wantConsensusNodes {
+                       wantConsensusNodes[node.XPub.String()] = node
+               }
+
+               if !testutil.DeepEqual(gotConsensusNodes, wantConsensusNodes) {
+                       t.Errorf("#%d (%s) got consensus nodes:%v, want consensus nodes:%v", i, c.desc, gotConsensusNodes, wantConsensusNodes)
+               }
+       }
+}
+
+func mustDecodeXPub(xpub string) chainkd.XPub {
+       bytes := testutil.MustDecodeHexString(xpub)
+       var result [64]byte
+       copy(result[:], bytes)
+       return result
+}
+
+type dummyStore struct {
+       blockHeaders     map[string]*types.BlockHeader
+       blocks           map[string]*types.Block
+       consensusResults map[uint64]*state.ConsensusResult
+}
+
+func newDummyStore() *dummyStore {
+       return &dummyStore{
+               blockHeaders:     make(map[string]*types.BlockHeader),
+               consensusResults: make(map[uint64]*state.ConsensusResult),
+               blocks:           make(map[string]*types.Block),
+       }
+}
+
+func (s *dummyStore) BlockExist(*bc.Hash) bool {
+       return false
+}
+
+func (s *dummyStore) GetBlock(hash *bc.Hash) (*types.Block, error) {
+       return s.blocks[hash.String()], nil
+}
+
+func (s *dummyStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
+       return s.blockHeaders[hash.String()], nil
+}
+
+func (s *dummyStore) GetStoreStatus() *BlockStoreState {
+       return nil
+}
+
+func (s *dummyStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) {
+       return nil, nil
+}
+
+func (s *dummyStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error {
+       return nil
+}
+
+func (s *dummyStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) {
+       return nil, nil
+}
+
+func (s *dummyStore) GetConsensusResult(seq uint64) (*state.ConsensusResult, error) {
+       return s.consensusResults[seq], nil
+}
+
+func (s *dummyStore) SetConsensusResult(consensusResult *state.ConsensusResult) {
+       s.consensusResults[consensusResult.Seq] = consensusResult
+}
+
+func (s *dummyStore) GetMainChainHash(uint64) (*bc.Hash, error) {
+       return nil, nil
+}
+
+func (s *dummyStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) {
+       return nil, nil
+}
+
+func (s *dummyStore) SaveBlock(block *types.Block, _ *bc.TransactionStatus) error {
+       hash := block.Hash()
+       s.blocks[hash.String()] = block
+       return nil
+}
+
+func (s *dummyStore) SaveBlockHeader(header *types.BlockHeader) error {
+       hash := header.Hash()
+       s.blockHeaders[hash.String()] = header
+       return nil
+}
+
+func (s *dummyStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
+       return nil
+}