OSDN Git Service

add merkle proof api (#1308)
authormuscle_boy <shenao.78@163.com>
Fri, 31 Aug 2018 07:31:38 +0000 (15:31 +0800)
committerPaladz <yzhu101@uottawa.ca>
Fri, 31 Aug 2018 07:31:38 +0000 (15:31 +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

* add merkle proof api

* refactor

api/api.go
api/block_retrieve.go

index bd85426..a6bb374 100644 (file)
@@ -287,6 +287,8 @@ func (a *API) buildHandler() {
        m.Handle("/disconnect-peer", jsonHandler(a.disconnectPeer))
        m.Handle("/connect-peer", jsonHandler(a.connectPeer))
 
+       m.Handle("/get-merkle-proof", jsonHandler(a.getMerkleProof))
+
        handler := latencyHandler(m, walletEnable)
        handler = maxBytesHandler(handler) // TODO(tessr): consider moving this to non-core specific mux
        handler = webAssetsHandler(handler)
index 9b43b76..8c67ff5 100644 (file)
@@ -3,6 +3,8 @@ package api
 import (
        "math/big"
 
+       "gopkg.in/fatih/set.v0"
+
        "github.com/bytom/blockchain/query"
        "github.com/bytom/consensus/difficulty"
        chainjson "github.com/bytom/encoding/json"
@@ -141,15 +143,19 @@ func (a *API) getBlockHeader(ins BlockReq) Response {
 
 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
        if len(ins.BlockHash) == 32 {
-               b32 := [32]byte{}
-               copy(b32[:], ins.BlockHash)
-               hash := bc.NewHash(b32)
+               hash := hexBytesToHash(ins.BlockHash)
                return a.chain.GetBlockByHash(&hash)
        } else {
                return a.chain.GetBlockByHeight(ins.BlockHeight)
        }
 }
 
+func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
+       b32 := [32]byte{}
+       copy(b32[:], hexBytes)
+       return bc.NewHash(b32)
+}
+
 // GetDifficultyResp is resp struct for getDifficulty API
 type GetDifficultyResp struct {
        BlockHash   *bc.Hash `json:"hash"`
@@ -212,3 +218,72 @@ func (a *API) getHashRate(ins BlockReq) Response {
        }
        return NewSuccessResponse(resp)
 }
+
+// MerkleBlockReq is used to handle getTxOutProof req
+type MerkleBlockReq struct {
+       TxIDs     []chainjson.HexBytes `json:"tx_ids"`
+       BlockHash chainjson.HexBytes   `json:"block_hash"`
+}
+
+// GetMerkleBlockResp is resp struct for GetTxOutProof API
+type GetMerkleBlockResp struct {
+       BlockHeader  types.BlockHeader `json:"block_header"`
+       TxHashes     []*bc.Hash        `json:"tx_hashes"`
+       StatusHashes []*bc.Hash        `json:"status_hashes"`
+       Flags        []uint32          `json:"flags"`
+       MatchedTxIDs []*bc.Hash        `json:"matched_tx_ids"`
+}
+
+func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
+       blockReq := BlockReq{BlockHash: ins.BlockHash}
+       block, err := a.getBlockHelper(blockReq)
+       if err != nil {
+               return NewErrorResponse(err)
+       }
+
+       matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
+       var matchedTxIDs []*bc.Hash
+       for _, tx := range matchedTxs {
+               matchedTxIDs = append(matchedTxIDs, &tx.ID)
+       }
+
+       hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
+       flags := make([]uint32, len(compactFlags))
+       for i, flag := range compactFlags {
+               flags[i] = uint32(flag)
+       }
+
+       blockHash := block.Hash()
+       statuses, err := a.chain.GetTransactionStatus(&blockHash)
+       if err != nil {
+               return NewErrorResponse(err)
+       }
+
+       statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)
+
+       resp := &GetMerkleBlockResp{
+               BlockHeader:  block.BlockHeader,
+               TxHashes:     hashes,
+               StatusHashes: statusHashes,
+               Flags:        flags,
+               MatchedTxIDs: matchedTxIDs,
+       }
+       return NewSuccessResponse(resp)
+}
+
+func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
+       txIDSet := set.New()
+       for _, txID := range filterTxIDs {
+               hash := hexBytesToHash(txID)
+               txIDSet.Add(hash.String())
+       }
+
+       var matchedTxs []*types.Tx
+       for _, tx := range txs {
+               hashStr := tx.ID.String()
+               if txIDSet.Has(hashStr) {
+                       matchedTxs = append(matchedTxs, tx)
+               }
+       }
+       return matchedTxs
+}