// utility.go package utility import ( "encoding/binary" "encoding/hex" "encoding/json" "fmt" "io/ioutil" "strconv" "bytes" "log" "math" "math/big" "os" "os/exec" "strings" "time" "github.com/zeromq/goczmq" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) const BITCOIND_ZMQ_HASHBLOCK string = "hashblock" type CoinConfig struct { Coin string `json:"coin"` } type ZmqConfig struct { Pub string `json:"pub"` Sub string `json:"sub"` } type RedisConfig struct { Addr string `json:"addr"` Password string `json:"password"` DB int `json:"db"` } type LogRotateConfig struct { MaxSize int `json:"maxsize"` MaxBackups int `json:"maxbackups"` MaxAge int `json:"maxage"` Compress bool `json:"compress"` } func InitLogg(zaplog *zap.Config, rotate *LogRotateConfig, coinname string, modulename string) (*zap.Logger, *lumberjack.Logger, error) { os.MkdirAll("logs/"+coinname, os.ModePerm) logfile := "./logs/" + coinname + "/" + modulename + ".log" logRotate := &lumberjack.Logger{ Filename: logfile, MaxSize: rotate.MaxSize, MaxBackups: rotate.MaxBackups, MaxAge: rotate.MaxAge, Compress: rotate.Compress, } zaplog.EncoderConfig = zap.NewProductionEncoderConfig() zaplog.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder opath := []string{"", ""} opath[0] = zaplog.OutputPaths[0] opath[1] = logfile zaplog.OutputPaths = opath l, err := zaplog.Build( zap.WrapCore(func(core zapcore.Core) zapcore.Core { return zapcore.NewCore( zapcore.NewJSONEncoder(zaplog.EncoderConfig), zapcore.AddSync(logRotate), zaplog.Level, ) }), ) if err != nil { log.Fatal("[gbt]", err.Error()) return nil, nil, err } return l, logRotate, nil } func GetCoin(config_file string) string { var config CoinConfig data, err := ioutil.ReadFile(config_file) if err != nil { panic(err.Error()) } if err = json.Unmarshal(data, &config); err != nil { panic(err.Error()) } return config.Coin } func confirmXPubSubscriptions(pub *goczmq.Channeler, count int) { for i := 0; i < count; i++ { select { case <-pub.RecvChan: case <-time.After(time.Second * 2): log.Println("confirmXPubSubscriptions, timeout") } } } func InitZmqPub(pub_host string) *goczmq.Sock { pub_ch, err := goczmq.NewXPub(pub_host) if err != nil { log.Fatal("[server]", zap.String("NewXPub", "zmq pub create failed!")) } //pub_ch.SetMaxmsgsize(1024 * 1024 * 8) return pub_ch } func InitZmqSub(sub_to string, topic string) *goczmq.Sock { sub_ch, err := goczmq.NewSub(sub_to, topic) if err != nil { log.Fatal("[server]", zap.String("NewSub", "zmq sub connect failed!")) } //sub_ch.SetMaxmsgsize(1024 * 1024 * 8) return sub_ch } func InitZmqPush(sub_to string) *goczmq.Sock { push_ch, err := goczmq.NewPush(sub_to) if err != nil { log.Fatal("[server]", zap.String("NewPushChanneler", "zmq push connect failed!")) } //push_ch.Bind(sub_to) //push_ch.SetMaxmsgsize(1024 * 1024 * 8) return push_ch } func InitZmqPull(sub_to string) *goczmq.Sock { pull_ch, err := goczmq.NewPull(sub_to) if err != nil { log.Fatal("[server]", zap.String("InitZmqPull", "zmq pull connect failed! "+err.Error())) } //pull_ch.SetMaxmsgsize(1024 * 1024 * 8) return pull_ch } func Int32ToString(n uint32) string { buf := [11]byte{} pos := len(buf) i := int64(n) signed := i < 0 if signed { i = -i } for { pos-- buf[pos], i = '0'+byte(i%10), i/10 if i == 0 { if signed { pos-- buf[pos] = '-' } return string(buf[pos:]) } } } func ByteToUint32(bytes []byte) uint32 { return binary.LittleEndian.Uint32(bytes) } func Reverse_string(instr string) string { var outstr string = "" for i := 0; i < len(instr)/2; i++ { outstr = outstr + instr[len(instr)-i*2-2:len(instr)-i*2] } return outstr } // CompactToBig converts a compact representation of a whole number N to an // unsigned 32-bit number. The representation is similar to IEEE754 floating // point numbers. // // Like IEEE754 floating point, there are three basic components: the sign, // the exponent, and the mantissa. They are broken out as follows: // // - the most significant 8 bits represent the unsigned base 256 exponent // - bit 23 (the 24th bit) represents the sign bit // - the least significant 23 bits represent the mantissa // // ------------------------------------------------- // | Exponent | Sign | Mantissa | // ------------------------------------------------- // | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | // ------------------------------------------------- // // The formula to calculate N is: // // N = (-1^sign) * mantissa * 256^(exponent-3) // // This compact form is only used in bitcoin to encode unsigned 256-bit numbers // which represent difficulty targets, thus there really is not a need for a // sign bit, but it is implemented here to stay consistent with bitcoind. func CompactToBig(compact uint32) *big.Int { // Extract the mantissa, sign bit, and exponent. mantissa := compact & 0x007fffff isNegative := compact&0x00800000 != 0 exponent := uint(compact >> 24) // Since the base for the exponent is 256, the exponent can be treated // as the number of bytes to represent the full 256-bit number. So, // treat the exponent as the number of bytes and shift the mantissa // right or left accordingly. This is equivalent to: // N = mantissa * 256^(exponent-3) var bn *big.Int if exponent <= 3 { mantissa >>= 8 * (3 - exponent) bn = big.NewInt(int64(mantissa)) } else { bn = big.NewInt(int64(mantissa)) bn.Lsh(bn, 8*(exponent-3)) } // Make it negative if the sign bit is set. if isNegative { bn = bn.Neg(bn) } return bn } const truediffone float64 = 26959535291011309493156476344723991336010898738574164086137773096960.0 const bits192 float64 = 6277101735386680763835789423207666416102355444464034512896.0 const bits128 float64 = 340282366920938463463374607431768211456.0 const bits64 float64 = 18446744073709551616.0 func target2float(target []byte) float64 { var b64 float64 = float64(binary.LittleEndian.Uint64(target[24:32])) * bits192 b64 += (float64(binary.LittleEndian.Uint64(target[16:24])) * bits128) b64 += (float64(binary.LittleEndian.Uint64(target[8:16])) * bits64) b64 += (float64(binary.LittleEndian.Uint64(target[0:8]))) return b64 } // convert target to difficulty func Target2Diff(target []byte) float64 { //var f64 float64 = truediffone max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) // 2 ^ 256 -1 //max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) maxf, _ := new(big.Float).SetString(max.String()) f64, _ := maxf.Float64() var fcut64 float64 = target2float(target) //log.Println("diff", f64, fcut64, f64/fcut64) return f64 / fcut64 } func DiffToTarget(diff float64 /*, powLimit *big.Int*/) (*big.Int, error) { if diff <= 0 { return nil, fmt.Errorf("invalid pool difficulty %v (0 or less than "+ "zero passed)", diff) } // Round down in the case of a non-integer diff since we only support // ints (unless diff < 1 since we don't allow 0).. if diff <= 1 { diff = 1 } else { diff = math.Floor(diff) } divisor := new(big.Int).SetInt64(int64(diff)) //max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) max, _ := new(big.Int).SetString("00000000FFFF0000000000000000000000000000000000000000000000000000", 16) // BTC -> MAX_TARGET target := new(big.Int) //log.Println("target calc", hex.EncodeToString(max.Bytes()), hex.EncodeToString(divisor.Bytes())) target.Div(max, divisor) return target, nil } func Convert_big_endian(src []byte) []byte { var dst []byte = make([]byte, 32) for i := 0; i < 8; i++ { dst[0+4*i] = src[3+4*i] dst[1+4*i] = src[2+4*i] dst[2+4*i] = src[1+4*i] dst[3+4*i] = src[0+4*i] } return dst } func ReverseS(s string) (string, error) { a := strings.Split(s, "") sRev := "" if len(a)%2 != 0 { return "", fmt.Errorf("Incorrect input length") } for i := 0; i < len(a); i += 2 { tmp := []string{a[i], a[i+1], sRev} sRev = strings.Join(tmp, "") } return sRev, nil } func Reverse(src []byte) []byte { dst := make([]byte, len(src)) for i := len(src); i > 0; i-- { dst[len(src)-i] = src[i-1] } return dst } func Uint32ToByte(targetu uint32) []byte { bytes := make([]byte, 4) binary.LittleEndian.PutUint32(bytes, targetu) return bytes } func Uint32ToByteBig(targetu uint32) []byte { bytes := make([]byte, 4) binary.BigEndian.PutUint32(bytes, targetu) return bytes } func ExecShellCmd(s string) (string, error) { cmd := exec.Command("/bin/bash", "-c", s) var out bytes.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { fmt.Println(err) } //fmt.Println(out.String(), s) return out.String(), err } func BytesToHexStr(b []byte) string { hexString := hex.EncodeToString(b) return hexString } func NormalStrToHexStr(s string) string { hexStr := fmt.Sprintf("%x", s) // 将字符串转换为16进制字符串 return hexStr } func HexStrToBytes(s string) []byte { // 将16进制字符串转换为[]byte bytes, err := hex.DecodeString(s) if err != nil { log.Fatal(err) } return bytes } func ChainIndexStr(fromGroup uint32, toGroup uint32) string { return fmt.Sprintf("%d -> %d", fromGroup, toGroup) } func AlphDiff1Target() *big.Int { // 计算 2^226 - 1 result := new(big.Int).Lsh(big.NewInt(1), 226) // 1 << 226 result.Sub(result, big.NewInt(1)) // 2^226 - 1 return result } // fromBuffer: 将字节切片解析为大整数 func fromBuffer(buf []byte) *big.Int { return new(big.Int).SetBytes(buf) } func AlphShareDiff(hash []byte) float64 { hashBigNum := fromBuffer(hash) diff1Target := AlphDiff1Target() temp := new(big.Int).Mul(diff1Target, big.NewInt(1024)) result := new(big.Int).Div(temp, hashBigNum) finalResult := new(big.Float).SetInt(result) finalResult.Quo(finalResult, big.NewFloat(1024.0)) diffStr := finalResult.Text('f', 8) diff, err := strconv.ParseFloat(diffStr, 64) if err != nil { log.Fatal(err) return 0 } return diff } func AlphDiffToTarget(diff float64) (*big.Int, error) { if diff <= 0 { return nil, fmt.Errorf("invalid pool difficulty %v (0 or less than "+ "zero passed)", diff) } // Round down in the case of a non-integer diff since we only support // ints (unless diff < 1 since we don't allow 0).. if diff <= 1 { diff = 1 } else { diff = math.Floor(diff) } divisor := new(big.Int).SetInt64(int64(diff)) //max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) max, _ := new(big.Int).SetString("000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) // target := new(big.Int) //log.Println("target calc", hex.EncodeToString(max.Bytes()), hex.EncodeToString(divisor.Bytes())) target.Div(max, divisor) return target, nil } // 结果等同于上面的AlphDiffToTarget方法 func AlphDiffToTarget2(diff float64) string { alphTarget1Diff := new(big.Int).Lsh(big.NewInt(1), 226) alphTarget1Diff.Sub(alphTarget1Diff, big.NewInt(1)) // 难度1的 target // 直接在原变量上操作,避免不必要的变量创建 alphTarget1Diff.Mul(alphTarget1Diff, big.NewInt(1024)) // 计算 difficulty * 1024 并转换为 big.Int ceilDifficultyInt := new(big.Int).SetUint64(uint64(math.Ceil(diff * 1024))) // 计算最终 target target := new(big.Int).Div(alphTarget1Diff, ceilDifficultyInt) return target.Text(16) }