github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/p2p/chain_request.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/atomic" 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/globals" 32 33 //import "github.com/deroproject/derosuite/blockchain" 34 35 // we are sending a chain request, build a packet with our chain data 36 // so as other side can respond with chain response 37 func (connection *Connection) Send_ChainRequest() { 38 var request Chain_Request_Struct 39 40 fill_common(&request.Common) // fill common info 41 request.Command = V2_COMMAND_CHAIN_REQUEST 42 43 // send our blocks, first 10 blocks directly, then decreasing in powers of 2 44 start_point := chain.Load_TOPO_HEIGHT(nil) 45 for i := int64(0); i < start_point; { 46 47 blid, _ := chain.Load_Block_Topological_order_at_index(nil, start_point-i) 48 request.Block_list = append(request.Block_list, blid) 49 request.TopoHeights = append(request.TopoHeights, start_point-i) 50 rlog.Tracef(3, "Adding block to chain request h %d %s", i, blid) 51 switch { 52 case len(request.Block_list) < 10: 53 i++ 54 default: 55 i = i * 2 56 } 57 } 58 59 // add genesis block at the end 60 request.Block_list = append(request.Block_list, globals.Config.Genesis_Block_Hash) 61 request.TopoHeights = append(request.TopoHeights, 0) 62 63 // serialize and send 64 serialized, err := msgpack.Marshal(&request) 65 if err != nil { 66 panic(err) 67 } 68 69 // queue command 70 command := Queued_Command{Command: V2_COMMAND_CHAIN_RESPONSE} 71 connection.Objects <- command 72 73 atomic.StoreInt64(&connection.LastObjectRequestTime, time.Now().Unix()) 74 //connection.Lock() 75 //connection.Command_queue.PushBack(command) // queue command 76 connection.Send_Message_prelocked(serialized) 77 //connection.Unlock() 78 79 rlog.Tracef(2, "chain request sent successfully %s", globals.CTXString(connection.logger)) 80 } 81 82 // peer has requested chain 83 func (connection *Connection) Handle_ChainRequest(buf []byte) { 84 var request Chain_Request_Struct 85 var response Chain_Response_Struct 86 87 err := msgpack.Unmarshal(buf, &request) 88 if err != nil { 89 rlog.Warnf("Error while decoding incoming chain request err %s %s", err, globals.CTXString(connection.logger)) 90 connection.Exit() 91 return 92 } 93 94 // 95 if len(request.Block_list) < 1 { // malformed request ban peer 96 rlog.Warnf("malformed chain request received, banning peer %+v %s", request, globals.CTXString(connection.logger)) 97 connection.Exit() 98 99 return 100 } 101 102 if len(request.Block_list) != len(request.TopoHeights) { 103 rlog.Warnf("Peer chain request has %d block %d topos, therefore invalid", len(request.Block_list), len(request.TopoHeights)) 104 connection.Exit() 105 return 106 } 107 108 if request.Block_list[len(request.Block_list)-1] != globals.Config.Genesis_Block_Hash { 109 rlog.Warnf("Peer's genesis block is different from our, so disconnect Actual %s Expected %s", request.Block_list[len(request.Block_list)-1], globals.Config.Genesis_Block_Hash) 110 connection.Exit() 111 return 112 } 113 114 rlog.Tracef(2, "chain request received %s", globals.CTXString(connection.logger)) 115 116 // we must give user our version of the chain 117 start_height := int64(0) 118 start_topoheight := int64(0) 119 120 for i := 0; i < len(request.Block_list); i++ { // find the common point in our chain ( the block is NOT orphan) 121 122 //connection.logger.Infof("Checking block for chain detection %d %s", i, request.Block_list[i]) 123 124 if chain.Block_Exists(nil, request.Block_list[i]) && chain.Is_Block_Topological_order(nil, request.Block_list[i]) && 125 request.TopoHeights[i] == chain.Load_Block_Topological_order(nil, request.Block_list[i]) { 126 start_height = chain.Load_Height_for_BL_ID(nil, request.Block_list[i]) 127 start_topoheight = chain.Load_Block_Topological_order(nil, request.Block_list[i]) 128 rlog.Tracef(2, "Found common point in chain at hash %x height %d topoheight %d\n", request.Block_list[i], start_height, start_topoheight) 129 break 130 } 131 } 132 133 // we can serve maximum of 512 BLID = 16K KB 134 const MAX_BLOCKS = 512 135 136 // if everything is OK, we must respond with chain response 137 //connection.Send_TimedSync(false) // send it as response 138 139 for i := start_topoheight; i <= chain.Load_TOPO_HEIGHT(nil) && len(response.Block_list) <= MAX_BLOCKS; i++ { 140 hash, _ := chain.Load_Block_Topological_order_at_index(nil, i) 141 response.Block_list = append(response.Block_list, [32]byte(hash)) 142 } 143 144 // we must also fill blocks for the last top 10 heights, so client can sync faster to alt tips 145 top_height := chain.Get_Height() 146 counter := 0 147 for ; top_height > 0 && counter <= 10; top_height-- { 148 blocks := chain.Get_Blocks_At_Height(nil, top_height) 149 for i := range blocks { 150 response.TopBlocks = append([][32]byte{blocks[i]}, response.TopBlocks...) // blocks are ordered height wise 151 } 152 counter++ 153 } 154 155 response.Start_height = start_height 156 response.Start_topoheight = start_topoheight 157 fill_common(&response.Common) // fill common info 158 response.Command = V2_COMMAND_CHAIN_RESPONSE 159 160 // serialize and send 161 serialized, err := msgpack.Marshal(&response) 162 if err != nil { 163 panic(err) 164 } 165 166 // we should add to queue that we are waiting for chain response 167 rlog.Tracef(2, "chain response sent due to incoming chain request sent len response = %d %s", len(serialized), globals.CTXString(connection.logger)) 168 connection.Send_Message(serialized) 169 }