@ -18,6 +18,7 @@ import (
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/staking/network"
@ -635,6 +636,69 @@ func (s *PublicBlockChainAPI) GetDelegationByDelegatorAndValidator(ctx context.C
return nil , nil
}
// doEstimateGas ..
func doEstimateGas ( ctx context . Context , b Backend , args CallArgs , gasCap * big . Int ) ( hexutil . Uint64 , error ) {
// Binary search the gas requirement, as it may be higher than the amount used
var (
lo uint64 = params . TxGas - 1
hi uint64
cap uint64
)
blockNum := rpc . LatestBlockNumber
if args . Gas != nil && uint64 ( * args . Gas ) >= params . TxGas {
hi = uint64 ( * args . Gas )
} else {
// Retrieve the block to act as the gas ceiling
block , err := b . BlockByNumber ( ctx , blockNum )
if err != nil {
return 0 , err
}
hi = block . GasLimit ( )
}
if gasCap != nil && hi > gasCap . Uint64 ( ) {
// log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap . Uint64 ( )
}
cap = hi
// Use zero-address if none other is available
if args . From == nil {
args . From = & common . Address { }
}
// Create a helper to check if a gas allowance results in an executable transaction
executable := func ( gas uint64 ) bool {
args . Gas = ( * hexutil . Uint64 ) ( & gas )
_ , _ , failed , err := doCall ( ctx , b , args , blockNum , vm . Config { } , 0 , big . NewInt ( int64 ( cap ) ) )
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
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if ! executable ( hi ) {
return 0 , fmt . Errorf ( "gas required exceeds allowance (%d) or always failing transaction" , cap )
}
}
return hexutil . Uint64 ( hi ) , nil
}
// 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 . Uint64 , error ) {
return doEstimateGas ( ctx , s . b , args , nil )
}
// GetCurrentUtilityMetrics ..
func ( s * PublicBlockChainAPI ) GetCurrentUtilityMetrics ( ) ( * network . UtilityMetric , error ) {
if s . b . GetShardID ( ) == shard . BeaconChainShardID {