Fix eth_estimateGas and simulated txs (#142)

This commit is contained in:
Austin Abell 2019-11-04 11:59:16 -05:00 committed by GitHub
parent 3ad2bb1de1
commit 42227a1b8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 18 deletions

View File

@ -374,7 +374,10 @@ type account struct {
// DoCall performs a simulated call operation through the evm
func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasCap *big.Int) (sdk.Result, error) {
// Set height for historical queries
ctx := e.cliCtx.WithHeight(blockNr.Int64())
ctx := e.cliCtx
if blockNr.Int64() != 0 {
ctx = e.cliCtx.WithHeight(blockNr.Int64())
}
// Set sender address or use a default if none specified
var addr common.Address
@ -452,13 +455,14 @@ func (e *PublicEthAPI) doCall(args CallArgs, blockNr rpc.BlockNumber, globalGasC
}
// EstimateGas estimates gas usage for the given smart contract call.
func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) {
result, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit))
func (e *PublicEthAPI) EstimateGas(args CallArgs) (hexutil.Uint64, error) {
result, err := e.doCall(args, 0, big.NewInt(emint.DefaultRPCGasLimit))
if err != nil {
return 0, err
}
return hexutil.Uint64(result.GasUsed), nil
// TODO: change 1000 buffer for more accurate buffer (must be at least 1 to not run OOG)
return hexutil.Uint64(result.GasUsed + 1000), nil
}
// GetBlockByHash returns the block identified by hash.
@ -916,7 +920,7 @@ func (e *PublicEthAPI) GenerateFromArgs(args params.SendTxArgs) (msg *types.Ethe
Value: args.Value,
Data: args.Data,
}
g, _ := e.EstimateGas(callArgs, rpc.BlockNumber(e.cliCtx.Height))
g, _ := e.EstimateGas(callArgs)
gasLimit = uint64(g)
} else {
gasLimit = (uint64)(*args.Gas)

View File

@ -44,13 +44,19 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
// This gas limit the the transaction gas limit with intrinsic gas subtracted
gasLimit := st.GasLimit - ctx.GasMeter().GasConsumed()
var snapshot int
csdb := st.Csdb
if st.Simulate {
// gasLimit is set here because stdTxs incur gaskv charges in the ante handler, but for eth_call
// the cost needs to be the same as an Ethereum transaction sent through the web3 API
consumedGas := ctx.GasMeter().GasConsumed()
gasLimit = st.GasLimit - cost
if consumedGas < cost {
// If Cosmos standard tx ante handler cost is less than EVM intrinsic cost
// gas must be consumed to match to accurately simulate an Ethereum transaction
ctx.GasMeter().ConsumeGas(cost-consumedGas, "Intrinsic gas match")
}
snapshot = st.Csdb.Snapshot()
csdb = st.Csdb.Copy()
}
// Create context for evm
@ -70,7 +76,7 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
evmGasMeter := sdk.NewInfiniteGasMeter()
vmenv := vm.NewEVM(
context, st.Csdb.WithContext(ctx.WithGasMeter(evmGasMeter)),
context, csdb.WithContext(ctx.WithGasMeter(evmGasMeter)),
GenerateChainConfig(st.ChainID), vm.Config{},
)
@ -86,15 +92,15 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
ret, addr, leftOverGas, vmerr = vmenv.Create(senderRef, st.Payload, gasLimit, st.Amount)
} else {
// Increment the nonce for the next transaction
st.Csdb.SetNonce(st.Sender, st.Csdb.GetNonce(st.Sender)+1)
csdb.SetNonce(st.Sender, csdb.GetNonce(st.Sender)+1)
ret, leftOverGas, vmerr = vmenv.Call(senderRef, *st.Recipient, st.Payload, gasLimit, st.Amount)
}
// Generate bloom filter to be saved in tx receipt data
bloomInt := big.NewInt(0)
var bloomFilter ethtypes.Bloom
if st.THash != nil {
logs := st.Csdb.GetLogs(*st.THash)
if st.THash != nil && !st.Simulate {
logs := csdb.GetLogs(*st.THash)
bloomInt = ethtypes.LogsBloom(logs)
bloomFilter = ethtypes.BytesToBloom(bloomInt.Bytes())
}
@ -114,13 +120,11 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
return nil, res
}
if st.Simulate {
st.Csdb.RevertToSnapshot(snapshot)
}
// TODO: Refund unused gas here, if intended in future
st.Csdb.Finalise(true) // Change to depend on config
if !st.Simulate {
// Finalise state if not a simulated transaction
st.Csdb.Finalise(true) // Change to depend on config
}
// Consume gas from evm execution
// Out of gas check does not need to be done here since it is done within the EVM execution

View File

@ -571,7 +571,7 @@ func (csdb *CommitStateDB) CreateAccount(addr ethcmn.Address) {
// Copy creates a deep, independent copy of the state.
//
// NOTE: Snapshots of the copied state cannot be applied to the copy.
func (csdb *CommitStateDB) Copy() ethvm.StateDB {
func (csdb *CommitStateDB) Copy() *CommitStateDB {
csdb.lock.Lock()
defer csdb.lock.Unlock()