Skip to content

Commit

Permalink
Merge pull request #1886 from irisnet/vincent/gas-consume
Browse files Browse the repository at this point in the history
R4R: Decrease gas consumption by logarithm
  • Loading branch information
Haifeng Xi authored Aug 16, 2019
2 parents aaccde2 + c51043f commit 12c66db
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
17 changes: 8 additions & 9 deletions app/v1/auth/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import (
)

const (
BlockStoreCostPerByte = 10
ed25519VerifyCost = 59
secp256k1VerifyCost = 100
maxMemoCharacters = 100
// how much gas = 1 atom
gasPerUnitCost = 1000
// max total number of sigs per tx
txSigLimit = 7
ed25519VerifyCost = 59
secp256k1VerifyCost = 100

// if gas > gasShift, gas = log(gas)/log(gasBase)
// else gasConsumed = gas
gasBase = 1.02 // gas logarithm base
gasShift = 285 // gas logarithm shift
)

// NewAnteHandler returns an AnteHandler that checks
Expand Down Expand Up @@ -308,7 +307,7 @@ func setGasMeter(simulate bool, ctx sdk.Context, gasLimit uint64) sdk.Context {
if simulate || ctx.BlockHeight() == 0 {
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
}
return ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
return ctx.WithGasMeter(sdk.NewGasMeterWithBase(gasLimit, gasBase, gasShift))
}

func getSignBytesList(chainID string, stdTx StdTx, stdSigs []StdSignature) (signatureBytesList [][]byte) {
Expand Down
21 changes: 21 additions & 0 deletions types/gas.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package types

import (
"math"
)

// Gas consumption descriptors.
const (
GasIterNextCostFlatDesc = "IterNextFlat"
Expand Down Expand Up @@ -44,6 +48,8 @@ type GasMeter interface {
type basicGasMeter struct {
limit Gas
consumed Gas
base float64
shift uint64
}

// NewGasMeter returns a reference to a new basicGasMeter.
Expand All @@ -54,6 +60,15 @@ func NewGasMeter(limit Gas) GasMeter {
}
}

func NewGasMeterWithBase(limit Gas, base float64, shift uint64) GasMeter {
return &basicGasMeter{
limit: limit,
consumed: 0,
base: base,
shift: shift,
}
}

func (g *basicGasMeter) GasConsumed() Gas {
return g.consumed
}
Expand All @@ -70,6 +85,12 @@ func (g *basicGasMeter) GasConsumedToLimit() Gas {

func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
var overflow bool

// amount = log(gas)/log(gasBase)
if g.base > 1 && amount > g.shift && amount < math.MaxInt64 &&
(descriptor == GasWritePerByteDesc || descriptor == GasReadPerByteDesc) {
amount = uint64(math.Log(float64(int64(amount))) / math.Log(g.base))
}
// TODO: Should we set the consumed field after overflow checking?
g.consumed, overflow = AddUint64Overflow(g.consumed, amount)
if overflow {
Expand Down
31 changes: 31 additions & 0 deletions types/gas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,34 @@ func TestGasMeter(t *testing.T) {

}
}

func TestGasMeterWithLog(t *testing.T) {
cases := []struct {
limit Gas
usage Gas
base float64
shift uint64
desc string
expect Gas
}{
{1000, 100, 10, 0, GasWritePerByteDesc, 2},
{1000, 285, 1.02, 285, GasWritePerByteDesc, 285},
{1000, 286, 1.02, 285, GasWritePerByteDesc, 285},
{1000, 288, 1.02, 285, GasWritePerByteDesc, 285},
{1000, 289, 1.02, 285, GasWritePerByteDesc, 286},
{1000, 100, 10, 100, GasWritePerByteDesc, 100},
{1000, 100, 10, 0, GasReadPerByteDesc, 2},
{1000, 100, 10, 0, "", 100},
{1000, 100, 1, 0, GasWritePerByteDesc, 100},
{1000, 100, 0, 0, GasWritePerByteDesc, 100},
{1000, 100, 0.99, 0, GasWritePerByteDesc, 100},
{1000, 100, -0.1, 0, GasWritePerByteDesc, 100},
}

for tcnum, tc := range cases {
meter := NewGasMeterWithBase(tc.limit, tc.base, tc.shift)

meter.ConsumeGas(tc.usage, tc.desc)
require.Equal(t, tc.expect, meter.GasConsumed(), "Gas consumption not match. tc #%d", tcnum)
}
}

0 comments on commit 12c66db

Please sign in to comment.