aboutsummaryrefslogtreecommitdiffstats
path: root/internal
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2017-01-05 03:17:24 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2017-02-14 04:44:25 +0800
commitc12f4df910e2da1cc5dd28c5c4bbe2d8721e1057 (patch)
treeda94063644627d9da853a91c28bc37f2df341dd1 /internal
parent72dcd3c58bec0a281280d5d42ed53b6e429ce4af (diff)
downloaddexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.gz
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.bz2
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.lz
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.xz
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.zst
dexon-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.zip
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
Diffstat (limited to 'internal')
-rw-r--r--internal/ethapi/api.go62
-rw-r--r--internal/ethapi/backend.go2
-rw-r--r--internal/ethapi/tracer_test.go4
3 files changed, 45 insertions, 23 deletions
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index cf82cc866..6b11cbc97 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -48,6 +48,8 @@ import (
const defaultGas = 90000
+var emptyHex = "0x"
+
// PublicEthereumAPI provides an API to access Ethereum related information.
// It offers only methods that operate on public data that is freely available to anyone.
type PublicEthereumAPI struct {
@@ -574,12 +576,12 @@ type CallArgs struct {
Data hexutil.Bytes `json:"data"`
}
-func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) {
+func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) {
defer func(start time.Time) { glog.V(logger.Debug).Infof("call took %v", time.Since(start)) }(time.Now())
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil {
- return "0x", common.Big0, err
+ return nil, common.Big0, err
}
// Set sender address or use a default if none specified
addr := args.From
@@ -589,40 +591,60 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
addr = accounts[0].Address
}
}
- } else {
- addr = args.From
}
// Set default gas & gas price if none were set
gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt()
- if gas.Cmp(common.Big0) == 0 {
+ if gas.BitLen() == 0 {
gas = big.NewInt(50000000)
}
- if gasPrice.Cmp(common.Big0) == 0 {
+ if gasPrice.BitLen() == 0 {
gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
}
+
+ // Create new call message
msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
- // Execute the call and return
- vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
- if err != nil {
- return "0x", common.Big0, err
+ // Setup context so it may be cancelled the call has completed
+ // or, in case of unmetered gas, setup a context with a timeout.
+ var cancel context.CancelFunc
+ if vmCfg.DisableGasMetering {
+ ctx, cancel = context.WithTimeout(ctx, time.Second*5)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
}
+ // Make sure the context is cancelled when the call has completed
+ // this makes sure resources are cleaned up.
+ defer func() { cancel() }()
+
+ // Get a new instance of the EVM.
+ evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg)
+ if err != nil {
+ return nil, common.Big0, err
+ }
+ // Wait for the context to be done and cancel the evm. Even if the
+ // EVM has finished, cancelling may be done (repeatedly)
+ go func() {
+ select {
+ case <-ctx.Done():
+ evm.Cancel()
+ }
+ }()
+
+ // Setup the gas pool (also for unmetered requests)
+ // and apply the message.
gp := new(core.GasPool).AddGas(common.MaxBig)
- res, gas, err := core.ApplyMessage(vmenv, msg, gp)
+ res, gas, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
- return "0x", common.Big0, err
- }
- if len(res) == 0 { // backwards compatibility
- return "0x", gas, err
+ return nil, common.Big0, err
}
- return common.ToHex(res), gas, err
+ return res, gas, err
}
// Call executes the given transaction on the state for the given block number.
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
-func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) {
- result, _, err := s.doCall(ctx, args, blockNr)
- return result, err
+func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
+ result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
+ return (hexutil.Bytes)(result), err
}
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
@@ -644,7 +666,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
mid := (hi + lo) / 2
(*big.Int)(&args.Gas).SetUint64(mid)
- _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
+ _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
// If the transaction became invalid or used all the gas (failed), raise the gas limit
if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index ebb14a5b5..214214f51 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -51,7 +51,7 @@ type Backend interface {
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetTd(blockHash common.Hash) *big.Int
- GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (*vm.EVM, func() error, error)
+ GetEVM(ctx context.Context, msg core.Message, state State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error)
// TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
RemoveTx(txHash common.Hash)
diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go
index 65a23f55e..693afe802 100644
--- a/internal/ethapi/tracer_test.go
+++ b/internal/ethapi/tracer_test.go
@@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
func runTrace(tracer *JavascriptTracer) (interface{}, error) {
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
- contract := vm.NewContract(account{}, account{}, big.NewInt(0), big.NewInt(10000))
+ contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
_, err := env.Interpreter().Run(contract, []byte{})
@@ -134,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) {
}
env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
- contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0))
+ contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil)
timeout := errors.New("stahp")