Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
extract BinSearch function and add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
yihuang committed Jul 15, 2021
1 parent 5a46370 commit 5f674f9
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 16 deletions.
2 changes: 1 addition & 1 deletion client/docs/statik/statik.go

Large diffs are not rendered by default.

19 changes: 4 additions & 15 deletions ethereum/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,22 +643,11 @@ func (e *PublicAPI) EstimateGas(args evmtypes.CallArgs, blockNrOptional *rpctype
}

// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
failed, _, err := executable(mid)

// If the error is not nil(consensus error), it means the provided message
// call or transaction will never be accepted no matter how much gas it is
// assigned. Return the error directly, don't struggle any more.
if err != nil {
return 0, err
}
if failed {
lo = mid
} else {
hi = mid
}
hi, err := evmtypes.BinSearch(lo, hi, executable)
if err != nil {
return 0, err
}

// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
failed, result, err := executable(hi)
Expand Down
21 changes: 21 additions & 0 deletions x/evm/types/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,24 @@ func UnwrapEthereumMsg(tx *sdk.Tx) (*MsgEthereumTx, error) {

return msg, nil
}

// BinSearch execute the binary search and hone in on an executable gas limit
func BinSearch(lo uint64, hi uint64, executable func(uint64) (bool, *MsgEthereumTxResponse, error)) (uint64, error) {
for lo+1 < hi {
mid := (hi + lo) / 2
failed, _, err := executable(mid)

// If the error is not nil(consensus error), it means the provided message
// call or transaction will never be accepted no matter how much gas it is
// assigned. Return the error directly, don't struggle any more.
if err != nil {
return 0, err
}
if failed {
lo = mid
} else {
hi = mid
}
}
return hi, nil
}
19 changes: 19 additions & 0 deletions x/evm/types/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package types_test

import (
"errors"
"math/big"
"testing"

Expand Down Expand Up @@ -79,3 +80,21 @@ func TestUnwrapEthererumMsg(t *testing.T) {
require.Nil(t, err)
require.Equal(t, msg_, msg)
}

func TestBinSearch(t *testing.T) {
success_executable := func(gas uint64) (bool, *evmtypes.MsgEthereumTxResponse, error) {
target := uint64(21000)
return gas < target, nil, nil
}
failed_executable := func(gas uint64) (bool, *evmtypes.MsgEthereumTxResponse, error) {
return true, nil, errors.New("contract failed")
}

gas, err := evmtypes.BinSearch(20000, 21001, success_executable)
require.NoError(t, err)
require.Equal(t, gas, uint64(21000))

gas, err = evmtypes.BinSearch(20000, 21001, failed_executable)
require.Error(t, err)
require.Equal(t, gas, uint64(0))
}

0 comments on commit 5f674f9

Please sign in to comment.