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
|
||||
// or hexadecimal syntax.
|
||||
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
|
||||
// hexadecimal syntax.
|
||||
type BigFlag struct {
|
||||
Name string
|
||||
Value *big.Int
|
||||
|
|
@ -97,7 +97,7 @@ func (b *bigValue) String() string {
|
|||
}
|
||||
|
||||
func (b *bigValue) Set(s string) error {
|
||||
int, ok := math.ParseBig(s)
|
||||
int, ok := math.ParseBig256(s)
|
||||
if !ok {
|
||||
return errors.New("invalid integer syntax")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,23 +28,30 @@ var (
|
|||
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.
|
||||
func ParseBig(s string) (*big.Int, bool) {
|
||||
func ParseBig256(s string) (*big.Int, bool) {
|
||||
if s == "" {
|
||||
return new(big.Int), true
|
||||
}
|
||||
var bigint *big.Int
|
||||
var ok bool
|
||||
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.
|
||||
func MustParseBig(s string) *big.Int {
|
||||
v, ok := ParseBig(s)
|
||||
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
|
||||
func MustParseBig256(s string) *big.Int {
|
||||
v, ok := ParseBig256(s)
|
||||
if !ok {
|
||||
panic("invalid integer: " + s)
|
||||
panic("invalid 256 bit integer: " + s)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestParseBig(t *testing.T) {
|
||||
func TestParseBig256(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
num *big.Int
|
||||
|
|
@ -42,9 +42,11 @@ func TestParseBig(t *testing.T) {
|
|||
// Invalid syntax:
|
||||
{"abcdef", nil, false},
|
||||
{"0xgg", nil, false},
|
||||
// Larger than 256 bits:
|
||||
{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
num, ok := ParseBig(test.input)
|
||||
num, ok := ParseBig256(test.input)
|
||||
if ok != test.ok {
|
||||
t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok)
|
||||
continue
|
||||
|
|
@ -55,13 +57,13 @@ func TestParseBig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMustParseBig(t *testing.T) {
|
||||
func TestMustParseBig256(t *testing.T) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Error("MustParseBig should've panicked")
|
||||
}
|
||||
}()
|
||||
MustParseBig("ggg")
|
||||
MustParseBig256("ggg")
|
||||
}
|
||||
|
||||
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(1), 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(2), exponent: big.NewInt(255), result: MustParseBig("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
|
||||
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
|
||||
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
|
||||
}
|
||||
for _, test := range tests {
|
||||
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.ParentDifficulty = math.MustParseBig(ext.ParentDifficulty)
|
||||
d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
|
||||
d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
|
||||
d.CurrentBlocknumber = math.MustParseBig(ext.CurrentBlocknumber)
|
||||
d.CurrentDifficulty = math.MustParseBig(ext.CurrentDifficulty)
|
||||
d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
|
||||
d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
|||
// creating with empty hash always works
|
||||
statedb, _ := state.New(common.Hash{}, chainDb)
|
||||
for addr, account := range genesis.Alloc {
|
||||
balance, ok := math.ParseBig(account.Balance)
|
||||
balance, ok := math.ParseBig256(account.Balance)
|
||||
if !ok {
|
||||
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)
|
||||
|
||||
difficulty, ok := math.ParseBig(genesis.Difficulty)
|
||||
difficulty, ok := math.ParseBig256(genesis.Difficulty)
|
||||
if !ok {
|
||||
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 {
|
||||
return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
|
||||
}
|
||||
timestamp, ok := math.ParseBig(genesis.Timestamp)
|
||||
timestamp, ok := math.ParseBig256(genesis.Timestamp)
|
||||
if !ok {
|
||||
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)
|
||||
}
|
||||
|
||||
if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig(account.Balance)) != 0 {
|
||||
return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig(account.Balance), balance)
|
||||
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.MustParseBig256(account.Balance), balance)
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
statedb.Reset(root)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ func verifyTxFields(chainConfig *params.ChainConfig, txTest TransactionTest, dec
|
|||
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ func insertAccount(state *state.StateDB, saddr string, account Account) {
|
|||
addr := common.HexToAddress(saddr)
|
||||
state.SetCode(addr, common.Hex2Bytes(account.Code))
|
||||
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 {
|
||||
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) {
|
||||
var (
|
||||
data = common.FromHex(tx["data"])
|
||||
gas = math.MustParseBig(tx["gasLimit"])
|
||||
price = math.MustParseBig(tx["gasPrice"])
|
||||
value = math.MustParseBig(tx["value"])
|
||||
gas = math.MustParseBig256(tx["gasLimit"])
|
||||
price = math.MustParseBig256(tx["gasPrice"])
|
||||
value = math.MustParseBig256(tx["value"])
|
||||
nonce = math.MustParseUint64(tx["nonce"])
|
||||
)
|
||||
|
||||
|
|
@ -199,10 +199,10 @@ func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *st
|
|||
|
||||
Origin: origin,
|
||||
Coinbase: common.HexToAddress(envValues["currentCoinbase"]),
|
||||
BlockNumber: math.MustParseBig(envValues["currentNumber"]),
|
||||
Time: math.MustParseBig(envValues["currentTimestamp"]),
|
||||
GasLimit: math.MustParseBig(envValues["currentGasLimit"]),
|
||||
Difficulty: math.MustParseBig(envValues["currentDifficulty"]),
|
||||
BlockNumber: math.MustParseBig256(envValues["currentNumber"]),
|
||||
Time: math.MustParseBig256(envValues["currentTimestamp"]),
|
||||
GasLimit: math.MustParseBig256(envValues["currentGasLimit"]),
|
||||
Difficulty: math.MustParseBig256(envValues["currentDifficulty"]),
|
||||
GasPrice: price,
|
||||
}
|
||||
if context.GasPrice == nil {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func runVmTest(test VmTest) error {
|
|||
if len(test.Gas) == 0 && err == nil {
|
||||
return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful")
|
||||
} else {
|
||||
gexp := math.MustParseBig(test.Gas)
|
||||
gexp := math.MustParseBig256(test.Gas)
|
||||
if gexp.Cmp(gas) != 0 {
|
||||
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"])
|
||||
from = common.HexToAddress(exec["caller"])
|
||||
data = common.FromHex(exec["data"])
|
||||
gas = math.MustParseBig(exec["gas"])
|
||||
value = math.MustParseBig(exec["value"])
|
||||
gas = math.MustParseBig256(exec["gas"])
|
||||
value = math.MustParseBig256(exec["value"])
|
||||
)
|
||||
caller := statedb.GetOrNewStateObject(from)
|
||||
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
||||
|
|
|
|||
Loading…
Reference in a new issue