github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/p2p/chain_response.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 p2p
    18  
    19  //import "fmt"
    20  //import "net"
    21  //import "sync"
    22  //import "time"
    23  
    24  //import "container/list"
    25  
    26  //import log "github.com/sirupsen/logrus"
    27  import "github.com/romana/rlog"
    28  import "github.com/vmihailenco/msgpack"
    29  
    30  import "github.com/deroproject/derosuite/crypto"
    31  import "github.com/deroproject/derosuite/config"
    32  
    33  //import "github.com/deroproject/derosuite/blockchain"
    34  
    35  // peer has responded with chain response and we must process the response
    36  func (connection *Connection) Handle_ChainResponse(buf []byte) {
    37  	var response Chain_Response_Struct
    38  
    39  	err := msgpack.Unmarshal(buf, &response)
    40  	if err != nil {
    41  		rlog.Warnf("Error while decoding incoming chain response err %s %s", err, connection.logid)
    42  		connection.Exit()
    43  		return
    44  	}
    45  
    46  	// check what we we queued is what what we got back
    47  	// for chain request we queue an empty hash
    48  
    49  	var expected Queued_Command
    50  
    51  	select {
    52  	case expected = <-connection.Objects:
    53  
    54  	default: // if nothing is on queue the peer sent us bogus request,
    55  		rlog.Warnf("Peer sent us a chain response, when we didnot request chain, Exiting, may be block the peer %s", connection.logid)
    56  		connection.Exit()
    57  	}
    58  
    59  	if expected.Command != V2_COMMAND_CHAIN_RESPONSE {
    60  		rlog.Warnf("We were waiting for a different object, but peer sent something else, Exiting, may be block the peer %s", connection.logid)
    61  		connection.Exit()
    62  	}
    63  
    64  	// we were expecting something else ban
    65  	if len(response.Block_list) < 1 {
    66  		rlog.Warnf("Malformed chain response  %s", err, connection.logid)
    67  		connection.Exit()
    68  		return
    69  	}
    70  
    71  	rlog.Tracef(2, "Peer wants to give chain from topoheight %d ", response.Start_height)
    72          _ = config.STABLE_LIMIT
    73  
    74  	// we do not need reorganisation if deviation is less than  or equak to 7 blocks
    75  	// only pop blocks if the system has somehow deviated more than 7 blocks
    76  	// if the deviation is less than 7 blocks, we internally reorganise everything
    77  	if chain.Load_TOPO_HEIGHT(nil)-response.Start_topoheight >= config.STABLE_LIMIT && connection.SyncNode {
    78  		// get our top block
    79  		rlog.Infof("rewinding status our %d  peer %d", chain.Load_TOPO_HEIGHT(nil), response.Start_topoheight)
    80  		pop_count := chain.Load_TOPO_HEIGHT(nil) - response.Start_topoheight
    81  		chain.Rewind_Chain(int(pop_count)) // pop as many blocks as necessary
    82  
    83  		// we should NOT queue blocks, instead we sent our chain request again
    84  		connection.Send_ChainRequest()
    85  		return
    86  
    87  	}
    88  
    89  	// response only 128 blocks at a time
    90  	max_blocks_to_queue := 128
    91  	// check whether the objects are in our db or not
    92  	// until we put in place a parallel object tracker, do it one at a time
    93  	for i := range response.Block_list {
    94  		if !chain.Block_Exists(nil, response.Block_list[i]) { // if block is not in our chain, add it to request list
    95  			//queue_block(request.Block_list[i])
    96  			if max_blocks_to_queue >= 0 {
    97  				max_blocks_to_queue--
    98  				connection.Send_ObjectRequest([]crypto.Hash{response.Block_list[i]}, []crypto.Hash{})
    99  				rlog.Tracef(2, "Queuing block %x height %d  %s", response.Block_list[i], response.Start_height+int64(i), connection.logid)
   100  			}
   101  		} else {
   102  			//logger.Warnf("We must have queued %x, but we skipped it at height %d",request.Block_list[i],request.Start_height+int64(i) )
   103  		}
   104  	}
   105  
   106  	// request alt-tips ( blocks if we are nearing the main tip )
   107  	if (response.Common.TopoHeight - chain.Load_TOPO_HEIGHT(nil)) <= 5 {
   108  		for i := range response.TopBlocks {
   109  			if !chain.Block_Exists(nil, response.TopBlocks[i]) {
   110  				connection.Send_ObjectRequest([]crypto.Hash{response.TopBlocks[i]}, []crypto.Hash{})
   111  				rlog.Tracef(2, "Queuing ALT-TIP  block %x %s", response.TopBlocks[i], connection.logid)
   112  
   113  			}
   114  
   115  		}
   116  	}
   117  }