github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/network/txpool_mine.go (about) 1 package network 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/piotrnar/gocoin/client/common" 9 "github.com/piotrnar/gocoin/lib/btc" 10 ) 11 12 func (rec *OneTxToSend) IIdx(key uint64) int { 13 for i, o := range rec.TxIn { 14 if o.Input.UIdx() == key { 15 return i 16 } 17 } 18 return -1 19 } 20 21 // UnMarkChildrenForMem clears the MemInput flag of all the children (used when a tx is mined). 22 func (tx *OneTxToSend) UnMarkChildrenForMem() { 23 // Go through all the tx's outputs and unmark MemInputs in txs that have been spending it 24 var po btc.TxPrevOut 25 po.Hash = tx.Hash.Hash 26 for po.Vout = 0; po.Vout < uint32(len(tx.TxOut)); po.Vout++ { 27 uidx := po.UIdx() 28 if val, ok := SpentOutputs[uidx]; ok { 29 if rec, _ := TransactionsToSend[val]; rec != nil { 30 if rec.MemInputs == nil { 31 common.CountSafe("TxMinedMeminER1") 32 fmt.Println("WTF?", po.String(), "just mined in", rec.Hash.String(), "- not marked as mem") 33 continue 34 } 35 idx := rec.IIdx(uidx) 36 if idx < 0 { 37 common.CountSafe("TxMinedMeminER2") 38 fmt.Println("WTF?", po.String(), " just mined. Was in SpentOutputs & mempool, but DUPA") 39 continue 40 } 41 rec.MemInputs[idx] = false 42 rec.MemInputCnt-- 43 common.CountSafe("TxMinedMeminOut") 44 if rec.MemInputCnt == 0 { 45 common.CountSafe("TxMinedMeminTx") 46 rec.MemInputs = nil 47 } 48 } else { 49 common.CountSafe("TxMinedMeminERR") 50 fmt.Println("WTF?", po.String(), " in SpentOutputs, but not in mempool") 51 } 52 } 53 } 54 } 55 56 // tx_mined is called for each tx mined in a new block. 57 func tx_mined(tx *btc.Tx) (wtg *OneWaitingList) { 58 h := tx.Hash 59 if rec, ok := TransactionsToSend[h.BIdx()]; ok { 60 common.CountSafe("TxMinedToSend") 61 rec.UnMarkChildrenForMem() 62 rec.Delete(false, 0) 63 } 64 if mr, ok := TransactionsRejected[h.BIdx()]; ok { 65 if mr.Tx != nil { 66 common.CountSafe(fmt.Sprint("TxMinedROK-", mr.Reason)) 67 } else { 68 common.CountSafe(fmt.Sprint("TxMinedRNO-", mr.Reason)) 69 } 70 deleteRejected(h.BIdx()) 71 } 72 if _, ok := TransactionsPending[h.BIdx()]; ok { 73 common.CountSafe("TxMinedPending") 74 delete(TransactionsPending, h.BIdx()) 75 } 76 77 // Go through all the inputs and make sure we are not leaving them in SpentOutputs 78 for i := range tx.TxIn { 79 idx := tx.TxIn[i].Input.UIdx() 80 if val, ok := SpentOutputs[idx]; ok { 81 if rec, _ := TransactionsToSend[val]; rec != nil { 82 // if we got here, the txs has been Malleabled 83 if rec.Local { 84 common.CountSafe("TxMinedMalleabled") 85 fmt.Println("Input from own ", rec.Tx.Hash.String(), " mined in ", tx.Hash.String()) 86 } else { 87 common.CountSafe("TxMinedOtherSpend") 88 } 89 rec.Delete(true, 0) 90 } else { 91 common.CountSafe("TxMinedSpentERROR") 92 fmt.Println("WTF? Input from ", rec.Tx.Hash.String(), " in mem-spent, but tx not in the mem-pool") 93 } 94 delete(SpentOutputs, idx) 95 } 96 } 97 98 wtg = WaitingForInputs[h.BIdx()] 99 return 100 } 101 102 // BlockMined removes all the block's tx from the mempool. 103 func BlockMined(bl *btc.Block) { 104 wtgs := make([]*OneWaitingList, len(bl.Txs)-1) 105 var wtg_cnt int 106 TxMutex.Lock() 107 for i := 1; i < len(bl.Txs); i++ { 108 wtg := tx_mined(bl.Txs[i]) 109 if wtg != nil { 110 wtgs[wtg_cnt] = wtg 111 wtg_cnt++ 112 } 113 } 114 TxMutex.Unlock() 115 116 // Try to redo waiting txs 117 if wtg_cnt > 0 { 118 common.CountSafeAdd("TxMinedGotInput", uint64(wtg_cnt)) 119 for _, wtg := range wtgs[:wtg_cnt] { 120 RetryWaitingForInput(wtg) 121 } 122 } 123 124 expireTxsNow = true 125 } 126 127 // MarkChildrenForMem sets the MemInput flag of all the children (used when a tx is mined). 128 func MarkChildrenForMem(tx *btc.Tx) { 129 // Go through all the tx's outputs and mark MemInputs in txs that have been spending it 130 var po btc.TxPrevOut 131 po.Hash = tx.Hash.Hash 132 for po.Vout = 0; po.Vout < uint32(len(tx.TxOut)); po.Vout++ { 133 uidx := po.UIdx() 134 if val, ok := SpentOutputs[uidx]; ok { 135 if rec, _ := TransactionsToSend[val]; rec != nil { 136 if rec.MemInputs == nil { 137 rec.MemInputs = make([]bool, len(rec.TxIn)) 138 } 139 idx := rec.IIdx(uidx) 140 rec.MemInputs[idx] = true 141 rec.MemInputCnt++ 142 common.CountSafe("TxPutBackMemIn") 143 } else { 144 common.CountSafe("TxPutBackMeminERR") 145 fmt.Println("MarkChildrenForMem WTF?", po.String(), " in SpentOutputs, but not in mempool") 146 } 147 } 148 } 149 } 150 151 func BlockUndone(bl *btc.Block) { 152 var cnt int 153 for _, tx := range bl.Txs[1:] { 154 // put it back into the mempool 155 ntx := &TxRcvd{Tx: tx, trusted: true} 156 157 if NeedThisTx(&ntx.Hash, nil) { 158 if HandleNetTx(ntx, true) { 159 common.CountSafe("TxPutBackOK") 160 cnt++ 161 } else { 162 common.CountSafe("TxPutBackFail") 163 } 164 } else { 165 common.CountSafe("TxPutBackNoNeed") 166 } 167 168 // TODO: make sure to set MemInputs of ones using it back to true (issue #58) 169 MarkChildrenForMem(tx) 170 } 171 if cnt != len(bl.Txs)-1 { 172 println("WARNING: network.BlockUndone("+bl.Hash.String()+") - ", cnt, "of", len(bl.Txs)-1, "txs put back") 173 } 174 } 175 176 func (c *OneConnection) SendGetMP() error { 177 if len(c.GetMP) == 0 { 178 // TODO: remove it at some point (should not be happening) 179 println("ERROR: SendGetMP() called with no GetMP lock") 180 return nil 181 } 182 b := new(bytes.Buffer) 183 TxMutex.Lock() 184 if TransactionsToSendSize > common.MaxMempoolSize()>>1 { 185 // Don't send "getmp" messages if we have more than 50% of MaxMempoolSize() used 186 //fmt.Println("Mempool more than half full - not sending getmp message -", TransactionsToSendSize>>20, "/", common.MaxMempoolSize()>>20) 187 TxMutex.Unlock() 188 c.cntInc("GetMPHold") 189 return errors.New("SendGetMP: Mempool more than half full") 190 } 191 tcnt := len(TransactionsToSend) + len(TransactionsRejected) 192 if tcnt > MAX_GETMP_TXS { 193 fmt.Println("Too many transactions in the current pool", tcnt, "/", MAX_GETMP_TXS) 194 tcnt = MAX_GETMP_TXS 195 } 196 btc.WriteVlen(b, uint64(tcnt)) 197 var cnt int 198 for k := range TransactionsToSend { 199 b.Write(k[:]) 200 cnt++ 201 if cnt == MAX_GETMP_TXS { 202 break 203 } 204 } 205 for k := range TransactionsRejected { 206 b.Write(k[:]) 207 cnt++ 208 if cnt == MAX_GETMP_TXS { 209 break 210 } 211 } 212 TxMutex.Unlock() 213 return c.SendRawMsg("getmp", b.Bytes()) 214 } 215 216 func (c *OneConnection) ProcessGetMP(pl []byte) { 217 br := bytes.NewBuffer(pl) 218 219 cnt, er := btc.ReadVLen(br) 220 if er != nil { 221 println("getmp message does not have the length field") 222 c.DoS("GetMPError1") 223 return 224 } 225 226 has_this_one := make(map[BIDX]bool, cnt) 227 for i := 0; i < int(cnt); i++ { 228 var idx BIDX 229 if n, _ := br.Read(idx[:]); n != len(idx) { 230 println("getmp message too short") 231 c.DoS("GetMPError2") 232 return 233 } 234 has_this_one[idx] = true 235 } 236 237 var data_sent_so_far int 238 var redo [1]byte 239 240 TxMutex.Lock() 241 for k, v := range TransactionsToSend { 242 c.Mutex.Lock() 243 bts := c.BytesToSent() 244 c.Mutex.Unlock() 245 if bts > SendBufSize/4 { 246 redo[0] = 1 247 break 248 } 249 if !has_this_one[k] { 250 c.SendRawMsg("tx", v.Raw) 251 data_sent_so_far += 24 + len(v.Raw) 252 } 253 } 254 TxMutex.Unlock() 255 256 c.SendRawMsg("getmpdone", redo[:]) 257 }