core/vm, cmd/evm: Add ability for 'evm' binary to report gas used

This commit is contained in:
Martin Holst Swende 2017-06-04 20:46:29 +02:00
parent 567f69539e
commit 21ac4dd109
3 changed files with 15 additions and 13 deletions

View file

@ -137,11 +137,11 @@ func runCmd(ctx *cli.Context) error {
} }
code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
} }
initialGas := ctx.GlobalUint64(GasFlag.Name)
runtimeConfig := runtime.Config{ runtimeConfig := runtime.Config{
Origin: sender, Origin: sender,
State: statedb, State: statedb,
GasLimit: ctx.GlobalUint64(GasFlag.Name), GasLimit: initialGas,
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
Value: utils.GlobalBig(ctx, ValueFlag.Name), Value: utils.GlobalBig(ctx, ValueFlag.Name),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
@ -168,14 +168,15 @@ func runCmd(ctx *cli.Context) error {
runtimeConfig.ChainConfig = chainConfig runtimeConfig.ChainConfig = chainConfig
} }
tstart := time.Now() tstart := time.Now()
var leftOverGas uint64
if ctx.GlobalBool(CreateFlag.Name) { if ctx.GlobalBool(CreateFlag.Name) {
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
ret, _, err = runtime.Create(input, &runtimeConfig) ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig)
} else { } else {
receiver := common.StringToAddress("receiver") receiver := common.StringToAddress("receiver")
statedb.SetCode(receiver, code) statedb.SetCode(receiver, code)
ret, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
} }
execTime := time.Since(tstart) execTime := time.Since(tstart)
@ -214,11 +215,12 @@ heap objects: %d
allocations: %d allocations: %d
total allocations: %d total allocations: %d
GC calls: %d GC calls: %d
Gas used: %d
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC) `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
} }
if tracer != nil { if tracer != nil {
tracer.CaptureEnd(ret, 0, execTime) tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime)
} else { } else {
fmt.Printf("0x%x\n", ret) fmt.Printf("0x%x\n", ret)
} }

View file

@ -125,7 +125,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
} }
// Create executes the code using the EVM create method // Create executes the code using the EVM create method
func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
if cfg == nil { if cfg == nil {
cfg = new(Config) cfg = new(Config)
} }
@ -141,13 +141,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
) )
// Call the code with the given configuration. // Call the code with the given configuration.
code, address, _, err := vmenv.Create( code, address, leftOverGas, err := vmenv.Create(
sender, sender,
input, input,
cfg.GasLimit, cfg.GasLimit,
cfg.Value, cfg.Value,
) )
return code, address, err return code, address, leftOverGas, err
} }
// Call executes the code given by the contract's address. It will return the // Call executes the code given by the contract's address. It will return the
@ -155,14 +155,14 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
// //
// Call, unlike Execute, requires a config and also requires the State field to // Call, unlike Execute, requires a config and also requires the State field to
// be set. // be set.
func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) { func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
setDefaults(cfg) setDefaults(cfg)
vmenv := NewEnv(cfg, cfg.State) vmenv := NewEnv(cfg, cfg.State)
sender := cfg.State.GetOrNewStateObject(cfg.Origin) sender := cfg.State.GetOrNewStateObject(cfg.Origin)
// Call the code with the given configuration. // Call the code with the given configuration.
ret, _, err := vmenv.Call( ret, leftOverGas, err := vmenv.Call(
sender, sender,
address, address,
input, input,
@ -170,5 +170,5 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
cfg.Value, cfg.Value,
) )
return ret, err return ret, leftOverGas, err
} }

View file

@ -106,7 +106,7 @@ func TestCall(t *testing.T) {
byte(vm.RETURN), byte(vm.RETURN),
}) })
ret, err := Call(address, nil, &Config{State: state}) ret, _, err := Call(address, nil, &Config{State: state})
if err != nil { if err != nil {
t.Fatal("didn't expect error", err) t.Fatal("didn't expect error", err)
} }