github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/blockchain/rpcserver/gettransactions.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package rpcserver
    18  
    19  import "net/http"
    20  import "encoding/hex"
    21  import "encoding/json"
    22  
    23  import "github.com/romana/rlog"
    24  import "github.com/vmihailenco/msgpack"
    25  
    26  import "github.com/deroproject/derosuite/crypto"
    27  import "github.com/deroproject/derosuite/globals"
    28  import "github.com/deroproject/derosuite/structures"
    29  import "github.com/deroproject/derosuite/transaction"
    30  
    31  // we definitely need to clear up the MESS that has been created by the MONERO project
    32  // half of their APIs are json rpc and half are http
    33  // for compatibility reasons, we are implementing theirs ( however we are also providin a json rpc implementation)
    34  // we should DISCARD the http
    35  
    36  //  NOTE: we have currently not implemented the decode as json parameter
    37  //  it is however on the pending list
    38  
    39  type GetTransaction_Handler struct{}
    40  
    41  func gettransactions(rw http.ResponseWriter, req *http.Request) {
    42  	decoder := json.NewDecoder(req.Body)
    43  	var p structures.GetTransaction_Params
    44  	err := decoder.Decode(&p)
    45  	if err != nil {
    46  		panic(err)
    47  	}
    48  	defer req.Body.Close()
    49  
    50  	result := gettransactions_fill(p)
    51  	//logger.Debugf("Request %+v", p)
    52  
    53  	encoder := json.NewEncoder(rw)
    54  	encoder.Encode(result)
    55  }
    56  
    57  // fill up the response
    58  func gettransactions_fill(p structures.GetTransaction_Params) (result structures.GetTransaction_Result) {
    59  
    60  	for i := 0; i < len(p.Tx_Hashes); i++ {
    61  
    62  		hash := crypto.HashHexToHash(p.Tx_Hashes[i])
    63  
    64  		{ // check if tx is from  blockchain
    65  			tx, err := chain.Load_TX_FROM_ID(nil, hash)
    66  			if err == nil {
    67  				var related structures.Tx_Related_Info
    68  
    69  				// check whether tx is orphan
    70  
    71  				/*if chain.Is_TX_Orphan(hash) {
    72  					result.Txs_as_hex = append(result.Txs_as_hex, "") // given empty data
    73  					result.Txs = append(result.Txs, related)          // should we have an orphan tx marker
    74  				} else */{
    75  
    76  					// topo height at which it was mined
    77  					related.Block_Height = int64(chain.Load_TX_Height(nil, hash))
    78  
    79  					if tx.IsCoinbase() { // fill reward but only for coinbase
    80  						blhash, err := chain.Load_Block_Topological_order_at_index(nil, int64(related.Block_Height))
    81  						if err == nil { // if err return err
    82  							related.Reward = chain.Load_Block_Total_Reward(nil, blhash)
    83  						}
    84  					}
    85  
    86  					if !tx.IsCoinbase() {
    87  						// expand ring members and provide information
    88  						related.Ring = make([][]globals.TX_Output_Data, len(tx.Vin), len(tx.Vin))
    89  						for i := 0; i < len(tx.Vin); i++ {
    90  							related.Ring[i] = make([]globals.TX_Output_Data, len(tx.Vin[i].(transaction.Txin_to_key).Key_offsets), len(tx.Vin[i].(transaction.Txin_to_key).Key_offsets))
    91  							ring_member := uint64(0)
    92  							for j := 0; j < len(tx.Vin[i].(transaction.Txin_to_key).Key_offsets); j++ {
    93  								ring_member += tx.Vin[i].(transaction.Txin_to_key).Key_offsets[j]
    94  
    95  								var ring_data globals.TX_Output_Data
    96  								data_bytes, err := chain.Read_output_index(nil, ring_member)
    97  
    98  								err = msgpack.Unmarshal(data_bytes, &ring_data)
    99  								if err != nil {
   100  									rlog.Warnf("RPC err while unmarshallin output index data index = %d  data_len %d err %s", ring_member, len(data_bytes), err)
   101  								}
   102  								related.Ring[i][j] = ring_data
   103  							}
   104  						}
   105  						err = nil
   106  					}
   107  
   108  					// also fill where the tx is found and in which block is valid and in which it is invalid
   109  
   110  					blocks := chain.Load_TX_blocks(nil, hash)
   111  
   112  					for i := range blocks {
   113  
   114  						//  logger.Infof("%s tx valid %+v",blocks[i],chain.IS_TX_Valid(nil,blocks[i],hash))
   115  						//  logger.Infof("%s block topo %+v", blocks[i], chain.Is_Block_Topological_order(nil,blocks[i]))
   116  						if chain.IS_TX_Valid(nil, blocks[i], hash) && chain.Is_Block_Topological_order(nil, blocks[i]) {
   117  							related.ValidBlock = blocks[i].String()
   118  						} else {
   119  
   120  							related.InvalidBlock = append(related.InvalidBlock, blocks[i].String())
   121  						}
   122  
   123  					}
   124  
   125  					index := chain.Find_TX_Output_Index(hash)
   126  					// index := uint64(0)
   127  
   128  					//   logger.Infof("TX hash %s height %d",hash, related.Block_Height)
   129  					for i := 0; i < len(tx.Vout); i++ {
   130  						if index >= 0 {
   131  							related.Output_Indices = append(related.Output_Indices, uint64(index+int64(i)))
   132  						} else {
   133  							related.Output_Indices = append(related.Output_Indices, 0)
   134  						}
   135  					}
   136  					result.Txs_as_hex = append(result.Txs_as_hex, hex.EncodeToString(tx.Serialize()))
   137  					result.Txs = append(result.Txs, related)
   138  				}
   139  				continue
   140  			}
   141  		}
   142  		// check whether we can get the tx from the pool
   143  		{
   144  			tx := chain.Mempool.Mempool_Get_TX(hash)
   145  			if tx != nil { // found the tx in the mempool
   146  				result.Txs_as_hex = append(result.Txs_as_hex, hex.EncodeToString(tx.Serialize()))
   147  
   148  				var related structures.Tx_Related_Info
   149  
   150  				related.Block_Height = -1 // not mined
   151  				related.In_pool = true
   152  
   153  				for i := 0; i < len(tx.Vout); i++ {
   154  					related.Output_Indices = append(related.Output_Indices, 0) // till the tx is mined we do not get indices
   155  				}
   156  
   157  				result.Txs = append(result.Txs, related)
   158  
   159  				continue // no more processing required
   160  			}
   161  		}
   162  
   163  		{ // we could not fetch the tx, return an empty string
   164  			result.Txs_as_hex = append(result.Txs_as_hex, "")
   165  			result.Status = "TX NOT FOUND"
   166  			return
   167  		}
   168  
   169  	}
   170  	result.Status = "OK"
   171  	return
   172  }