github.com/turingchain2020/turingchain@v1.1.21/cmd/miner_accounts/accounts/show.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package accounts 6 7 import ( 8 "time" 9 10 l "github.com/turingchain2020/turingchain/common/log/log15" 11 12 "github.com/turingchain2020/turingchain/types" 13 14 //"encoding/json" 15 //"io/ioutil" 16 "fmt" 17 "strconv" 18 19 rpctypes "github.com/turingchain2020/turingchain/rpc/types" 20 ) 21 22 const secondsPerBlock = 5 23 const trcPreBlock = 5 24 const baseInterval = 3600 25 const maxInterval = 15 * 24 * 3600 26 const monitorTrcLowLimit = 3 * 1e7 * types.Coin 27 28 var log = l.New("module", "accounts") 29 30 //ShowMinerAccount 挖矿账户 31 type ShowMinerAccount struct { 32 DataDir string 33 Addrs []string 34 } 35 36 //Echo 打印 37 func (*ShowMinerAccount) Echo(in *string, out *interface{}) error { 38 if in == nil { 39 return types.ErrInvalidParam 40 } 41 *out = *in 42 return nil 43 } 44 45 //TimeAt time 46 type TimeAt struct { 47 // YYYY-mm-dd-HH 48 TimeAt string `json:"timeAt,omitempty"` 49 Addrs []string `json:"addrs,omitempty"` 50 } 51 52 //Get get 53 func (show *ShowMinerAccount) Get(in *TimeAt, out *interface{}) error { 54 if in == nil { 55 log.Error("show", "in", "nil") 56 return types.ErrInvalidParam 57 } 58 addrs := show.Addrs 59 if in.Addrs != nil && len(in.Addrs) > 0 { 60 addrs = in.Addrs 61 } 62 log.Info("show", "miners", addrs) 63 64 height, err := toBlockHeight(in.TimeAt) 65 if err != nil { 66 return err 67 } 68 log.Info("show", "header", height) 69 70 header, curAcc, err := cache.getBalance(addrs, "ticket", height) 71 if err != nil { 72 log.Error("show", "getBalance failed", err, "height", height) 73 return nil 74 } 75 76 totalTrc := int64(0) 77 for _, acc := range curAcc { 78 totalTrc += acc.Frozen 79 } 80 log.Info("show 1st balance", "utc", header.BlockTime, "total", totalTrc) 81 82 monitorInterval := calcMoniterInterval(totalTrc) 83 log.Info("show", "monitor Interval", monitorInterval) 84 85 lastHourHeader, lastAcc, err := cache.getBalance(addrs, "ticket", header.Height-monitorInterval) 86 if err != nil { 87 log.Error("show", "getBalance failed", err, "ts", header.BlockTime-monitorInterval) 88 return nil 89 } 90 fmt.Print(curAcc, lastAcc) 91 log.Info("show 2nd balance", "utc", *lastHourHeader) 92 93 miner := &MinerAccounts{} 94 miner.Seconds = header.BlockTime - lastHourHeader.BlockTime 95 miner.Blocks = header.Height - lastHourHeader.Height 96 miner.ExpectBlocks = miner.Seconds / secondsPerBlock 97 98 miner = calcIncrease(miner, curAcc, lastAcc, header) 99 *out = &miner 100 101 return nil 102 } 103 104 // 找指定时间最接近的区块, 默认是当前时间 105 func toBlockHeight(timeAt string) (int64, error) { 106 seconds := time.Now().Unix() 107 if len(timeAt) != 0 { 108 tm, err := time.Parse("2006-01-02-15", timeAt) 109 if err != nil { 110 log.Error("show", "in.TimeAt Parse", err) 111 return 0, types.ErrInvalidParam 112 } 113 seconds = tm.Unix() 114 } 115 log.Info("show", "utc-init", seconds) 116 117 realTs, header := cache.findBlock(seconds) 118 if realTs == 0 || header == nil { 119 log.Error("show", "findBlock", "nil") 120 return 0, types.ErrNotFound 121 } 122 return header.Height, nil 123 } 124 125 // 计算监控区块的范围 126 // 做对小额帐号限制,不然监控范围过大, 如9000个币需要138天 127 func calcMoniterInterval(totalTrc int64) int64 { 128 monitorInterval := int64(baseInterval) 129 if totalTrc < monitorTrcLowLimit && totalTrc > 0 { 130 monitorInterval = int64(float64(monitorTrcLowLimit) / float64(totalTrc) * float64(baseInterval)) 131 } 132 if monitorInterval > maxInterval { 133 monitorInterval = maxInterval 134 } 135 log.Info("show", "monitor Interval", monitorInterval) 136 return monitorInterval / secondsPerBlock 137 } 138 139 func calcIncrease(miner *MinerAccounts, acc1, acc2 []*rpctypes.Account, header *rpctypes.Header) *MinerAccounts { 140 type minerAt struct { 141 addr string 142 curAcc *rpctypes.Account 143 lastAcc *rpctypes.Account 144 } 145 miners := map[string]*minerAt{} 146 for _, a := range acc1 { 147 miners[a.Addr] = &minerAt{a.Addr, a, nil} 148 } 149 for _, a := range acc2 { 150 if _, ok := miners[a.Addr]; ok { 151 miners[a.Addr].lastAcc = a 152 } 153 } 154 155 totalIncrease := float64(0) 156 expectTotalIncrease := float64(0) 157 totalFrozen := float64(0) 158 for _, v := range miners { 159 if v.lastAcc != nil && v.curAcc != nil { 160 totalFrozen += float64(v.curAcc.Frozen) / float64(types.Coin) 161 } 162 } 163 ticketTotal := float64(30000 * 10000) 164 _, ticketAcc, err := cache.getBalance([]string{"16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"}, "coins", header.Height) 165 if err == nil && len(ticketAcc) == 1 { 166 ticketTotal = float64(ticketAcc[0].Balance+ticketAcc[0].Frozen) / float64(types.Coin) 167 } 168 for k, v := range miners { 169 if v.lastAcc != nil && v.curAcc != nil { 170 total := v.curAcc.Balance + v.curAcc.Frozen 171 increase := total - v.lastAcc.Balance - v.lastAcc.Frozen 172 expectIncrease := float64(miner.Blocks) * float64(trcPreBlock) * (float64(v.curAcc.Frozen) / float64(types.Coin)) / ticketTotal 173 174 m := &MinerAccount{ 175 Addr: k, 176 Total: strconv.FormatFloat(float64(total)/float64(types.Coin), 'f', 4, 64), 177 Increase: strconv.FormatFloat(float64(increase)/float64(types.Coin), 'f', 4, 64), 178 Frozen: strconv.FormatFloat(float64(v.curAcc.Frozen)/float64(types.Coin), 'f', 4, 64), 179 ExpectIncrease: strconv.FormatFloat(expectIncrease, 'f', 4, 64), 180 } 181 182 //if m.Addr == "1Lw6QLShKVbKM6QvMaCQwTh5Uhmy4644CG" { 183 // log.Info("acount", "Increase", m.Increase, "expectIncrease", m.ExpectIncrease) 184 // fmt.Println(os.Stderr, "Increase", m.Increase, "expectIncrease", m.ExpectIncrease) 185 //} 186 187 // 由于取不到挖矿的交易, 通过预期挖矿数, 推断间隔多少个区块能挖到。 188 // 由于挖矿分布的波动, 用双倍的预期能挖到区块的时间间隔来预警 189 expectBlocks := (expectIncrease / trcPreBlock) // 一个小时预期挖多少个块 190 expectMinerInterval := float64(miner.Seconds/secondsPerBlock) / expectBlocks // 预期多少秒可以挖一个块 191 moniterInterval := int64(2*expectMinerInterval) + 1 192 193 m.ExpectMinerBlocks = strconv.FormatFloat(expectBlocks, 'f', 4, 64) 194 _, acc, err := cache.getBalance([]string{m.Addr}, "ticket", header.Height-moniterInterval) 195 if err != nil || len(acc) == 0 { 196 m.MinerTrcDuring = "0.0000" 197 } else { 198 minerDelta := total - acc[0].Balance - acc[0].Frozen 199 m.MinerTrcDuring = strconv.FormatFloat(float64(minerDelta)/float64(types.Coin), 'f', 4, 64) 200 } 201 202 miner.MinerAccounts = append(miner.MinerAccounts, m) 203 totalIncrease += float64(increase) / float64(types.Coin) 204 expectTotalIncrease += expectIncrease 205 } 206 } 207 miner.TotalIncrease = strconv.FormatFloat(totalIncrease, 'f', 4, 64) 208 miner.ExpectTotalIncrease = strconv.FormatFloat(expectTotalIncrease, 'f', 4, 64) 209 210 return miner 211 212 }