Skip to content

Commit

Permalink
expand gas cost interface, limit number of addresses for hasQuorum
Browse files Browse the repository at this point in the history
  • Loading branch information
igorcrevar committed Mar 6, 2024
1 parent f486ac4 commit 9696d4f
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 23 deletions.
14 changes: 14 additions & 0 deletions consensus/polybft/polybft.go
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,20 @@ func (p *Polybft) GetLatestChainConfig() (*chain.Params, error) {
return nil, nil
}

func (p *Polybft) GetMaxValidatorSetSize() (uint64, error) {
params, err := p.GetLatestChainConfig()
if err != nil {
return 0, err
}

polyBFTConfig, err := GetPolyBFTConfig(params)
if err != nil {
return 0, err
}

return polyBFTConfig.MaxValidatorSetSize, nil
}

// GetBridgeProvider is an implementation of Consensus interface
// Returns an instance of BridgeDataProvider
func (p *Polybft) GetBridgeProvider() consensus.BridgeDataProvider {
Expand Down
8 changes: 4 additions & 4 deletions state/runtime/precompiled/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type ecrecover struct {
p *Precompiled
}

func (e *ecrecover) gas(input []byte, config *chain.ForksInTime) uint64 {
func (e *ecrecover) gas(_ []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return 3000
}

Expand Down Expand Up @@ -57,7 +57,7 @@ func (e *ecrecover) run(input []byte, caller types.Address, _ runtime.Host) ([]b
type identity struct {
}

func (i *identity) gas(input []byte, config *chain.ForksInTime) uint64 {
func (i *identity) gas(input []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return baseGasCalc(input, 15, 3)
}

Expand All @@ -68,7 +68,7 @@ func (i *identity) run(input []byte, _ types.Address, _ runtime.Host) ([]byte, e
type sha256h struct {
}

func (s *sha256h) gas(input []byte, config *chain.ForksInTime) uint64 {
func (s *sha256h) gas(input []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return baseGasCalc(input, 60, 12)
}

Expand All @@ -82,7 +82,7 @@ type ripemd160h struct {
p *Precompiled
}

func (r *ripemd160h) gas(input []byte, config *chain.ForksInTime) uint64 {
func (r *ripemd160h) gas(input []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return baseGasCalc(input, 600, 120)
}

Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func testPrecompiled(t *testing.T, p contract, cases []precompiledTest, enabledF
h, _ := hex.DecodeString(c.Input)

if c.Gas != 0 && len(enabledForks) > 0 {
gas := p.gas(h, enabledForks[0])
gas := p.gas(h, types.Address{}, enabledForks[0])
assert.Equal(t, c.Gas, gas, "Incorrect gas estimation")
}

Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/blake2f.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type blake2f struct {
p *Precompiled
}

func (e *blake2f) gas(input []byte, config *chain.ForksInTime) uint64 {
func (e *blake2f) gas(input []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
if len(input) != 213 {
return 0
}
Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/bls_agg_sigs_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type blsAggSignsVerification struct {
}

// gas returns the gas required to execute the pre-compiled contract
func (c *blsAggSignsVerification) gas(input []byte, _ *chain.ForksInTime) uint64 {
func (c *blsAggSignsVerification) gas(_ []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return 150000
}

Expand Down
6 changes: 3 additions & 3 deletions state/runtime/precompiled/bn256.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type bn256Add struct {
p *Precompiled
}

func (b *bn256Add) gas(input []byte, config *chain.ForksInTime) uint64 {
func (b *bn256Add) gas(_ []byte, _ types.Address, config *chain.ForksInTime) uint64 {
if config.Istanbul {
return 150
}
Expand Down Expand Up @@ -48,7 +48,7 @@ type bn256Mul struct {
p *Precompiled
}

func (b *bn256Mul) gas(input []byte, config *chain.ForksInTime) uint64 {
func (b *bn256Mul) gas(_ []byte, _ types.Address, config *chain.ForksInTime) uint64 {
if config.Istanbul {
return 6000
}
Expand Down Expand Up @@ -79,7 +79,7 @@ type bn256Pairing struct {
p *Precompiled
}

func (b *bn256Pairing) gas(input []byte, config *chain.ForksInTime) uint64 {
func (b *bn256Pairing) gas(input []byte, _ types.Address, config *chain.ForksInTime) uint64 {
baseGas, pointGas := uint64(100000), uint64(80000)
if config.Istanbul {
baseGas, pointGas = 45000, 34000
Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/modexp.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func multComplexity(x *big.Int) *big.Int {
return x
}

func (m *modExp) gas(input []byte, config *chain.ForksInTime) uint64 {
func (m *modExp) gas(input []byte, _ types.Address, config *chain.ForksInTime) uint64 {
var val, tail []byte

val, tail = m.p.get(input, 32)
Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/native_transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

type nativeTransfer struct{}

func (c *nativeTransfer) gas(input []byte, _ *chain.ForksInTime) uint64 {
func (c *nativeTransfer) gas(_ []byte, _ types.Address, _ *chain.ForksInTime) uint64 {
return 21000
}

Expand Down
4 changes: 2 additions & 2 deletions state/runtime/precompiled/precompiled.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func init() {
}

type contract interface {
gas(input []byte, config *chain.ForksInTime) uint64
gas(input []byte, caller types.Address, config *chain.ForksInTime) uint64
run(input []byte, caller types.Address, host runtime.Host) ([]byte, error)
}

Expand Down Expand Up @@ -139,7 +139,7 @@ func (p *Precompiled) Name() string {
// Run runs an execution
func (p *Precompiled) Run(c *runtime.Contract, host runtime.Host, config *chain.ForksInTime) *runtime.ExecutionResult {
contract := p.contracts[c.CodeAddress]
gasCost := contract.gas(c.Input, config)
gasCost := contract.gas(c.Input, c.Caller, config)

// In the case of not enough gas for precompiled execution we return ErrOutOfGas
if c.Gas < gasCost {
Expand Down
25 changes: 21 additions & 4 deletions state/runtime/precompiled/validator_set_precompile.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import (
"github.com/hashicorp/go-hclog"
)

const addrOffset = 32 - types.AddressLength
const (
addrOffset = 32 - types.AddressLength
defaultMaxHasQuorumAddresses = 100
)

var (
errValidatorSetPrecompileNotEnabled = errors.New("validator set precompile is not enabled")
Expand All @@ -22,6 +25,7 @@ var (
// responsible for retrieving validators (current account set) for a specific block number
type ValidatorSetPrecompileBackend interface {
GetValidatorsForBlock(blockNumber uint64) (validator.AccountSet, error)
GetMaxValidatorSetSize() (uint64, error)
}

// validatorSetPrecompile is a concrete implementation of the contract interface.
Expand All @@ -34,7 +38,7 @@ type validatorSetPrecompile struct {
}

// gas returns the gas required to execute the pre-compiled contract
func (c *validatorSetPrecompile) gas(input []byte, _ *chain.ForksInTime) uint64 {
func (c *validatorSetPrecompile) gas(_ []byte, _ types.Address, config *chain.ForksInTime) uint64 {
return 240000
}

Expand Down Expand Up @@ -67,7 +71,16 @@ func (c *validatorSetPrecompile) run(input []byte, caller types.Address, host ru
return abiBoolFalse, nil
}

addresses, err := abiDecodeAddresses(input)
maxAddressesCount, err := c.backend.GetMaxValidatorSetSize()
if err != nil {
return nil, err
}

if maxAddressesCount == 0 {
maxAddressesCount = defaultMaxHasQuorumAddresses
}

addresses, err := abiDecodeAddresses(input, uint32(maxAddressesCount))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -102,7 +115,7 @@ func createValidatorSet(blockNumber uint64, backend ValidatorSetPrecompileBacken
return validator.NewValidatorSet(accounts, hclog.NewNullLogger()), nil
}

func abiDecodeAddresses(input []byte) ([]types.Address, error) {
func abiDecodeAddresses(input []byte, maxCount uint32) ([]types.Address, error) {
if len(input) < 64 || len(input)%32 != 0 {
return nil, runtime.ErrInvalidInputData
}
Expand All @@ -122,6 +135,10 @@ func abiDecodeAddresses(input []byte) ([]types.Address, error) {
if uint32(len(input)) != size*32+64 {
return nil, runtime.ErrInvalidInputData
}
// sanitize the input if it contains too many addresses.
if maxCount != 0 && size > maxCount {
return nil, runtime.ErrInvalidInputData
}

res := make([]types.Address, size)
for i, offset := 0, 64; offset < len(input); i, offset = i+1, offset+32 {
Expand Down
18 changes: 13 additions & 5 deletions state/runtime/precompiled/validator_set_precompile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
)

func Test_ValidatorSetPrecompile_gas(t *testing.T) {
assert.Equal(t, uint64(240000), (&validatorSetPrecompile{}).gas(nil, nil))
assert.Equal(t, uint64(240000), (&validatorSetPrecompile{}).gas(nil, types.Address{}, nil))
}

func Test_ValidatorSetPrecompile_run_BackendNotSet(t *testing.T) {
Expand Down Expand Up @@ -101,6 +101,8 @@ func Test_ValidatorSetPrecompile_run_HasQuorum(t *testing.T) {
backendMock := &validatorSetBackendMock{}

backendMock.On("GetValidatorsForBlock", uint64(host.context.Number)).Return(accounts, error(nil))
backendMock.On("GetMaxValidatorSetSize").Return(uint64(100), error(nil)).Twice()
backendMock.On("GetMaxValidatorSetSize").Return(uint64(0), error(nil)).Once()

p := &validatorSetPrecompile{
backend: backendMock,
Expand All @@ -127,16 +129,16 @@ func Test_abiDecodeAddresses_Error(t *testing.T) {
dummy4[31] = 32
dummy4[63] = 10

_, err := abiDecodeAddresses(dummy1[:])
_, err := abiDecodeAddresses(dummy1[:], 0)
require.ErrorIs(t, err, runtime.ErrInvalidInputData)

_, err = abiDecodeAddresses(dummy2[:])
_, err = abiDecodeAddresses(dummy2[:], 0)
require.ErrorIs(t, err, runtime.ErrInvalidInputData)

_, err = abiDecodeAddresses(dummy3[:])
_, err = abiDecodeAddresses(dummy3[:], 0)
require.ErrorIs(t, err, runtime.ErrInvalidInputData)

_, err = abiDecodeAddresses(dummy4[:])
_, err = abiDecodeAddresses(dummy4[:], 0)
require.ErrorIs(t, err, runtime.ErrInvalidInputData)
}

Expand All @@ -150,6 +152,12 @@ func (m *validatorSetBackendMock) GetValidatorsForBlock(blockNumber uint64) (val
return call.Get(0).(validator.AccountSet), call.Error(1)
}

func (m *validatorSetBackendMock) GetMaxValidatorSetSize() (uint64, error) {
call := m.Called()

return call.Get(0).(uint64), call.Error(1)
}

func getDummyAccountSet() validator.AccountSet {
v, _ := new(big.Int).SetString("1000000000000000000000", 10)

Expand Down

0 comments on commit 9696d4f

Please sign in to comment.