Skip to content

Commit

Permalink
core/vm: fix incorrect computation of BLS discount (#21253)
Browse files Browse the repository at this point in the history
* core/vm: fix incorrect computation of discount

During testing on Yolov1 we found that the way geth calculates the discount
is not in line with the specification. Basically what we did is calculate
128 * Bls12381GXMulGas * discount / 1000 whenever we received more than 128 pairs
of values. Correct would be to calculate k * Bls12381... for k > 128.

* core/vm: better logic for discount calculation

* core/vm: better calculation logic, added worstcase benchmarks

* core/vm: better benchmarking logic
  • Loading branch information
MariusVanDerWijden authored Jun 24, 2020
1 parent b482423 commit 0c82928
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 8 deletions.
18 changes: 10 additions & 8 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,11 +620,12 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
return 0
}
// Lookup discount value for G1 point, scalar value pair length
maxDiscountLen := len(params.Bls12381MultiExpDiscountTable)
if k > maxDiscountLen {
k = maxDiscountLen
var discount uint64
if dLen := len(params.Bls12381MultiExpDiscountTable); k < dLen {
discount = params.Bls12381MultiExpDiscountTable[k-1]
} else {
discount = params.Bls12381MultiExpDiscountTable[dLen-1]
}
discount := params.Bls12381MultiExpDiscountTable[k-1]
// Calculate gas and return the result
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
}
Expand Down Expand Up @@ -750,11 +751,12 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
return 0
}
// Lookup discount value for G2 point, scalar value pair length
maxDiscountLen := len(params.Bls12381MultiExpDiscountTable)
if k > maxDiscountLen {
k = maxDiscountLen
var discount uint64
if dLen := len(params.Bls12381MultiExpDiscountTable); k < dLen {
discount = params.Bls12381MultiExpDiscountTable[k-1]
} else {
discount = params.Bls12381MultiExpDiscountTable[dLen-1]
}
discount := params.Bls12381MultiExpDiscountTable[k-1]
// Calculate gas and return the result
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
}
Expand Down
47 changes: 47 additions & 0 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"io/ioutil"
"math/big"
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
)
Expand Down Expand Up @@ -142,14 +143,21 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {

bench.Run(fmt.Sprintf("%s-Gas=%d", test.Name, contract.Gas), func(bench *testing.B) {
bench.ReportAllocs()
start := time.Now().Nanosecond()
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
contract.Gas = reqGas
copy(data, in)
res, err = RunPrecompiledContract(p, data, contract)
}
bench.StopTimer()
elapsed := float64(time.Now().Nanosecond() - start)
if elapsed < 1 {
elapsed = 1
}
gasUsed := reqGas * uint64(bench.N)
bench.ReportMetric(float64(reqGas), "gas/op")
bench.ReportMetric(float64(gasUsed*1000)/elapsed, "mgas/s")
//Check if it is correct
if err != nil {
bench.Error(err)
Expand Down Expand Up @@ -320,3 +328,42 @@ func loadJsonFail(name string) ([]precompiledFailureTest, error) {
err = json.Unmarshal(data, &testcases)
return testcases, err
}

// BenchmarkPrecompiledBLS12381G1MultiExpWorstCase benchmarks the worst case we could find that still fits a gaslimit of 10MGas.
func BenchmarkPrecompiledBLS12381G1MultiExpWorstCase(b *testing.B) {
task := "0000000000000000000000000000000008d8c4a16fb9d8800cce987c0eadbb6b3b005c213d44ecb5adeed713bae79d606041406df26169c35df63cf972c94be1" +
"0000000000000000000000000000000011bc8afe71676e6730702a46ef817060249cd06cd82e6981085012ff6d013aa4470ba3a2c71e13ef653e1e223d1ccfe9" +
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
input := task
for i := 0; i < 4787; i++ {
input = input + task
}
testcase := precompiledTest{
Input: input,
Expected: "0000000000000000000000000000000005a6310ea6f2a598023ae48819afc292b4dfcb40aabad24a0c2cb6c19769465691859eeb2a764342a810c5038d700f18000000000000000000000000000000001268ac944437d15923dc0aec00daa9250252e43e4b35ec7a19d01f0d6cd27f6e139d80dae16ba1c79cc7f57055a93ff5",
Name: "WorstCaseG1",
NoBenchmark: false,
}
benchmarkPrecompiled("0c", testcase, b)
}

// BenchmarkPrecompiledBLS12381G2MultiExpWorstCase benchmarks the worst case we could find that still fits a gaslimit of 10MGas.
func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
task := "000000000000000000000000000000000d4f09acd5f362e0a516d4c13c5e2f504d9bd49fdfb6d8b7a7ab35a02c391c8112b03270d5d9eefe9b659dd27601d18f" +
"000000000000000000000000000000000fd489cb75945f3b5ebb1c0e326d59602934c8f78fe9294a8877e7aeb95de5addde0cb7ab53674df8b2cfbb036b30b99" +
"00000000000000000000000000000000055dbc4eca768714e098bbe9c71cf54b40f51c26e95808ee79225a87fb6fa1415178db47f02d856fea56a752d185f86b" +
"000000000000000000000000000000001239b7640f416eb6e921fe47f7501d504fadc190d9cf4e89ae2b717276739a2f4ee9f637c35e23c480df029fd8d247c7" +
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
input := task
for i := 0; i < 1040; i++ {
input = input + task
}

testcase := precompiledTest{
Input: input,
Expected: "0000000000000000000000000000000018f5ea0c8b086095cfe23f6bb1d90d45de929292006dba8cdedd6d3203af3c6bbfd592e93ecb2b2c81004961fdcbb46c00000000000000000000000000000000076873199175664f1b6493a43c02234f49dc66f077d3007823e0343ad92e30bd7dc209013435ca9f197aca44d88e9dac000000000000000000000000000000000e6f07f4b23b511eac1e2682a0fc224c15d80e122a3e222d00a41fab15eba645a700b9ae84f331ae4ed873678e2e6c9b000000000000000000000000000000000bcb4849e460612aaed79617255fd30c03f51cf03d2ed4163ca810c13e1954b1e8663157b957a601829bb272a4e6c7b8",
Name: "WorstCaseG2",
NoBenchmark: false,
}
benchmarkPrecompiled("0f", testcase, b)
}

0 comments on commit 0c82928

Please sign in to comment.