From 7486023b7bda8cd9f1e4fc87b2a78f0ff337b7d7 Mon Sep 17 00:00:00 2001 From: Igor Crevar Date: Thu, 15 Feb 2024 20:31:55 +0100 Subject: [PATCH] custom abi.(d)encode(address[]) --- e2e-polybft/e2e/consensus_test.go | 3 +- .../precompiled/validator_set_precompile.go | 64 +++++++++++++++---- .../validator_set_precompile_test.go | 37 +++++------ 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/e2e-polybft/e2e/consensus_test.go b/e2e-polybft/e2e/consensus_test.go index 1ef65d0aa6..066c8ad308 100644 --- a/e2e-polybft/e2e/consensus_test.go +++ b/e2e-polybft/e2e/consensus_test.go @@ -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" @@ -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 diff --git a/state/runtime/precompiled/validator_set_precompile.go b/state/runtime/precompiled/validator_set_precompile.go index 2c641c1851..4ea5aed19e 100644 --- a/state/runtime/precompiled/validator_set_precompile.go +++ b/state/runtime/precompiled/validator_set_precompile.go @@ -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") ) @@ -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)) for _, x := range addresses { - signers[types.Address(x)] = struct{}{} + signers[x] = struct{}{} + fmt.Println("HAS QUOORUM", x) + } + + for _, x := range validatorSet.Accounts() { + fmt.Println(x.Address.String(), x.VotingPower) } if validatorSet.HasQuorum(uint64(host.GetTxContext().Number), signers) { @@ -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 +} diff --git a/state/runtime/precompiled/validator_set_precompile_test.go b/state/runtime/precompiled/validator_set_precompile_test.go index 3724cf339c..a9d31da098 100644 --- a/state/runtime/precompiled/validator_set_precompile_test.go +++ b/state/runtime/precompiled/validator_set_precompile_test.go @@ -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{ @@ -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) }