github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/p2p/notification.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 "encoding/binary" 25 26 //import "container/list" 27 28 import "github.com/romana/rlog" 29 import "github.com/vmihailenco/msgpack" 30 31 import "github.com/deroproject/derosuite/crypto" 32 import "github.com/deroproject/derosuite/globals" 33 import "github.com/deroproject/derosuite/block" 34 import "github.com/deroproject/derosuite/errormsg" 35 import "github.com/deroproject/derosuite/transaction" 36 37 // Peer has notified us of a new transaction 38 func (connection *Connection) Handle_Notification_Transaction(buf []byte) { 39 var request Notify_New_Objects_Struct 40 41 err := msgpack.Unmarshal(buf, &request) 42 if err != nil { 43 rlog.Warnf("Error while decoding incoming TX notifcation err %s %s", err, globals.CTXString(connection.logger)) 44 connection.Exit() 45 } 46 47 var tx transaction.Transaction 48 err = tx.DeserializeHeader(request.Tx) 49 if err != nil { // we have a tx which could not be deserialized ban peer 50 rlog.Warnf("Error Incoming TX could not be deserialized err %s %s", err, globals.CTXString(connection.logger)) 51 connection.Exit() 52 return 53 } 54 55 // track transaction propagation 56 if first_time, ok := tx_propagation_map.Load(tx.GetHash()); ok { 57 // block already has a reference, take the time and observe the value 58 diff := time.Now().Sub(first_time.(time.Time)).Round(time.Millisecond) 59 transaction_propagation.Observe(float64(diff / 1000000)) 60 } else { 61 tx_propagation_map.Store(tx.GetHash(), time.Now()) // if this is the first time, store the tx time 62 } 63 64 // try adding tx to pool 65 success_pool := chain.Add_TX_To_Pool(&tx) 66 67 // add tx to cache of the peer who sent us this tx 68 connection.TXpool_cache_lock.Lock() 69 if success_pool && globals.Arguments["--lowcpuram"].(bool) == false && connection.TXpool_cache != nil { 70 71 txhash := tx.GetHash() 72 connection.TXpool_cache[binary.LittleEndian.Uint64(txhash[:])] = uint32(time.Now().Unix()) 73 74 //logger.Debugf("Adding %s to cache", tx.GetHash()) 75 } 76 connection.TXpool_cache_lock.Unlock() 77 78 // broadcasting of tx is controlled by mempool 79 80 } 81 82 // Peer has notified us of a new block 83 func (connection *Connection) Handle_Notification_Block(buf []byte) { 84 var request Notify_New_Objects_Struct 85 86 err := msgpack.Unmarshal(buf, &request) 87 if err != nil { 88 rlog.Warnf("Error while decoding incoming Block notifcation request err %s %s", err, globals.CTXString(connection.logger)) 89 connection.Exit() 90 } 91 92 var cbl block.Complete_Block // parse incoming block and deserialize it 93 var bl block.Block 94 // lets deserialize block first and see whether it is the requested object 95 cbl.Bl = &bl 96 err = bl.Deserialize(request.CBlock.Block) 97 if err != nil { // we have a block which could not be deserialized ban peer 98 rlog.Warnf("Error Incoming block could not be deserilised err %s %s", err, globals.CTXString(connection.logger)) 99 connection.Exit() 100 return 101 } 102 103 blid := bl.GetHash() 104 105 rlog.Infof("Incoming block Notification hash %s %s ", blid, globals.CTXString(connection.logger)) 106 107 // track block propagation 108 if first_time, ok := block_propagation_map.Load(blid); ok { 109 // block already has a reference, take the time and observe the value 110 diff := time.Now().Sub(first_time.(time.Time)).Round(time.Millisecond) 111 block_propagation.Observe(float64(diff / 1000000)) 112 } else { 113 block_propagation_map.Store(blid, time.Now()) // if this is the first time, store the block 114 } 115 116 // object is already is in our chain, we need not relay it 117 if chain.Block_Exists(nil, blid) { 118 return 119 } 120 121 // the block is not in our db, parse entire block, complete the txs and try to add it 122 if len(bl.Tx_hashes) == len(request.CBlock.Txs) { 123 connection.logger.Debugf("Received a complete block %s with %d transactions",blid, len(bl.Tx_hashes)) 124 for j := range request.CBlock.Txs { 125 var tx transaction.Transaction 126 err = tx.DeserializeHeader(request.CBlock.Txs[j]) 127 if err != nil { // we have a tx which could not be deserialized ban peer 128 rlog.Warnf("Error Incoming TX could not be deserialized err %s %s", err, globals.CTXString(connection.logger)) 129 connection.Exit() 130 return 131 } 132 cbl.Txs = append(cbl.Txs, &tx) 133 } 134 } else { // the block is NOT complete, we consider it as an ultra compact block 135 136 connection.logger.Debugf("Received an ultra compact block %s, total %d contains %d skipped %d transactions", blid,len(bl.Tx_hashes), len(request.CBlock.Txs), len(bl.Tx_hashes)-len(request.CBlock.Txs)) 137 for j := range request.CBlock.Txs { 138 var tx transaction.Transaction 139 err = tx.DeserializeHeader(request.CBlock.Txs[j]) 140 if err != nil { // we have a tx which could not be deserialized ban peer 141 rlog.Warnf("Error Incoming TX could not be deserialized err %s %s", err, globals.CTXString(connection.logger)) 142 connection.Exit() 143 return 144 } 145 chain.Add_TX_To_Pool(&tx) // add tx to pool 146 } 147 148 // lets build a complete block ( tx from db or mempool ) 149 for i := range bl.Tx_hashes { 150 if tx, err := chain.Load_TX_FROM_ID(nil, bl.Tx_hashes[i]); err == nil { 151 cbl.Txs = append(cbl.Txs, tx) // tx is from disk 152 } else { 153 tx := chain.Mempool.Mempool_Get_TX(bl.Tx_hashes[i]) // tx is from mempool 154 if tx != nil { 155 cbl.Txs = append(cbl.Txs, tx) 156 } else { 157 // the tx mentioned in ultra compact block could not be found 158 // request a full block 159 160 connection.Send_ObjectRequest([]crypto.Hash{blid}, []crypto.Hash{}) 161 logger.Debugf("Ultra compact block %s missing TX %s, requesting full block", blid, bl.Tx_hashes[i]) 162 return 163 } 164 } 165 166 } 167 } 168 169 // check if we can add ourselves to chain 170 if err, ok := chain.Add_Complete_Block(&cbl); ok { // if block addition was successfil 171 // notify all peers 172 Broadcast_Block(&cbl, connection.Peer_ID) // do not send back to the original peer 173 174 } else { // ban the peer for sometime 175 if err == errormsg.ErrInvalidPoW { 176 connection.logger.Warnf("This peer should be banned and terminated") 177 connection.Exit() 178 } 179 } 180 181 }