368 lines
9.8 KiB
Go
368 lines
9.8 KiB
Go
// utility.go
|
|
package utility
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
|
|
"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"`
|
|
Pprof string `json:"pprof,omitempty"`
|
|
}
|
|
|
|
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, 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, config.Pprof
|
|
}
|
|
|
|
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!"))
|
|
}
|
|
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!"))
|
|
}
|
|
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)
|
|
|
|
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()))
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func Target2Diff(target []byte) float64 {
|
|
//var f64 float64 = truediffone
|
|
//max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
|
|
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 MoneroTarget2Diff(target []byte) float64 {
|
|
//var f64 float64 = truediffone
|
|
// max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
|
|
max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 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("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
|
|
target := new(big.Int)
|
|
//log.Println("target calc", hex.EncodeToString(max.Bytes()), hex.EncodeToString(divisor.Bytes()))
|
|
target.Div(max, divisor)
|
|
|
|
return target, nil
|
|
}
|
|
|
|
func MoneroDiffToTarget(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("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
|
|
max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
|
|
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
|
|
}
|