【初心者向け】ETHの残高を計算する際に気をつけること
この記事は株式会社Gincoのテックブログとして書いています。
本記事では、GoでEthereum(ETH)の残高を計算する際に初心者が間違えやすいint64のオーバーフロー問題について解説します。
整数範囲の指定とオーバーフローについて
整数を扱う際、型ごとに表現できる範囲があります。その範囲を超えた場合、予期せぬ振る舞いやエラーが発生することがあります。これをオーバーフローと言います。
Ethereumの最小単位「wei」が小さすぎる件
ETHの残高は「wei」という単位で表現されます。このweiは非常に小さな単位で、1ETHは10^18 weiに相当します。そのため、ETHの残高にはint64(最大値: 9223372036854775807(約9*10^19))で表現できないことがあります。
例えば、ユーザーが10ETH(=1^20wei)を保持している場合、この数値はint64の範囲を超えてしまうため、そのユーザーの残高を計算する際には注意が必要です。
実際にint64でETHを計算すると…
初心者が間違えやすいエラーの一つとして、int64を用いて直接ETHの残高を計算しようとするケースがあります。以下にそのコード例を示します。
func main() {
var balance int64 = 1000000000000000000 // 1 ETH in wei
var ethValue int64 = 9000000000000000000 // 9 ETH in wei
balance += ethValue
fmt.Println("Balance: ", balance)
}
出力結果
Balance: -8446744073709551616
このコードを実行すると、正の値が期待されるにもかかわらず、負の値が出力されます。
これは加算の結果がint64の範囲を超えて、オーバーフローが発生したためです。
math/bigパッケージを活用して落とし穴を回避
オーバーフローを防ぐためには、Goの標準ライブラリであるmath/big パッケージが利用できます。このパッケージは、任意の大きさの整数(big.Int)や浮動小数点数(big.Float)を扱うことが可能です。
以下に、上記のコードをmath/big パッケージを使用して書き直したコード例を示します。
func main() {
balance := new(big.Int)
balance.SetString("1000000000000000000", 10) // 1 ETH in wei
ethValue := new(big.Int)
ethValue.SetString("9000000000000000000", 10) // 9 ETH in wei
balance.Add(balance, ethValue)
fmt.Printf("Balance: %s", balance.String())
}
出力結果
Balance: 10000000000000000000
上記のコードでは、math/big パッケージの、big.Int型を用いて大きな数値を扱っているため、オーバーフローは発生しません。
これにより、int64のオーバーフローを防ぐことができます。
弊社の「Ginco Enterprise Wallet」でもこちらの方法を使用しており、ウォレットの残高はDBにStringで保存し、計算時にはbig.Intを利用しています。
まとめ
大きな数値を扱う際には、適切な型とその範囲を理解することが重要です。特に、int64などの型を使用する際には、その型が表現できる範囲を超えないように注意が必要です。
また、大きな数値を扱う場合や範囲を超える可能性がある場合には、math/big パッケージのような任意精度の数値を扱うパッケージの利用することでオーバーフローを避けることができます。
株式会社Gincoではブロックチェーンを学びたい方、ウォレットについて詳しくなりたい方を募集していますので下記リンクから是非ご応募ください。
Discussion