Skip to content
Permalink
Browse files

params: core, core/vm, miner: 64bit gas instructions

Reworked the EVM gas instructions to use 64bit integers rather than
arbitrary size big ints. All gas operations, be it additions,
multiplications or divisions, are checked and guarded against 64 bit
integer overflows.

In additon, most of the protocol paramaters in the params package have
been converted to uint64 and are now constants rather than variables.

* common/math: added overflow check ops
* core: vmenv, env renamed to evm
* eth, internal/ethapi, les: unmetered eth_call and cancel methods
* core/vm: implemented big.Int pool for evm instructions
* core/vm: unexported intPool methods & verification methods
* core/vm: added memoryGasCost overflow check and test
  • Loading branch information...
obscuren committed Jan 4, 2017
1 parent 72dcd3c commit c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057
Showing with 1,087 additions and 826 deletions.
  1. +2 −2 cmd/evm/main.go
  2. +1 −1 cmd/geth/main.go
  3. +25 −0 common/math/integer.go
  4. +50 −0 common/math/integer_test.go
  5. +4 −3 core/bench_test.go
  6. +1 −1 core/block_validator.go
  7. +8 −8 core/blockchain_test.go
  8. +3 −3 core/chain_makers_test.go
  9. +50 −38 core/state_transition.go
  10. +11 −67 core/vm/common.go
  11. +9 −24 core/vm/contract.go
  12. +21 −18 core/vm/contracts.go
  13. +27 −56 core/vm/{environment.go → evm.go}
  14. +23 −130 core/vm/gas.go
  15. +294 −124 core/vm/gas_table.go
  16. +24 −0 core/vm/gas_table_test.go
  17. +211 −127 core/vm/instructions.go
  18. +15 −0 core/vm/int_pool_verifier.go
  19. +7 −0 core/vm/int_pool_verifier_empty.go
  20. +30 −10 core/vm/{vm.go → interpreter.go}
  21. +31 −4 core/vm/{virtual_machine.go → intpool.go}
  22. +54 −51 core/vm/jump_table.go
  23. +2 −2 core/vm/logger_test.go
  24. +3 −2 core/vm/memory.go
  25. +1 −1 core/vm/runtime/env.go
  26. +8 −6 core/vm/runtime/runtime.go
  27. +2 −2 core/vm/runtime/runtime_test.go
  28. +4 −4 core/vm/stack_table.go
  29. +2 −2 eth/api_backend.go
  30. +2 −2 eth/bind.go
  31. +6 −6 eth/downloader/downloader.go
  32. +1 −1 eth/downloader/downloader_test.go
  33. +1 −1 eth/fetcher/fetcher_test.go
  34. +8 −6 eth/handler_test.go
  35. +42 −20 internal/ethapi/api.go
  36. +1 −1 internal/ethapi/backend.go
  37. +2 −2 internal/ethapi/tracer_test.go
  38. +2 −2 les/api_backend.go
  39. +5 −3 les/helper_test.go
  40. +5 −3 light/odr_test.go
  41. +1 −1 light/txpool_test.go
  42. +1 −1 miner/miner.go
  43. +31 −37 params/gas_table.go
  44. +51 −49 params/protocol_params.go
  45. +1 −1 tests/block_test_util.go
  46. +1 −1 tests/state_test_util.go
  47. +3 −3 tests/vm_test_util.go
@@ -156,7 +156,7 @@ func run(ctx *cli.Context) error {
ret, _, err = runtime.Create(input, &runtime.Config{
Origin: sender.Address(),
State: statedb,
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
EVMConfig: vm.Config{
@@ -172,7 +172,7 @@ func run(ctx *cli.Context) error {
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
Origin: sender.Address(),
State: statedb,
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
EVMConfig: vm.Config{
@@ -205,7 +205,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
if err != nil {
glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
}
if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
if uint64(len(extra)) > params.MaximumExtraDataSize {
glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
glog.V(logger.Debug).Infof("extra: %x\n", extra)
extra = nil
@@ -0,0 +1,25 @@
package math

import gmath "math"

/*
* NOTE: The following methods need to be optimised using either bit checking or asm
*/

// SafeSub returns subtraction result and whether overflow occurred.
func SafeSub(x, y uint64) (uint64, bool) {
return x - y, x < y
}

// SafeAdd returns the result and whether overflow occurred.
func SafeAdd(x, y uint64) (uint64, bool) {
return x + y, y > gmath.MaxUint64-x
}

// SafeMul returns multiplication result and whether overflow occurred.
func SafeMul(x, y uint64) (uint64, bool) {
if x == 0 {
return 0, false
}
return x * y, x != 0 && y != 0 && y > gmath.MaxUint64/x
}
@@ -0,0 +1,50 @@
package math

import (
gmath "math"
"testing"
)

type operation byte

const (
sub operation = iota
add
mul
)

func TestOverflow(t *testing.T) {
for i, test := range []struct {
x uint64
y uint64
overflow bool
op operation
}{
// add operations
{gmath.MaxUint64, 1, true, add},
{gmath.MaxUint64 - 1, 1, false, add},

// sub operations
{0, 1, true, sub},
{0, 0, false, sub},

// mul operations
{10, 10, false, mul},
{gmath.MaxUint64, 2, true, mul},
{gmath.MaxUint64, 1, false, mul},
} {
var overflows bool
switch test.op {
case sub:
_, overflows = SafeSub(test.x, test.y)
case add:
_, overflows = SafeAdd(test.x, test.y)
case mul:
_, overflows = SafeMul(test.x, test.y)
}

if test.overflow != overflows {
t.Errorf("%d failed. Expected test to be %v, got %v", i, test.overflow, overflows)
}
}
}
@@ -92,6 +92,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
var (
ringKeys = make([]*ecdsa.PrivateKey, 1000)
ringAddrs = make([]common.Address, len(ringKeys))
bigTxGas = new(big.Int).SetUint64(params.TxGas)
)

func init() {
@@ -111,16 +112,16 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
gas := CalcGasLimit(gen.PrevBlock(i - 1))
for {
gas.Sub(gas, params.TxGas)
if gas.Cmp(params.TxGas) < 0 {
gas.Sub(gas, bigTxGas)
if gas.Cmp(bigTxGas) < 0 {
break
}
to := (from + 1) % naccounts
tx := types.NewTransaction(
gen.TxNonce(ringAddrs[from]),
ringAddrs[to],
benchRootFunds,
params.TxGas,
bigTxGas,
nil,
nil,
)
@@ -204,7 +204,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
//
// See YP section 4.3.4. "Block Header Validity"
func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
}

@@ -720,7 +720,7 @@ func TestFastVsFullChains(t *testing.T) {
// If the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 {
for j := 0; j < i%4+1; j++ {
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key)
if err != nil {
panic(err)
}
@@ -884,8 +884,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain
postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)

// Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block
@@ -901,13 +901,13 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
switch i {
case 0:
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)

gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork

case 2:
freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)

gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
@@ -926,18 +926,18 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i {
case 0:
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg

case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain

freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time

case 3:
futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
}
})
@@ -56,13 +56,13 @@ func ExampleGenerateChain() {
switch i {
case 0:
// In block 1, addr1 sends addr2 some ether.
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), bigTxGas, nil, nil), signer, key1)
gen.AddTx(tx)
case 1:
// In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3.
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
gen.AddTx(tx1)
gen.AddTx(tx2)
case 2:
Oops, something went wrong.

0 comments on commit c12f4df

Please sign in to comment.
You can’t perform that action at this time.