Skip to content

Commit

Permalink
precompiled: adjust the gas cost of consortium precompiled contract
Browse files Browse the repository at this point in the history
This commit adds the benchmarks and calculated gas cost from the benchmarks to
validator sorting, pick validator set and verify double sign proof precompiled
contracts. Ethereum aims for 30 mgas/s when setting gas cost for precompiled
contracts, we aims for 60 mgas/s.

Benchmark results:

BenchmarkConsortiumValidatorSorting/validator-sort-Gas=2310-8             548737             20101 ns/op              2310 gas/op              114.9 mgas/s        11616 B/op        224 allocs/op
BenchmarkConsortiumValidatorSorting/validator-sort-Gas=9780-8             205410             66083 ns/op              9780 gas/op              148.0 mgas/s        49280 B/op        852 allocs/op
BenchmarkConsortiumVerifyHeaders/verify-headers-Gas=21000-8                48445            232612 ns/op             21000 gas/op               90.27 mgas/s       53043 B/op        477 allocs/op
BenchmarkConsortiumPickValidatorSet/pick-validator-set-Gas=3540-8         377305             32748 ns/op              3540 gas/op              108.1 mgas/s        19775 B/op        299 allocs/op
BenchmarkConsortiumPickValidatorSet/pick-validator-set-Gas=14790-8        113479            129076 ns/op             14790 gas/op              114.6 mgas/s        76689 B/op       1092 allocs/op
  • Loading branch information
minh-bq committed Nov 30, 2023
1 parent 910efae commit ea76b97
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 30 deletions.
85 changes: 60 additions & 25 deletions core/vm/consortium_precompiled_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,28 @@ type consortiumPickValidatorSet struct {
evm *EVM
}

func (c *consortiumPickValidatorSet) RequiredGas(_ []byte) uint64 {
return 0
func (c *consortiumPickValidatorSet) RequiredGas(input []byte) uint64 {
// c.evm is nil in benchmark
if c.evm == nil || c.evm.chainRules.IsMiko {
// We approximate the number of validators by dividing the length of input by
// length of address (20). This is likely an overestimation because there are
// slices of weight, maxValidatorNumber and maxPrioritizedValidatorNumber in
// the input too.
return uint64((len(input) / common.AddressLength)) * params.ValidatorSortingBaseGas
} else {
return 0
}
}

func (c *consortiumPickValidatorSet) Run(input []byte) ([]byte, error) {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
// These 2 fields are nil in benchmark only
if c.caller != nil && c.evm != nil {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
}
}
// get method, args from abi
_, method, args, err := loadMethodAndArgs(PickValidatorSet, input)
Expand Down Expand Up @@ -248,16 +260,27 @@ type consortiumValidatorSorting struct {
evm *EVM
}

func (c *consortiumValidatorSorting) RequiredGas(_ []byte) uint64 {
return 0
func (c *consortiumValidatorSorting) RequiredGas(input []byte) uint64 {
// c.evm is nil in benchmark
if c.evm == nil || c.evm.chainRules.IsMiko {
// We approximate the number of validators by dividing the length of input by
// length of address (20). This is likely an overestimation because there is
// a slice of weight in the input too.
return uint64((len(input) / common.AddressLength)) * params.ValidatorSortingBaseGas
} else {
return 0
}
}

func (c *consortiumValidatorSorting) Run(input []byte) ([]byte, error) {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
// These 2 fields are nil in benchmark only
if c.caller != nil && c.evm != nil {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
}
}
// get method, args from abi
_, method, args, err := loadMethodAndArgs(SortValidator, input)
Expand Down Expand Up @@ -401,15 +424,23 @@ type consortiumVerifyHeaders struct {
}

func (c *consortiumVerifyHeaders) RequiredGas(_ []byte) uint64 {
return 0
// c.evm is nil in benchmark
if c.evm == nil || c.evm.chainRules.IsMiko {
return params.VerifyFinalityHeadersProofGas
} else {
return 0
}
}

func (c *consortiumVerifyHeaders) Run(input []byte) ([]byte, error) {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
// These 2 fields are nil in benchmark only
if c.caller != nil && c.evm != nil {
if c.evm.ChainConfig().ConsortiumV2Contracts == nil {
return nil, errors.New("cannot find consortium v2 contracts")
}
if !c.evm.ChainConfig().ConsortiumV2Contracts.IsSystemContract(c.caller.Address()) {
return nil, errors.New("unauthorized sender")
}
}
// get method, args from abi
smcAbi, method, args, err := loadMethodAndArgs(VerifyHeaders, input)
Expand Down Expand Up @@ -475,7 +506,8 @@ func (c *consortiumVerifyHeaders) getSigner(header types.BlockHeader) (common.Ad
func (c *consortiumVerifyHeaders) verify(consensusAddr common.Address, header1, header2 types.BlockHeader) bool {
var maxOffset *big.Int

if !c.evm.chainConfig.IsConsortiumV2(header1.Number) {
// c.evm s nil in benchmark, so we skip this check in benchmark
if c.evm != nil && !c.evm.chainConfig.IsConsortiumV2(header1.Number) {
return false
}
if header1.ToHeader().ParentHash.Hex() != header2.ToHeader().ParentHash.Hex() {
Expand Down Expand Up @@ -527,10 +559,13 @@ func (c *consortiumVerifyHeaders) verify(consensusAddr common.Address, header1,
}
}

currentBlock := c.evm.Context.BlockNumber
// What if current block < header1.Number?
if currentBlock.Cmp(header1.Number) > 0 && new(big.Int).Sub(currentBlock, header1.Number).Cmp(maxOffset) > 0 {
return false
// c.evm is nil in benchmark, so we skip this check in benchmark
if c.evm != nil {
currentBlock := c.evm.Context.BlockNumber
// What if current block < header1.Number?
if currentBlock.Cmp(header1.Number) > 0 && new(big.Int).Sub(currentBlock, header1.Number).Cmp(maxOffset) > 0 {
return false
}
}

return signer1.Hex() == signer2.Hex() &&
Expand Down
Loading

0 comments on commit ea76b97

Please sign in to comment.