github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/fees.go (about) 1 package usif 2 3 import ( 4 "bufio" 5 "encoding/gob" 6 "os" 7 "sync" 8 9 "github.com/piotrnar/gocoin/client/common" 10 "github.com/piotrnar/gocoin/lib/btc" 11 "github.com/piotrnar/gocoin/lib/chain" 12 ) 13 14 const ( 15 BLKFES_FILE_NAME = "blkfees.gob" 16 ) 17 18 var ( 19 BlockFeesMutex sync.Mutex 20 BlockFees map[uint32][][3]uint64 = make(map[uint32][][3]uint64) // [0]=Weight [1]-Fee [2]-Group 21 BlockFeesDirty bool // it true, clean up old data 22 ) 23 24 func ProcessBlockFees(height uint32, bl *btc.Block) { 25 if len(bl.Txs) < 2 { 26 return 27 } 28 29 txs := make(map[[32]byte]int, len(bl.Txs)) // group_id -> transaciton_idx 30 txs[bl.Txs[0].Hash.Hash] = 0 31 32 fees := make([][3]uint64, len(bl.Txs)-1) 33 34 for i := 1; i < len(bl.Txs); i++ { 35 txs[bl.Txs[i].Hash.Hash] = i 36 fees[i-1][0] = uint64(3*bl.Txs[i].NoWitSize + bl.Txs[i].Size) 37 fees[i-1][1] = uint64(bl.Txs[i].Fee) 38 fees[i-1][2] = uint64(i) 39 } 40 41 for i := 1; i < len(bl.Txs); i++ { 42 for _, inp := range bl.Txs[i].TxIn { 43 if paretidx, yes := txs[inp.Input.Hash]; yes { 44 if fees[paretidx-1][2] < fees[i-1][2] { // only update it for a lower index 45 fees[i-1][2] = fees[paretidx-1][2] 46 } 47 } 48 } 49 } 50 51 BlockFeesMutex.Lock() 52 BlockFees[height] = fees 53 BlockFeesDirty = true 54 BlockFeesMutex.Unlock() 55 } 56 57 func ExpireBlockFees() { 58 var height uint32 59 common.Last.Lock() 60 height = common.Last.Block.Height 61 common.Last.Unlock() 62 63 if height <= 144 { 64 return 65 } 66 height -= 144 67 68 BlockFeesMutex.Lock() 69 if BlockFeesDirty { 70 for k, _ := range BlockFees { 71 if k < height { 72 delete(BlockFees, k) 73 } 74 } 75 BlockFeesDirty = false 76 } 77 BlockFeesMutex.Unlock() 78 } 79 80 func SaveBlockFees() { 81 f, er := os.Create(common.GocoinHomeDir + BLKFES_FILE_NAME) 82 if er != nil { 83 println("SaveBlockFees:", er.Error()) 84 return 85 } 86 87 ExpireBlockFees() 88 buf := bufio.NewWriter(f) 89 er = gob.NewEncoder(buf).Encode(BlockFees) 90 91 if er != nil { 92 println("SaveBlockFees:", er.Error()) 93 } 94 95 buf.Flush() 96 f.Close() 97 98 } 99 100 func LoadBlockFees() { 101 f, er := os.Open(common.GocoinHomeDir + BLKFES_FILE_NAME) 102 if er != nil { 103 println("LoadBlockFees:", er.Error()) 104 return 105 } 106 107 buf := bufio.NewReader(f) 108 er = gob.NewDecoder(buf).Decode(&BlockFees) 109 if er != nil { 110 println("LoadBlockFees:", er.Error()) 111 } 112 113 f.Close() 114 } 115 116 var ( 117 AverageFeeMutex sync.Mutex 118 AverageFeeBytes uint64 119 AverageFeeTotal uint64 120 AverageFee_SPB float64 121 averageFeeLastBlock *chain.BlockTreeNode 122 averageFeeLastCount uint = 0xffffffff 123 ) 124 125 func GetAverageFee() float64 { 126 common.Last.Mutex.Lock() 127 end := common.Last.Block 128 common.Last.Mutex.Unlock() 129 130 common.LockCfg() 131 blocks := common.CFG.Stat.FeesBlks 132 common.UnlockCfg() 133 if blocks <= 0 { 134 blocks = 1 // at leats one block 135 } 136 137 AverageFeeMutex.Lock() 138 defer AverageFeeMutex.Unlock() 139 140 if end == averageFeeLastBlock && averageFeeLastCount == blocks { 141 return AverageFee_SPB // we've already calculated for this block 142 } 143 144 averageFeeLastBlock = end 145 averageFeeLastCount = blocks 146 147 AverageFeeBytes = 0 148 AverageFeeTotal = 0 149 150 for blocks > 0 { 151 bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) 152 if e != nil { 153 return 0 154 } 155 block, e := btc.NewBlockX(bl, end.BlockHash) 156 if e != nil { 157 return 0 158 } 159 160 rb, cbasetx := GetReceivedBlockX(block) 161 var fees_from_this_block int64 162 for o := range cbasetx.TxOut { 163 fees_from_this_block += int64(cbasetx.TxOut[o].Value) 164 } 165 fees_from_this_block -= int64(btc.GetBlockReward(end.Height)) 166 167 if fees_from_this_block > 0 { 168 AverageFeeTotal += uint64(fees_from_this_block) 169 } 170 171 AverageFeeBytes += uint64(rb.ThePaidVSize) 172 173 blocks-- 174 end = end.Parent 175 } 176 if AverageFeeBytes == 0 { 177 if AverageFeeTotal != 0 { 178 panic("Impossible that miner gest a fee with no transactions in the block") 179 } 180 AverageFee_SPB = 0 181 } else { 182 AverageFee_SPB = float64(AverageFeeTotal) / float64(AverageFeeBytes) 183 } 184 return AverageFee_SPB 185 }