mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
common/math: check for 256 bit overflow in ParseBig
This is supposed to prevent silent overflow/truncation of values in the genesis block JSON. Without this check, a genesis block that set a balance larger than 256 bits would lead to weird behaviour in the VM.
This commit is contained in:
parent
8fd6e8043a
commit
eb96864658
9 changed files with 47 additions and 38 deletions
|
|
@ -78,8 +78,8 @@ func (self DirectoryFlag) Apply(set *flag.FlagSet) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// BigFlag is a command line flag that accepts big integers in decimal
|
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
|
||||||
// or hexadecimal syntax.
|
// hexadecimal syntax.
|
||||||
type BigFlag struct {
|
type BigFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
|
|
@ -97,7 +97,7 @@ func (b *bigValue) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bigValue) Set(s string) error {
|
func (b *bigValue) Set(s string) error {
|
||||||
int, ok := math.ParseBig(s)
|
int, ok := math.ParseBig256(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("invalid integer syntax")
|
return errors.New("invalid integer syntax")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,23 +28,30 @@ var (
|
||||||
MaxBig256 = new(big.Int).Set(tt256m1)
|
MaxBig256 = new(big.Int).Set(tt256m1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseBig parses s as a big integer in decimal or hexadecimal syntax.
|
// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
|
||||||
// Leading zeros are accepted. The empty string parses as zero.
|
// Leading zeros are accepted. The empty string parses as zero.
|
||||||
func ParseBig(s string) (*big.Int, bool) {
|
func ParseBig256(s string) (*big.Int, bool) {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return new(big.Int), true
|
return new(big.Int), true
|
||||||
}
|
}
|
||||||
|
var bigint *big.Int
|
||||||
|
var ok bool
|
||||||
if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
|
if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
|
||||||
return new(big.Int).SetString(s[2:], 16)
|
bigint, ok = new(big.Int).SetString(s[2:], 16)
|
||||||
|
} else {
|
||||||
|
bigint, ok = new(big.Int).SetString(s, 10)
|
||||||
}
|
}
|
||||||
return new(big.Int).SetString(s, 10)
|
if ok && bigint.BitLen() > 256 {
|
||||||
|
bigint, ok = nil, false
|
||||||
|
}
|
||||||
|
return bigint, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustParseBig parses s as a big integer and panics if the string is invalid.
|
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
|
||||||
func MustParseBig(s string) *big.Int {
|
func MustParseBig256(s string) *big.Int {
|
||||||
v, ok := ParseBig(s)
|
v, ok := ParseBig256(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("invalid integer: " + s)
|
panic("invalid 256 bit integer: " + s)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseBig(t *testing.T) {
|
func TestParseBig256(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
input string
|
input string
|
||||||
num *big.Int
|
num *big.Int
|
||||||
|
|
@ -42,9 +42,11 @@ func TestParseBig(t *testing.T) {
|
||||||
// Invalid syntax:
|
// Invalid syntax:
|
||||||
{"abcdef", nil, false},
|
{"abcdef", nil, false},
|
||||||
{"0xgg", nil, false},
|
{"0xgg", nil, false},
|
||||||
|
// Larger than 256 bits:
|
||||||
|
{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
num, ok := ParseBig(test.input)
|
num, ok := ParseBig256(test.input)
|
||||||
if ok != test.ok {
|
if ok != test.ok {
|
||||||
t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok)
|
t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok)
|
||||||
continue
|
continue
|
||||||
|
|
@ -55,13 +57,13 @@ func TestParseBig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMustParseBig(t *testing.T) {
|
func TestMustParseBig256(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if recover() == nil {
|
if recover() == nil {
|
||||||
t.Error("MustParseBig should've panicked")
|
t.Error("MustParseBig should've panicked")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
MustParseBig("ggg")
|
MustParseBig256("ggg")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBigMax(t *testing.T) {
|
func TestBigMax(t *testing.T) {
|
||||||
|
|
@ -183,8 +185,8 @@ func TestExp(t *testing.T) {
|
||||||
{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
|
{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
|
||||||
{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
|
{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
|
||||||
{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
|
{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
|
||||||
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig("507528786056415600719754159741696356908742250191663887263627442114881")},
|
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
|
||||||
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
|
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
|
if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,10 @@ func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
|
d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
|
||||||
d.ParentDifficulty = math.MustParseBig(ext.ParentDifficulty)
|
d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
|
||||||
d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
|
d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
|
||||||
d.CurrentBlocknumber = math.MustParseBig(ext.CurrentBlocknumber)
|
d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
|
||||||
d.CurrentDifficulty = math.MustParseBig(ext.CurrentDifficulty)
|
d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
// creating with empty hash always works
|
// creating with empty hash always works
|
||||||
statedb, _ := state.New(common.Hash{}, chainDb)
|
statedb, _ := state.New(common.Hash{}, chainDb)
|
||||||
for addr, account := range genesis.Alloc {
|
for addr, account := range genesis.Alloc {
|
||||||
balance, ok := math.ParseBig(account.Balance)
|
balance, ok := math.ParseBig256(account.Balance)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid balance for account %s: %q", addr, account.Balance)
|
return nil, fmt.Errorf("invalid balance for account %s: %q", addr, account.Balance)
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +87,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
}
|
}
|
||||||
root, stateBatch := statedb.CommitBatch(false)
|
root, stateBatch := statedb.CommitBatch(false)
|
||||||
|
|
||||||
difficulty, ok := math.ParseBig(genesis.Difficulty)
|
difficulty, ok := math.ParseBig256(genesis.Difficulty)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty)
|
return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty)
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +99,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
|
return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
|
||||||
}
|
}
|
||||||
timestamp, ok := math.ParseBig(genesis.Timestamp)
|
timestamp, ok := math.ParseBig256(genesis.Timestamp)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid timestamp: %q", genesis.Timestamp)
|
return nil, fmt.Errorf("invalid timestamp: %q", genesis.Timestamp)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,8 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
|
||||||
return fmt.Errorf("did not find expected post-state account: %s", addr)
|
return fmt.Errorf("did not find expected post-state account: %s", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig(account.Balance)) != 0 {
|
if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig256(account.Balance)) != 0 {
|
||||||
return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig(account.Balance), balance)
|
return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig256(account.Balance), balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
if nonce := statedb.GetNonce(address); nonce != math.MustParseUint64(account.Nonce) {
|
if nonce := statedb.GetNonce(address); nonce != math.MustParseUint64(account.Nonce) {
|
||||||
|
|
@ -206,7 +206,7 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
|
||||||
|
|
||||||
func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, []*types.Log, *big.Int, error) {
|
func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, []*types.Log, *big.Int, error) {
|
||||||
environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx)
|
environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx)
|
||||||
gaspool := new(core.GasPool).AddGas(math.MustParseBig(env["currentGasLimit"]))
|
gaspool := new(core.GasPool).AddGas(math.MustParseBig256(env["currentGasLimit"]))
|
||||||
|
|
||||||
root, _ := statedb.Commit(false)
|
root, _ := statedb.Commit(false)
|
||||||
statedb.Reset(root)
|
statedb.Reset(root)
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ func verifyTxFields(chainConfig *params.ChainConfig, txTest TransactionTest, dec
|
||||||
|
|
||||||
var decodedSender common.Address
|
var decodedSender common.Address
|
||||||
|
|
||||||
signer := types.MakeSigner(chainConfig, math.MustParseBig(txTest.Blocknumber))
|
signer := types.MakeSigner(chainConfig, math.MustParseBig256(txTest.Blocknumber))
|
||||||
decodedSender, err = types.Sender(signer, decodedTx)
|
decodedSender, err = types.Sender(signer, decodedTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ func insertAccount(state *state.StateDB, saddr string, account Account) {
|
||||||
addr := common.HexToAddress(saddr)
|
addr := common.HexToAddress(saddr)
|
||||||
state.SetCode(addr, common.Hex2Bytes(account.Code))
|
state.SetCode(addr, common.Hex2Bytes(account.Code))
|
||||||
state.SetNonce(addr, math.MustParseUint64(account.Nonce))
|
state.SetNonce(addr, math.MustParseUint64(account.Nonce))
|
||||||
state.SetBalance(addr, math.MustParseBig(account.Balance))
|
state.SetBalance(addr, math.MustParseBig256(account.Balance))
|
||||||
for a, v := range account.Storage {
|
for a, v := range account.Storage {
|
||||||
state.SetState(addr, common.HexToHash(a), common.HexToHash(v))
|
state.SetState(addr, common.HexToHash(a), common.HexToHash(v))
|
||||||
}
|
}
|
||||||
|
|
@ -153,9 +153,9 @@ type VmTest struct {
|
||||||
func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) {
|
func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) {
|
||||||
var (
|
var (
|
||||||
data = common.FromHex(tx["data"])
|
data = common.FromHex(tx["data"])
|
||||||
gas = math.MustParseBig(tx["gasLimit"])
|
gas = math.MustParseBig256(tx["gasLimit"])
|
||||||
price = math.MustParseBig(tx["gasPrice"])
|
price = math.MustParseBig256(tx["gasPrice"])
|
||||||
value = math.MustParseBig(tx["value"])
|
value = math.MustParseBig256(tx["value"])
|
||||||
nonce = math.MustParseUint64(tx["nonce"])
|
nonce = math.MustParseUint64(tx["nonce"])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -199,10 +199,10 @@ func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *st
|
||||||
|
|
||||||
Origin: origin,
|
Origin: origin,
|
||||||
Coinbase: common.HexToAddress(envValues["currentCoinbase"]),
|
Coinbase: common.HexToAddress(envValues["currentCoinbase"]),
|
||||||
BlockNumber: math.MustParseBig(envValues["currentNumber"]),
|
BlockNumber: math.MustParseBig256(envValues["currentNumber"]),
|
||||||
Time: math.MustParseBig(envValues["currentTimestamp"]),
|
Time: math.MustParseBig256(envValues["currentTimestamp"]),
|
||||||
GasLimit: math.MustParseBig(envValues["currentGasLimit"]),
|
GasLimit: math.MustParseBig256(envValues["currentGasLimit"]),
|
||||||
Difficulty: math.MustParseBig(envValues["currentDifficulty"]),
|
Difficulty: math.MustParseBig256(envValues["currentDifficulty"]),
|
||||||
GasPrice: price,
|
GasPrice: price,
|
||||||
}
|
}
|
||||||
if context.GasPrice == nil {
|
if context.GasPrice == nil {
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ func runVmTest(test VmTest) error {
|
||||||
if len(test.Gas) == 0 && err == nil {
|
if len(test.Gas) == 0 && err == nil {
|
||||||
return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful")
|
return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful")
|
||||||
} else {
|
} else {
|
||||||
gexp := math.MustParseBig(test.Gas)
|
gexp := math.MustParseBig256(test.Gas)
|
||||||
if gexp.Cmp(gas) != 0 {
|
if gexp.Cmp(gas) != 0 {
|
||||||
return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
|
return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
|
||||||
}
|
}
|
||||||
|
|
@ -223,8 +223,8 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type
|
||||||
to = common.HexToAddress(exec["address"])
|
to = common.HexToAddress(exec["address"])
|
||||||
from = common.HexToAddress(exec["caller"])
|
from = common.HexToAddress(exec["caller"])
|
||||||
data = common.FromHex(exec["data"])
|
data = common.FromHex(exec["data"])
|
||||||
gas = math.MustParseBig(exec["gas"])
|
gas = math.MustParseBig256(exec["gas"])
|
||||||
value = math.MustParseBig(exec["value"])
|
value = math.MustParseBig256(exec["value"])
|
||||||
)
|
)
|
||||||
caller := statedb.GetOrNewStateObject(from)
|
caller := statedb.GetOrNewStateObject(from)
|
||||||
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue