我需要将以太坊(加密货币)余额导出到Postgres,但我需要在blob中压缩它们,因为它们太多了,我必须为每个块存储状态。余额存储在big.Int
,但大多数帐户的余额为0(或非常接近于零),所以我在考虑这种压缩算法:
Format (single record):
8bits: the length of the bit string
following bits : the actual big.Int converted into bits with Int.Bits() function
天平以1/10 ^ 18精度存储,因此1个以1位存储,18个零。将我的算法压缩成最好的方法吗?或者有更好的想法吗?
例如,另一个想法是选择一个float64,但我不确定它是否可以保存所有值的范围。 1以太是1
,有18个零,但加密货币交换可以平衡百万个,所以最大值为1
,大约25个零。或者我可以在最糟糕的情况下选择float128。
你有什么建议?
答案 0 :(得分:2)
要获得最大压缩效果,请使用Bytes()
(返回[]byte
),而不是Bits()
(返回[]uint
)。例如,零余额(公共值)是一个字节的blob。此外,允许负余额。例如,
package main
import (
"fmt"
"math/big"
)
func CompressBalance(i *big.Int) []byte {
if i == nil {
return nil
}
if i.BitLen() == 0 {
return []byte{0}
}
byts := i.Bytes()
if len(byts) > 0x7F {
return nil
}
blob := make([]byte, 1+len(byts))
blob[0] = byte(len(byts))
blob[0] |= byte(i.Sign()) & 0x80
copy(blob[1:], byts)
return blob
}
func DecompressBalance(b []byte) *big.Int {
if len(b) <= 0 {
return nil
}
if 1+int(b[0]&0x7F) != len(b) {
return nil
}
i := new(big.Int)
if b[0] == 0 {
return i
}
i.SetBytes(b[1:])
if b[0]&0x80 == 0x80 {
i.Neg(i)
}
return i
}
func main() {
tests := []string{
"0",
"1925000288124900513257758", // 1,925,000.288124900513257758
"-1925000288124900513257758", // -1,925,000.288124900513257758
}
for _, s := range tests {
i := new(big.Int)
i, ok := i.SetString(s, 10)
if !ok {
fmt.Println("error:", i, ok)
}
blob := CompressBalance(i)
j := DecompressBalance(blob)
fmt.Printf("i: %s\nj: %s\nblob: %d %v\n", i, j, len(blob), blob)
}
}
游乐场:https://play.golang.org/p/zClfVxG6agL
输出:
i: 0
j: 0
blob: 1 [0]
i: 1925000288124900513257758
j: 1925000288124900513257758
blob: 12 [11 1 151 162 121 135 80 245 19 41 153 30]
i: -1925000288124900513257758
j: -1925000288124900513257758
blob: 12 [139 1 151 162 121 135 80 245 19 41 153 30]
金融交易需要确切的数字。根据设计,浮点数是近似值。