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 7486023
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 35 deletions.
3 changes: 1 addition & 2 deletions e2e-polybft/e2e/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (

"github.com/0xPolygon/polygon-edge/command"
"github.com/0xPolygon/polygon-edge/command/genesis"
"github.com/0xPolygon/polygon-edge/command/validator/helper"
validatorHelper "github.com/0xPolygon/polygon-edge/command/validator/helper"
"github.com/0xPolygon/polygon-edge/consensus/polybft"
"github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi"
Expand Down Expand Up @@ -842,7 +841,7 @@ func TestE2E_TestValidatorSetPrecompile(t *testing.T) {
validatorKeys := make([]*wallet.Key, len(validatorAddrs))

for i, s := range cluster.Servers {
voterAcc, err := helper.GetAccountFromDir(s.DataDir())
voterAcc, err := validatorHelper.GetAccountFromDir(s.DataDir())
require.NoError(t, err)

validatorKeys[i] = voterAcc.Ecdsa
Expand Down
64 changes: 53 additions & 11 deletions state/runtime/precompiled/validator_set_precompile.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package precompiled

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

"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,24 +53,25 @@ 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
}

fmt.Println("QUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU")
signers := make(map[types.Address]struct{}, len(addresses))

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

View workflow job for this annotation

GitHub Actions / Lint / Run Lint

assignments should only be cuddled with other assignments (wsl)
for _, x := range addresses {

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

View workflow job for this annotation

GitHub Actions / Lint / Run Lint

only one cuddle assignment allowed before range statement (wsl)
signers[types.Address(x)] = struct{}{}
signers[x] = struct{}{}
fmt.Println("HAS QUOORUM", x)

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

View workflow job for this annotation

GitHub Actions / Lint / Run Lint

only cuddled expressions if assigning variable or using from line above (wsl)
}

for _, x := range validatorSet.Accounts() {
fmt.Println(x.Address.String(), x.VotingPower)
}

if validatorSet.HasQuorum(uint64(host.GetTxContext().Number), signers) {
Expand Down Expand Up @@ -99,3 +99,45 @@ 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+12 : 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 {
copy(res[64+i*32+12: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 7486023

Please sign in to comment.