OSDN Git Service

add test case for send merkle block (#1289)
authormuscle_boy <shenao.78@163.com>
Wed, 29 Aug 2018 13:49:44 +0000 (21:49 +0800)
committerPaladz <yzhu101@uottawa.ca>
Wed, 29 Aug 2018 13:49:44 +0000 (21:49 +0800)
* the transaction output amout prohibit set zero

* add network access control api

* format import code style

* refactor

* code refactor

* bug fix

* the struct node_info add json field

* estimate gas support multi-sign

* add testcase of estimate gas

* add testcase

* bug fix

* add test case

* test case refactor

* list-tx,list-address,list-utxo support partition

* list-addresses list-tx list-utxo support pagging

* refactor pagging

* fix save asset

* fix save external assets

* remove blank

* remove useless context

* remove redudant web address config

* fix bug

* remove useless ctx

* add spv message struct

* remove redundant

* refactor message struct

* refactor message struct

* add filter load message handler

* add debug log

* bug fix spv

* bug fix

* bug fix

* refactor

* refactor

* add merkle proof

* add merkle flags test case

* add multiset

* bug fix and refactor

* bug fix

* remove redundant code

* bug fix

* bug fix

* format code

* refactor merkle tree

* refactor

* refactor

* fix bug for make test

* bug fix

* move merkle tree to bc level

* NewMinedBlockMessage not broadcast to the spv node

* refactor

* refactor

* refactor

* merkle tree bug fix

* merkle tree bug fix

* limit the size of filter address

* bug fix

* refactor

* fix full node connect to spv node

* format code

* bug fix

* fix bug

* add merkle block test case

* format code

* refactor

* bug fix for merkle block case

* refactor

* add test case

* test case refactor

* refactor

* refactor test case

* refactor test case

* add test case

netsync/block_keeper_test.go
netsync/tool_test.go
protocol/bc/types/merkle.go
protocol/bc/types/merkle_test.go
test/mock/chain.go

index fa3b6ff..4f4ae15 100644 (file)
@@ -2,6 +2,8 @@ package netsync
 
 import (
        "container/list"
+       "encoding/hex"
+       "encoding/json"
        "testing"
        "time"
 
@@ -181,8 +183,11 @@ func TestFastBlockSync(t *testing.T) {
                netWork := NewNetWork()
                netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
                netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
-               if err := netWork.HandsShake(a, b); err != nil {
+               if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
                        t.Errorf("fail on peer hands shake %v", err)
+               } else {
+                       go B2A.postMan()
+                       go A2B.postMan()
                }
 
                a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
@@ -439,8 +444,11 @@ func TestRegularBlockSync(t *testing.T) {
                netWork := NewNetWork()
                netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
                netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
-               if err := netWork.HandsShake(a, b); err != nil {
+               if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
                        t.Errorf("fail on peer hands shake %v", err)
+               } else {
+                       go B2A.postMan()
+                       go A2B.postMan()
                }
 
                a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
@@ -470,8 +478,11 @@ func TestRequireBlock(t *testing.T) {
        netWork := NewNetWork()
        netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
        netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
-       if err := netWork.HandsShake(a, b); err != nil {
+       if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
                t.Errorf("fail on peer hands shake %v", err)
+       } else {
+               go B2A.postMan()
+               go A2B.postMan()
        }
 
        a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
@@ -510,3 +521,120 @@ func TestRequireBlock(t *testing.T) {
                }
        }
 }
+
+func TestSendMerkleBlock(t *testing.T) {
+       cases := []struct {
+               txCount        int
+               relatedTxIndex []int
+       }{
+               {
+                       txCount:        10,
+                       relatedTxIndex: []int{0, 2, 5},
+               },
+               {
+                       txCount:        0,
+                       relatedTxIndex: []int{},
+               },
+               {
+                       txCount:        10,
+                       relatedTxIndex: []int{},
+               },
+               {
+                       txCount:        5,
+                       relatedTxIndex: []int{0, 1, 2, 3, 4},
+               },
+               {
+                       txCount:        20,
+                       relatedTxIndex: []int{1, 6, 3, 9, 10, 19},
+               },
+       }
+
+       for _, c := range cases {
+               blocks := mockBlocks(nil, 2)
+               targetBlock := blocks[1]
+               txs, bcTxs := mockTxs(c.txCount)
+               var err error
+
+               targetBlock.Transactions = txs
+               if targetBlock.TransactionsMerkleRoot, err = types.TxMerkleRoot(bcTxs); err != nil {
+                       t.Fatal(err)
+               }
+
+               spvNode := mockSync(blocks)
+               blockHash := targetBlock.Hash()
+               var statusResult *bc.TransactionStatus
+               if statusResult, err = spvNode.chain.GetTransactionStatus(&blockHash); err != nil {
+                       t.Fatal(err)
+               }
+               
+               if targetBlock.TransactionStatusHash, err = types.TxStatusMerkleRoot(statusResult.VerifyStatus); err != nil {
+                       t.Fatal(err)
+               }
+               
+               fullNode := mockSync(blocks)
+               netWork := NewNetWork()
+               netWork.Register(spvNode, "192.168.0.1", "spv_node", consensus.SFFastSync)
+               netWork.Register(fullNode, "192.168.0.2", "full_node", consensus.DefaultServices)
+
+               var F2S *P2PPeer
+               if F2S, _, err = netWork.HandsShake(spvNode, fullNode); err != nil {
+                       t.Errorf("fail on peer hands shake %v", err)
+               }
+
+               completed := make(chan error)
+               go func() {
+                       msgBytes := <-F2S.msgCh
+                       _, msg, _ := DecodeMessage(msgBytes)
+                       switch m := msg.(type) {
+                       case *MerkleBlockMessage:
+                               var relatedTxIDs []*bc.Hash
+                               for _, rawTx := range m.RawTxDatas {
+                                       tx := &types.Tx{}
+                                       if err := tx.UnmarshalText(rawTx); err != nil {
+                                               completed <- err
+                                       }
+
+                                       relatedTxIDs = append(relatedTxIDs, &tx.ID)
+                               }
+                               var txHashes []*bc.Hash
+                               for _, hashByte := range m.TxHashes {
+                                       hash := bc.NewHash(hashByte)
+                                       txHashes = append(txHashes, &hash)
+                               }
+                               if ok := types.ValidateTxMerkleTreeProof(txHashes, m.Flags, relatedTxIDs, targetBlock.TransactionsMerkleRoot); !ok {
+                                       completed <- errors.New("validate tx fail")
+                               }
+
+                               var statusHashes []*bc.Hash
+                               for _, statusByte := range m.StatusHashes {
+                                       hash := bc.NewHash(statusByte)
+                                       statusHashes = append(statusHashes, &hash)
+                               }
+                               var relatedStatuses []*bc.TxVerifyResult
+                               for _, statusByte := range m.RawTxStatuses {
+                                       status := &bc.TxVerifyResult{}
+                                       err := json.Unmarshal(statusByte, status)
+                                       if err != nil {
+                                               completed <- err
+                                       }
+                                       relatedStatuses = append(relatedStatuses, status)
+                               }
+                               if ok := types.ValidateStatusMerkleTreeProof(statusHashes, m.Flags, relatedStatuses, targetBlock.TransactionStatusHash); !ok {
+                                       completed <- errors.New("validate status fail")
+                               }
+
+                               completed <- nil
+                       }
+               }()
+
+               spvPeer := fullNode.peers.getPeer("spv_node")
+               for i := 0; i < len(c.relatedTxIndex); i++ {
+                       spvPeer.filterAdds.Add(hex.EncodeToString(txs[c.relatedTxIndex[i]].Outputs[0].ControlProgram))
+               }
+               msg := &GetMerkleBlockMessage{RawHash: targetBlock.Hash().Byte32()}
+               fullNode.handleGetMerkleBlockMsg(spvPeer, msg)
+               if err := <-completed; err != nil {
+                       t.Fatal(err)
+               }
+       }
+}
index 88e6d37..253e84e 100644 (file)
@@ -4,10 +4,12 @@ import (
        "errors"
        "math/rand"
        "net"
+       "time"
 
        wire "github.com/tendermint/go-wire"
 
        "github.com/bytom/consensus"
+       "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
        "github.com/bytom/test/mock"
 )
@@ -94,27 +96,25 @@ func (nw *NetWork) Register(node *SyncManager, addr, id string, flag consensus.S
        nw.nodes[node] = *peer
 }
 
-func (nw *NetWork) HandsShake(nodeA, nodeB *SyncManager) error {
+func (nw *NetWork) HandsShake(nodeA, nodeB *SyncManager) (*P2PPeer, *P2PPeer, error) {
        B2A, ok := nw.nodes[nodeA]
        if !ok {
-               return errors.New("can't find nodeA's p2p peer on network")
+               return nil, nil, errors.New("can't find nodeA's p2p peer on network")
        }
        A2B, ok := nw.nodes[nodeB]
        if !ok {
-               return errors.New("can't find nodeB's p2p peer on network")
+               return nil, nil, errors.New("can't find nodeB's p2p peer on network")
        }
 
        A2B.SetConnection(&B2A, nodeB)
        B2A.SetConnection(&A2B, nodeA)
-       go A2B.postMan()
-       go B2A.postMan()
 
        nodeA.handleStatusRequestMsg(&A2B)
        nodeB.handleStatusRequestMsg(&B2A)
 
        A2B.setAsync(true)
        B2A.setAsync(true)
-       return nil
+       return &B2A, &A2B, nil
 }
 
 func mockBlocks(startBlock *types.Block, height uint64) []*types.Block {
@@ -157,3 +157,30 @@ func mockSync(blocks []*types.Block) *SyncManager {
                peers:       peers,
        }
 }
+
+func mockTxs(txCount int) ([]*types.Tx, []*bc.Tx) {
+       var txs []*types.Tx
+       var bcTxs []*bc.Tx
+       for i := 0; i < txCount; i++ {
+               trueProg := mockControlProgram(60)
+               assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash)
+               now := []byte(time.Now().String())
+               issuanceInp := types.NewIssuanceInput(now, 1, trueProg, nil, nil)
+               tx := types.NewTx(types.TxData{
+                       Version: 1,
+                       Inputs:  []*types.TxInput{issuanceInp},
+                       Outputs: []*types.TxOutput{types.NewTxOutput(assetID, 1, trueProg)},
+               })
+               txs = append(txs, tx)
+               bcTxs = append(bcTxs, tx.Tx)
+       }
+       return txs, bcTxs
+}
+
+func mockControlProgram(length int) []byte {
+       var cp []byte
+       for i := 0; i < length; i++ {
+               cp = append(cp, byte(rand.Intn(1<<8)))
+       }
+       return cp
+}
index dca07d4..78fbac7 100644 (file)
@@ -160,6 +160,9 @@ func getMerkleTreeProof(rawDatas []merkleNode, relatedRawDatas []merkleNode) ([]
                merkleHash := leafMerkleHash(data)
                merkleHashSet.Add(merkleHash.String())
        }
+       if merkleHashSet.Size() == 0 {
+               return []*bc.Hash{&merkleTree.hash}, []uint8{FlagAssist}
+       }
        return merkleTree.getMerkleTreeProof(merkleHashSet)
 }
 
@@ -222,36 +225,43 @@ func GetStatusMerkleTreeProof(statuses []*bc.TxVerifyResult, flags []uint8) []*b
 
 // getMerkleRootByProof caculate the merkle root hash according to the proof
 func getMerkleRootByProof(hashList *list.List, flagList *list.List, merkleHashes *list.List) bc.Hash {
-       if flagList.Len() == 0 {
+       if flagList.Len() == 0 || hashList.Len() == 0 {
                return bc.EmptyStringHash
        }
        flagEle := flagList.Front()
        flag := flagEle.Value.(uint8)
        flagList.Remove(flagEle)
-       if flag == FlagAssist {
-               hash := hashList.Front()
-               hashList.Remove(hash)
-               return hash.Value.(bc.Hash)
-       }
-       if flag == FlagTxLeaf {
-               if hashList.Len() == 0 || merkleHashes.Len() == 0 {
-                       return bc.EmptyStringHash
+       switch flag {
+       case FlagAssist:
+               {
+                       hash := hashList.Front()
+                       hashList.Remove(hash)
+                       return hash.Value.(bc.Hash)
                }
-               hashEle := hashList.Front()
-               hash := hashEle.Value.(bc.Hash)
-               relatedHashEle := merkleHashes.Front()
-               relatedHash := relatedHashEle.Value.(bc.Hash)
-               if hash == relatedHash {
-                       hashList.Remove(hashEle)
-                       merkleHashes.Remove(relatedHashEle)
+       case FlagTxLeaf:
+               {
+                       if merkleHashes.Len() == 0 {
+                               return bc.EmptyStringHash
+                       }
+                       hashEle := hashList.Front()
+                       hash := hashEle.Value.(bc.Hash)
+                       relatedHashEle := merkleHashes.Front()
+                       relatedHash := relatedHashEle.Value.(bc.Hash)
+                       if hash == relatedHash {
+                               hashList.Remove(hashEle)
+                               merkleHashes.Remove(relatedHashEle)
+                               return hash
+                       }
+               }
+       case FlagTxParent:
+               {
+                       leftHash := getMerkleRootByProof(hashList, flagList, merkleHashes)
+                       rightHash := getMerkleRootByProof(hashList, flagList, merkleHashes)
+                       hash := interiorMerkleHash(&leftHash, &rightHash)
                        return hash
                }
-               return bc.EmptyStringHash
        }
-       leftHash := getMerkleRootByProof(hashList, flagList, merkleHashes)
-       rightHash := getMerkleRootByProof(hashList, flagList, merkleHashes)
-       hash := interiorMerkleHash(&leftHash, &rightHash)
-       return hash
+       return bc.EmptyStringHash
 }
 
 func newMerkleTreeNode(merkleHash bc.Hash, left *merkleTreeNode, right *merkleTreeNode) *merkleTreeNode {
index 77022e0..c3c0f32 100644 (file)
@@ -1,8 +1,9 @@
 package types
 
 import (
+       "encoding/hex"
+
        "math/rand"
-       "reflect"
        "testing"
        "time"
 
@@ -145,11 +146,290 @@ func TestAllDuplicateLeaves(t *testing.T) {
 }
 
 func TestTxMerkleProof(t *testing.T) {
+       cases := []struct {
+               txCount          int
+               relatedTxIndexes []int
+               expectHashLen    int
+               expectFlags      []uint8
+       }{
+               {
+                       txCount:          10,
+                       relatedTxIndexes: []int{0, 3, 7, 8},
+                       expectHashLen:    9,
+                       expectFlags:      []uint8{1, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 2, 0},
+               },
+               {
+                       txCount:          10,
+                       relatedTxIndexes: []int{},
+                       expectHashLen:    1,
+                       expectFlags:      []uint8{0},
+               },
+               {
+                       txCount:          1,
+                       relatedTxIndexes: []int{0},
+                       expectHashLen:    1,
+                       expectFlags:      []uint8{2},
+               },
+               {
+                       txCount:          19,
+                       relatedTxIndexes: []int{1, 3, 5, 7, 11, 15},
+                       expectHashLen:    15,
+                       expectFlags:      []uint8{1, 1, 1, 1, 1, 0, 2, 1, 0, 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 0, 1, 0, 2, 1, 0, 1, 0, 2, 0},
+               },
+       }
+       for _, c := range cases {
+               txs, bcTxs := mockTransactions(c.txCount)
+
+               var nodes []merkleNode
+               for _, tx := range txs {
+                       nodes = append(nodes, tx.ID)
+               }
+               tree := buildMerkleTree(nodes)
+               root, err := TxMerkleRoot(bcTxs)
+               if err != nil {
+                       t.Fatalf("unexpected error %s", err)
+               }
+               if tree.hash != root {
+                       t.Error("build tree fail")
+               }
+
+               var relatedTx []*Tx
+               for _, index := range c.relatedTxIndexes {
+                       relatedTx = append(relatedTx, txs[index])
+               }
+               proofHashes, flags := GetTxMerkleTreeProof(txs, relatedTx)
+               if !testutil.DeepEqual(flags, c.expectFlags) {
+                       t.Error("The flags is not equals expect flags", flags, c.expectFlags)
+               }
+               if len(proofHashes) != c.expectHashLen {
+                       t.Error("The length proof hashes is not equals expect length")
+               }
+               var ids []*bc.Hash
+               for _, tx := range relatedTx {
+                       ids = append(ids, &tx.ID)
+               }
+               if !ValidateTxMerkleTreeProof(proofHashes, flags, ids, root) {
+                       t.Error("Merkle tree validate fail")
+               }
+       }
+}
+
+func TestStatusMerkleProof(t *testing.T) {
+       cases := []struct {
+               statusCount    int
+               relatedIndexes []int
+               flags          []uint8
+               expectHashLen  int
+       }{
+               {
+                       statusCount:    10,
+                       relatedIndexes: []int{0, 3, 7, 8},
+                       flags:          []uint8{1, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 2, 0},
+                       expectHashLen:  9,
+               },
+               {
+                       statusCount:    10,
+                       relatedIndexes: []int{},
+                       flags:          []uint8{0},
+                       expectHashLen:  1,
+               },
+               {
+                       statusCount:    1,
+                       relatedIndexes: []int{0},
+                       flags:          []uint8{2},
+                       expectHashLen:  1,
+               },
+               {
+                       statusCount:    19,
+                       relatedIndexes: []int{1, 3, 5, 7, 11, 15},
+                       flags:          []uint8{1, 1, 1, 1, 1, 0, 2, 1, 0, 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 0, 1, 0, 2, 1, 0, 1, 0, 2, 0},
+                       expectHashLen:  15,
+               },
+       }
+       for _, c := range cases {
+               statuses := mockStatuses(c.statusCount)
+               var relatedStatuses []*bc.TxVerifyResult
+               for _, index := range c.relatedIndexes {
+                       relatedStatuses = append(relatedStatuses, statuses[index])
+               }
+               hashes := GetStatusMerkleTreeProof(statuses, c.flags)
+               if len(hashes) != c.expectHashLen {
+                       t.Error("The length proof hashes is not equals expect length")
+               }
+               root, _ := TxStatusMerkleRoot(statuses)
+               if !ValidateStatusMerkleTreeProof(hashes, c.flags, relatedStatuses, root) {
+                       t.Error("Merkle tree validate fail")
+               }
+       }
+}
+
+func TestUglyValidateTxMerkleProof(t *testing.T) {
+       cases := []struct {
+               hashes        []string
+               flags         []uint8
+               relatedHashes []string
+               root          string
+               expectResult  bool
+       }{
+               {
+                       hashes:        []string{},
+                       flags:         []uint8{},
+                       relatedHashes: []string{},
+                       root:          "",
+                       expectResult:  false,
+               },
+               {
+                       hashes:        []string{},
+                       flags:         []uint8{1, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 2, 0},
+                       relatedHashes: []string{},
+                       root:          "",
+                       expectResult:  false,
+               },
+               {
+                       hashes: []string{
+                               "0093370a8e19f8f131fd7e75c576615950d5672ee5e18c63f105a95bcab4332c",
+                               "c9b7779847fb7ab74cf4b1e7f4557133918faa2bc130042753417dfb62b12dfa",
+                       },
+                       flags:         []uint8{},
+                       relatedHashes: []string{},
+                       root:          "",
+                       expectResult:  false,
+               },
+               {
+                       hashes: []string{},
+                       flags:  []uint8{},
+                       relatedHashes: []string{
+                               "0093370a8e19f8f131fd7e75c576615950d5672ee5e18c63f105a95bcab4332c",
+                               "c9b7779847fb7ab74cf4b1e7f4557133918faa2bc130042753417dfb62b12dfa",
+                       },
+                       root:         "",
+                       expectResult: false,
+               },
+               {
+                       hashes: []string{},
+                       flags:  []uint8{1, 1, 0, 2, 1, 2, 1, 0, 1},
+                       relatedHashes: []string{
+                               "0093370a8e19f8f131fd7e75c576615950d5672ee5e18c63f105a95bcab4332c",
+                               "c9b7779847fb7ab74cf4b1e7f4557133918faa2bc130042753417dfb62b12dfa",
+                       },
+                       root: "281138e0a9ea19505844bd61a2f5843787035782c093da74d12b5fba73eeeb07",
+               },
+               {
+                       hashes: []string{
+                               "68f03ea2b02a21ad944d1a43ad6152a7fa6a7ed4101d59be62594dd30ef2a558",
+                       },
+                       flags: []uint8{},
+                       relatedHashes: []string{
+                               "0093370a8e19f8f131fd7e75c576615950d5672ee5e18c63f105a95bcab4332c",
+                               "c9b7779847fb7ab74cf4b1e7f4557133918faa2bc130042753417dfb62b12dfa",
+                       },
+                       root:         "281138e0a9ea19505844bd61a2f5843787035782c093da74d12b5fba73eeeb07",
+                       expectResult: false,
+               },
+               {
+                       hashes: []string{
+                               "8ec3ee7589f95eee9b534f71fcd37142bcc839a0dbfe78124df9663827b90c35",
+                               "011bd3380852b2946df507e0c6234222c559eec8f545e4bc58a89e960892259b",
+                               "c205988d9c864083421f1bdb95e6cf8b52070facfcc87e46a6e8197f5389fca2",
+                       },
+                       flags: []uint8{1, 1, 0, 2, 0},
+                       relatedHashes: []string{
+                               "504af455e328e7dd39bbc059529851946d54ee8b459b11b3aac4a0feeb474487",
+                       },
+                       root:         "aff81a46fe79204ef9007243f374d54104a59762b9f74d80d56b5291753db6fb",
+                       expectResult: true,
+               },
+               // flags and hashes is correct, but relatedHashes has hash that does not exist
+               {
+                       hashes: []string{
+                               "8ec3ee7589f95eee9b534f71fcd37142bcc839a0dbfe78124df9663827b90c35",
+                               "011bd3380852b2946df507e0c6234222c559eec8f545e4bc58a89e960892259b",
+                               "c205988d9c864083421f1bdb95e6cf8b52070facfcc87e46a6e8197f5389fca2",
+                       },
+                       flags: []uint8{1, 1, 0, 2, 0},
+                       relatedHashes: []string{
+                               "504af455e328e7dd39bbc059529851946d54ee8b459b11b3aac4a0feeb474487",
+                               "281138e0a9ea19505844bd61a2f5843787035782c093da74d12b5fba73eeeb07",
+                       },
+                       root:         "aff81a46fe79204ef9007243f374d54104a59762b9f74d80d56b5291753db6fb",
+                       expectResult: false,
+               },
+               // flags and hashes is correct, but relatedHashes is not enough
+               {
+                       hashes: []string{
+                               "8ec3ee7589f95eee9b534f71fcd37142bcc839a0dbfe78124df9663827b90c35",
+                               "011bd3380852b2946df507e0c6234222c559eec8f545e4bc58a89e960892259b",
+                               "c205988d9c864083421f1bdb95e6cf8b52070facfcc87e46a6e8197f5389fca2",
+                       },
+                       flags:         []uint8{1, 1, 0, 2, 0},
+                       relatedHashes: []string{},
+                       root:          "aff81a46fe79204ef9007243f374d54104a59762b9f74d80d56b5291753db6fb",
+                       expectResult:  false,
+               },
+               // flags is correct, but hashes has additional hash at the end
+               {
+                       hashes: []string{
+                               "8ec3ee7589f95eee9b534f71fcd37142bcc839a0dbfe78124df9663827b90c35",
+                               "011bd3380852b2946df507e0c6234222c559eec8f545e4bc58a89e960892259b",
+                               "c205988d9c864083421f1bdb95e6cf8b52070facfcc87e46a6e8197f5389fca2",
+                               "5a06c90136e81c0f9cad29725e69edc6d21bd6fb0641265f9c4b6bb6840b37dd",
+                       },
+                       flags: []uint8{1, 1, 0, 2, 0},
+                       relatedHashes: []string{
+                               "504af455e328e7dd39bbc059529851946d54ee8b459b11b3aac4a0feeb474487",
+                       },
+                       root:         "aff81a46fe79204ef9007243f374d54104a59762b9f74d80d56b5291753db6fb",
+                       expectResult: true,
+               },
+       }
+
+       for _, c := range cases {
+               var hashes, relatedHashes []*bc.Hash
+               var hashBytes, rootBytes [32]byte
+               var err error
+               for _, hashStr := range c.hashes {
+                       if hashBytes, err = convertHashStr2Bytes(hashStr); err != nil {
+                               t.Fatal(err)
+                       }
+
+                       hash := bc.NewHash(hashBytes)
+                       hashes = append(hashes, &hash)
+               }
+               for _, hashStr := range c.relatedHashes {
+                       if hashBytes, err = convertHashStr2Bytes(hashStr); err != nil {
+                               t.Fatal(err)
+                       }
+
+                       hash := bc.NewHash(hashBytes)
+                       relatedHashes = append(relatedHashes, &hash)
+               }
+               if rootBytes, err = convertHashStr2Bytes(c.root); err != nil {
+                       t.Fatal(err)
+               }
+
+               root := bc.NewHash(rootBytes)
+               if ValidateTxMerkleTreeProof(hashes, c.flags, relatedHashes, root) != c.expectResult {
+                       t.Error("Validate merkle tree proof fail")
+               }
+       }
+}
+
+func convertHashStr2Bytes(hashStr string) ([32]byte, error) {
+       var result [32]byte
+       hashBytes, err := hex.DecodeString(hashStr)
+       if err != nil {
+               return result, err
+       }
+       copy(result[:], hashBytes)
+       return result, nil
+}
+
+func mockTransactions(txCount int) ([]*Tx, []*bc.Tx) {
        var txs []*Tx
        var bcTxs []*bc.Tx
        trueProg := []byte{byte(vm.OP_TRUE)}
        assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash)
-       for i := 0; i < 10; i++ {
+       for i := 0; i < txCount; i++ {
                now := []byte(time.Now().String())
                issuanceInp := NewIssuanceInput(now, 1, trueProg, nil, nil)
                tx := NewTx(TxData{
@@ -160,32 +440,12 @@ func TestTxMerkleProof(t *testing.T) {
                txs = append(txs, tx)
                bcTxs = append(bcTxs, tx.Tx)
        }
-       root, err := TxMerkleRoot(bcTxs)
-       if err != nil {
-               t.Fatalf("unexpected error %s", err)
-       }
-
-       relatedTx := []*Tx{txs[0], txs[3], txs[7], txs[8]}
-       proofHashes, flags := GetTxMerkleTreeProof(txs, relatedTx)
-       if len(proofHashes) <= 0 {
-               t.Error("Can not find any tx id in the merkle tree")
-       }
-       expectFlags := []uint8{1, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 2, 0}
-       if !reflect.DeepEqual(flags, expectFlags) {
-               t.Error("The flags is not equals expect flags", flags)
-       }
-       if len(proofHashes) != 9 {
-               t.Error("The length proof hashes is not equals expect length")
-       }
-       ids := []*bc.Hash{&txs[0].ID, &txs[3].ID, &txs[7].ID, &txs[8].ID}
-       if !ValidateTxMerkleTreeProof(proofHashes, flags, ids, root) {
-               t.Error("Merkle tree validate fail")
-       }
+       return txs, bcTxs
 }
 
-func TestStatusMerkleProof(t *testing.T) {
+func mockStatuses(statusCount int) []*bc.TxVerifyResult {
        var statuses []*bc.TxVerifyResult
-       for i := 0; i < 10; i++ {
+       for i := 0; i < statusCount; i++ {
                status := &bc.TxVerifyResult{}
                fail := rand.Intn(2)
                if fail == 0 {
@@ -195,14 +455,5 @@ func TestStatusMerkleProof(t *testing.T) {
                }
                statuses = append(statuses, status)
        }
-       relatedStatuses := []*bc.TxVerifyResult{statuses[0], statuses[3], statuses[7], statuses[8]}
-       flags := []uint8{1, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1, 0, 2, 1, 2, 0}
-       hashes := GetStatusMerkleTreeProof(statuses, flags)
-       if len(hashes) != 9 {
-               t.Error("The length proof hashes is not equals expect length")
-       }
-       root, _ := TxStatusMerkleRoot(statuses)
-       if !ValidateStatusMerkleTreeProof(hashes, flags, relatedStatuses, root) {
-               t.Error("Merkle tree validate fail")
-       }
+       return statuses
 }
index a25dd41..271d958 100644 (file)
@@ -2,6 +2,7 @@ package mock
 
 import (
        "errors"
+       "math/rand"
 
        "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
@@ -68,7 +69,24 @@ func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
 }
 
 func (c *Chain) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
-       return nil, nil
+       block, err := c.GetBlockByHash(hash)
+       if err != nil {
+               return nil, errors.New("can't find block by hash")
+       }
+       txCount := len(block.Transactions)
+       var statuses []*bc.TxVerifyResult
+       rand.Seed(int64(block.Height))
+       for i := 0; i < txCount; i++ {
+               status := &bc.TxVerifyResult{}
+               if fail := rand.Intn(2); fail == 0 {
+                       status.StatusFail = true
+               } else {
+                       status.StatusFail = false
+               }
+               statuses = append(statuses, status)
+       }
+       txStatus := &bc.TransactionStatus{VerifyStatus: statuses}
+       return txStatus, nil
 }
 
 func (c *Chain) InMainChain(hash bc.Hash) bool {