From 984c25ac406e86255b289a3d7fec4cd91a17707f Mon Sep 17 00:00:00 2001 From: gary rong Date: Tue, 14 Nov 2017 10:26:31 -0600 Subject: accounts, internal: fail if no suitable estimated gas found (#15477) * accounts, internal: return an error if no suitable estimated gas found * accounts, internal: minor polishes on the gas estimator --- internal/ethapi/api.go | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1ffb5a180..59a29d722 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -649,12 +649,14 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr r return (hexutil.Bytes)(result), err } -// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. +// EstimateGas returns an estimate of the amount of gas needed to execute the +// given transaction against the current pending block. func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { - // Binary search the gas requirement, as it may be higher than the amount used + // Determine the lowest and highest possible gas limits to binary search in between var ( - lo uint64 = params.TxGas - 1 - hi uint64 + lo uint64 = params.TxGas - 1 + hi uint64 + cap uint64 ) if (*big.Int)(&args.Gas).Uint64() >= params.TxGas { hi = (*big.Int)(&args.Gas).Uint64() @@ -666,20 +668,31 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* } hi = block.GasLimit().Uint64() } - for lo+1 < hi { - // Take a guess at the gas, and check transaction validity - mid := (hi + lo) / 2 - (*big.Int)(&args.Gas).SetUint64(mid) + cap = hi + // Create a helper to check if a gas allowance results in an executable transaction + executable := func(gas uint64) bool { + (*big.Int)(&args.Gas).SetUint64(gas) _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) - - // If the transaction became invalid or execution failed, raise the gas limit if err != nil || failed { + return false + } + return true + } + // Execute the binary search and hone in on an executable gas limit + for lo+1 < hi { + mid := (hi + lo) / 2 + if !executable(mid) { lo = mid - continue + } else { + hi = mid + } + } + // Reject the transaction as invalid if it still fails at the highest allowance + if hi == cap { + if !executable(hi) { + return nil, fmt.Errorf("gas required exceeds allowance or always failing transaction") } - // Otherwise assume the transaction succeeded, lower the gas limit - hi = mid } return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil } -- cgit v1.2.3 From b0190189a386d13eb2e8bbdb6d64d9ef8c0e572a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 16 Nov 2017 18:53:18 +0200 Subject: core/vm, internal/ethapi: tracer no full storage, nicer json output (#15499) * core/vm, internal/ethapi: tracer no full storage, nicer json output * core/vm, internal/ethapi: omit disabled trace fields --- internal/ethapi/api.go | 57 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 59a29d722..cf15d1c71 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -710,45 +710,52 @@ type ExecutionResult struct { // StructLogRes stores a structured log emitted by the EVM while replaying a // transaction in debug mode type StructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth int `json:"depth"` - Error error `json:"error"` - Stack []string `json:"stack"` - Memory []string `json:"memory"` - Storage map[string]string `json:"storage"` + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error error `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` } // formatLogs formats EVM returned structured logs for json output -func FormatLogs(structLogs []vm.StructLog) []StructLogRes { - formattedStructLogs := make([]StructLogRes, len(structLogs)) - for index, trace := range structLogs { - formattedStructLogs[index] = StructLogRes{ +func FormatLogs(logs []vm.StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ Pc: trace.Pc, Op: trace.Op.String(), Gas: trace.Gas, GasCost: trace.GasCost, Depth: trace.Depth, Error: trace.Err, - Stack: make([]string, len(trace.Stack)), - Storage: make(map[string]string), } - - for i, stackValue := range trace.Stack { - formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + } + formatted[index].Stack = &stack } - - for i := 0; i+32 <= len(trace.Memory); i += 32 { - formattedStructLogs[index].Memory = append(formattedStructLogs[index].Memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory } - - for i, storageValue := range trace.Storage { - formattedStructLogs[index].Storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage } } - return formattedStructLogs + return formatted } // rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are -- cgit v1.2.3 From c7b0abf86bf3039a87b5b5ae88635326a762cf31 Mon Sep 17 00:00:00 2001 From: tsarpaul Date: Fri, 17 Nov 2017 15:07:57 +0200 Subject: Added output to clarify gas calculation in txpool.inspect --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cf15d1c71..025f42617 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -151,9 +151,9 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string { // Define a formatter to flatten a transaction into a string var format = func(tx *types.Transaction) string { if to := tx.To(); to != nil { - return fmt.Sprintf("%s: %v wei + %v × %v gas", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) + return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) } - return fmt.Sprintf("contract creation: %v wei + %v × %v gas", tx.Value(), tx.Gas(), tx.GasPrice()) + return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value(), tx.Gas(), tx.GasPrice()) } // Flatten the pending transactions for account, txs := range pending { -- cgit v1.2.3 From bbea4b2b53be53fc07b620c426bda80732a8814b Mon Sep 17 00:00:00 2001 From: yoza Date: Wed, 13 Dec 2017 02:55:39 +0900 Subject: internal/ethapi: fix typo in comment (#15659) --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 025f42617..fe0ed8170 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1071,7 +1071,7 @@ type SendTxArgs struct { Nonce *hexutil.Uint64 `json:"nonce"` } -// prepareSendTxArgs is a helper function that fills in default values for unspecified tx fields. +// setDefaults is a helper function that fills in default values for unspecified tx fields. func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { args.Gas = (*hexutil.Big)(big.NewInt(defaultGas)) -- cgit v1.2.3 From e9971d356bf977d2a3f63e50296d7410ade2d075 Mon Sep 17 00:00:00 2001 From: rhaps107 Date: Thu, 14 Dec 2017 15:24:34 +0300 Subject: internal/ethapi: don't crash for missing receipts Fixes #15408 Fixes #14432 --- internal/ethapi/api.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index fe0ed8170..76a7306e4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1003,9 +1003,12 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash) if tx == nil { - return nil, nil + return nil, errors.New("unknown transaction") } receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available + if receipt == nil { + return nil, errors.New("unknown receipt") + } var signer types.Signer = types.FrontierSigner{} if tx.Protected() { -- cgit v1.2.3 From 8c33ac10bff32d082facfd274188334a3236a4e7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 18 Dec 2017 12:50:21 +0100 Subject: internal/ethapi: support "input" in transaction args (#15640) The tx data field is called "input" in returned objects and "data" in argument objects. Make it so "input" can be used, but bail if both are set. --- internal/ethapi/api.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'internal/ethapi/api.go') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 76a7306e4..d07b2e693 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -17,6 +17,7 @@ package ethapi import ( + "bytes" "context" "errors" "fmt" @@ -1070,8 +1071,11 @@ type SendTxArgs struct { Gas *hexutil.Big `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` Value *hexutil.Big `json:"value"` - Data hexutil.Bytes `json:"data"` Nonce *hexutil.Uint64 `json:"nonce"` + // We accept "data" and "input" for backwards-compatibility reasons. "input" is the + // newer name and should be preferred by clients. + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input"` } // setDefaults is a helper function that fills in default values for unspecified tx fields. @@ -1096,14 +1100,23 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { } args.Nonce = (*hexutil.Uint64)(&nonce) } + if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { + return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`) + } return nil } func (args *SendTxArgs) toTransaction() *types.Transaction { + var input []byte + if args.Data != nil { + input = *args.Data + } else if args.Input != nil { + input = *args.Input + } if args.To == nil { - return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) + return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input) } - return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input) } // submitTransaction is a helper function that submits tx to txPool and logs a message. -- cgit v1.2.3