Skip to content

Commit

Permalink
custom abi.(d)encode(address[])
Browse files Browse the repository at this point in the history
  • Loading branch information
igorcrevar committed Feb 15, 2024
1 parent 97f2dd4 commit fb5c095
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 32 deletions.
54 changes: 44 additions & 10 deletions state/runtime/precompiled/validator_set_precompile.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package precompiled

import (
"bytes"
"encoding/binary"
"errors"

"github.com/0xPolygon/polygon-edge/chain"
"github.com/0xPolygon/polygon-edge/consensus/polybft/validator"
"github.com/0xPolygon/polygon-edge/state/runtime"
"github.com/0xPolygon/polygon-edge/types"
"github.com/hashicorp/go-hclog"
"github.com/umbracle/ethgo"
"github.com/umbracle/ethgo/abi"
)

var (
hasQuorumAbiType = abi.MustNewType("address[]")

errValidatorSetPrecompileNotEnabled = errors.New("validator set precompile is not enabled")
)

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

rawData, err := abi.Decode(hasQuorumAbiType, input)
addresses, err := abiDecodeAddresses(input)
if err != nil {
return nil, err
}

addresses, ok := rawData.([]ethgo.Address)
if !ok {
return nil, errBLSVerifyAggSignsInputs
}

validatorSet, err := createValidatorSet(host, c.backend)
if err != nil {
return nil, err
Expand Down Expand Up @@ -99,3 +92,44 @@ func createValidatorSet(host runtime.Host, backend ValidatoSetPrecompileBackend)

return validator.NewValidatorSet(accounts, hclog.NewNullLogger()), nil
}

func abiDecodeAddresses(input []byte) ([]types.Address, error) {
if len(input) < 32 || len(input)%32 != 0 {
return nil, runtime.ErrInvalidInputData
}

// abi.encode encodes addresses[] with slice of bytes where initial 31 bytes
// are set to 0, and 32nd is 32
// then goes length of slice (32 bytes)
// then each address is 32 bytes
dummy := [32]byte{}
dummy[31] = 32

if bytes.Equal(dummy[:], input[:32]) {
input = input[32:]
}

size := binary.BigEndian.Uint32(input[28:32])
if uint32(len(input)) != size*32+32 {
return nil, runtime.ErrInvalidInputData
}

res := make([]types.Address, size)
for i, offset := 0, 32; offset < len(input); i, offset = i+1, offset+32 {
res[i] = types.Address(input[offset : offset+32])
}

return res, nil
}

func abiEncodeAddresses(addrs []types.Address) []byte {
res := make([]byte, len(addrs)*32+64)
res[31] = 32

binary.BigEndian.PutUint32(res[32+28:64], uint32(len(addrs)))
for i, a := range addrs {

Check failure on line 130 in state/runtime/precompiled/validator_set_precompile.go

View workflow job for this annotation

GitHub Actions / Lint / Run Lint

ranges should only be cuddled with assignments used in the iteration (wsl)
copy(res[64+i*32:64+(i+1)*32], a.Bytes())
}

return res
}
37 changes: 15 additions & 22 deletions state/runtime/precompiled/validator_set_precompile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,20 @@ func Test_ValidatorSetPrecompile_run_IsValidator(t *testing.T) {
}

func Test_ValidatorSetPrecompile_run_HasQuorum(t *testing.T) {
addrGood := [][]byte{
types.StringToAddress("a").Bytes(),
types.StringToAddress("b").Bytes(),
types.StringToAddress("d").Bytes(),
dummy := [32]byte{}
dummy[31] = 32
addrGood := []types.Address{
types.StringToAddress("a"),
types.StringToAddress("b"),
types.StringToAddress("d"),
}
addrBad1 := [][]byte{
types.StringToAddress("a").Bytes(),
addrBad1 := []types.Address{
types.StringToAddress("a"),
}
addrBad2 := [][]byte{
types.StringToAddress("a").Bytes(),
types.StringToAddress("0").Bytes(),
types.StringToAddress("d").Bytes(),
addrBad2 := []types.Address{
types.StringToAddress("a"),
types.StringToAddress("0"),
types.StringToAddress("d"),
}
host := newDummyHost(t)
host.context = &runtime.TxContext{
Expand All @@ -103,24 +105,15 @@ func Test_ValidatorSetPrecompile_run_HasQuorum(t *testing.T) {
backend: backendMock,
}

bytes, err := hasQuorumAbiType.Encode(addrGood)
require.NoError(t, err)

v, err := p.run(bytes, types.Address{}, host)
v, err := p.run(abiEncodeAddresses(addrGood), types.Address{}, host)
require.NoError(t, err)
assert.Equal(t, abiBoolTrue, v)

bytes, err = hasQuorumAbiType.Encode(addrBad1)
require.NoError(t, err)

v, err = p.run(bytes, types.Address{}, host)
v, err = p.run(abiEncodeAddresses(addrBad1), types.Address{}, host)
require.NoError(t, err)
assert.Equal(t, abiBoolFalse, v)

bytes, err = hasQuorumAbiType.Encode(addrBad2)
require.NoError(t, err)

v, err = p.run(bytes, types.Address{}, host)
v, err = p.run(abiEncodeAddresses(addrBad2), types.Address{}, host)
require.NoError(t, err)
assert.Equal(t, abiBoolFalse, v)
}
Expand Down

0 comments on commit fb5c095

Please sign in to comment.