Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evm 785: enable and disable access lists in the runtime #1839

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions chain/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Params struct {
BlockGasTarget uint64 `json:"blockGasTarget"`

// Access control configuration
AccessListsSuperAdmin *types.Address `json:"accessListsSuperAdmin,omitempty"`
ContractDeployerAllowList *AddressListConfig `json:"contractDeployerAllowList,omitempty"`
ContractDeployerBlockList *AddressListConfig `json:"contractDeployerBlockList,omitempty"`
TransactionsAllowList *AddressListConfig `json:"transactionsAllowList,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions command/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ func setFlags(cmd *cobra.Command) {
[]string{},
"list of addresses to enable by default in the bridge block list",
)

cmd.Flags().StringVar(
&params.accessListsSuperAdmin,
accessListsSuperAdminFlag,
"",
"super admin for all allow and block lists",
)
}
}

Expand Down
1 change: 1 addition & 0 deletions command/genesis/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type genesisParams struct {
bridgeAllowListEnabled []string
bridgeBlockListAdmin []string
bridgeBlockListEnabled []string
accessListsSuperAdmin string

nativeTokenConfigRaw string
nativeTokenConfig *polybft.TokenConfig
Expand Down
6 changes: 6 additions & 0 deletions command/genesis/polybft_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const (
defaultEpochReward = 1
defaultBlockTimeDrift = uint64(10)

accessListsSuperAdminFlag = "access-lists-super-admin" // #nosec G101
contractDeployerAllowListAdminFlag = "contract-deployer-allow-list-admin"
contractDeployerAllowListEnabledFlag = "contract-deployer-allow-list-enabled"
contractDeployerBlockListAdminFlag = "contract-deployer-block-list-admin"
Expand Down Expand Up @@ -296,6 +297,11 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
}
}

if p.accessListsSuperAdmin != "" {
value := types.StringToAddress(p.accessListsSuperAdmin)
chainConfig.Params.AccessListsSuperAdmin = &value
}

if p.isBurnContractEnabled() {
// only populate base fee and base fee multiplier values if burn contract(s)
// is provided
Expand Down
151 changes: 142 additions & 9 deletions e2e-polybft/e2e/acls_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package e2e

import (
"encoding/hex"
"fmt"
"math/big"
"testing"

"github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi"
"github.com/0xPolygon/polygon-edge/contracts"
"github.com/0xPolygon/polygon-edge/e2e-polybft/framework"
"github.com/0xPolygon/polygon-edge/helper/hex"
"github.com/0xPolygon/polygon-edge/state/runtime/addresslist"
"github.com/0xPolygon/polygon-edge/types"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -53,9 +54,7 @@ func TestE2E_AllowList_ContractDeployment(t *testing.T) {

cluster.WaitForReady(t)

// bytecode for an empty smart contract
bytecode, err := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033")
require.NoError(t, err)
bytecode := getDummySmartContract(t) // this test requires custom proxy smart contract

{
// Step 0. Check the role of both accounts
Expand Down Expand Up @@ -152,9 +151,7 @@ func TestE2E_BlockList_ContractDeployment(t *testing.T) {

cluster.WaitForReady(t)

// bytecode for an empty smart contract
bytecode, err := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033")
require.NoError(t, err)
bytecode := contractsapi.TestSimple.Bytecode

{
// Step 0. Check the role of accounts
Expand Down Expand Up @@ -236,8 +233,7 @@ func TestE2E_AllowList_Transactions(t *testing.T) {

cluster.WaitForReady(t)

// bytecode for an empty smart contract
bytecode, _ := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033")
bytecode := contractsapi.TestSimple.Bytecode

{
// Step 0. Check the role of both accounts
Expand Down Expand Up @@ -413,3 +409,140 @@ func TestE2E_AddressLists_Bridge(t *testing.T) {
expectRole(t, cluster, contracts.BlockListBridgeAddr, otherAddr, addresslist.EnabledRole)
}
}

func TestE2E_AllowList_SuperAdmin(t *testing.T) {
superadmin, _ := wallet.GenerateKey()
admin, _ := wallet.GenerateKey()
rndUser, _ := wallet.GenerateKey()

adminAddr := types.Address(admin.Address())
rndUserAddress := types.Address(rndUser.Address())

cluster := framework.NewTestCluster(t, 5,
framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)),
framework.WithPremine(adminAddr, rndUserAddress),
framework.WithAccessListsSuperAdmin(types.Address(superadmin.Address())),
)
defer cluster.Stop()

cluster.WaitForReady(t)

{
// Step 0. allow lists should be disabled
expectIsEnabled(t, cluster, contracts.AllowListTransactionsAddr, false)
expectIsEnabled(t, cluster, contracts.AllowListContractsAddr, false)
}

bytecode := contractsapi.TestSimple.Bytecode

{
// Step 1. anyone can send normal transaction or deploy smart contract because lists are disabled
tx := cluster.Transfer(t, admin, types.ZeroAddress, big.NewInt(1))
require.NoError(t, tx.Wait())
require.True(t, tx.Succeed())

tx = cluster.Deploy(t, rndUser, bytecode)
require.NoError(t, tx.Wait())
require.True(t, tx.Succeed())
require.True(t, cluster.ExistsCode(t, tx.Receipt().ContractAddress))
}

{
// Step 2. super admin enables two lists
input, _ := addresslist.SetListEnabledFunc.Encode([]interface{}{true})

saTxn := cluster.MethodTxn(t, superadmin, contracts.AllowListTransactionsAddr, input)
require.NoError(t, saTxn.Wait())
require.False(t, saTxn.Failed())

input, _ = addresslist.SetListEnabledFunc.Encode([]interface{}{true})

saTxn = cluster.MethodTxn(t, superadmin, contracts.AllowListContractsAddr, input)
require.NoError(t, saTxn.Wait())
require.False(t, saTxn.Failed())
}

{
// Step 3. no one can send normal transaction or deploy smart contract because lists are enabled and empty
tx := cluster.Transfer(t, rndUser, types.ZeroAddress, big.NewInt(1))
require.NoError(t, tx.Wait())
require.False(t, tx.Succeed())

tx = cluster.Deploy(t, admin, bytecode)
require.NoError(t, tx.Wait())
require.False(t, tx.Succeed())
require.False(t, cluster.ExistsCode(t, tx.Receipt().ContractAddress))
}

{
// Step 4. add two roles by superadmin
input, _ := addresslist.SetAdminFunc.Encode([]interface{}{adminAddr})

saTxn := cluster.MethodTxn(t, superadmin, contracts.AllowListTransactionsAddr, input)
require.NoError(t, saTxn.Wait())
require.True(t, saTxn.Succeed())

input, _ = addresslist.SetEnabledFunc.Encode([]interface{}{rndUserAddress})

saTxn = cluster.MethodTxn(t, superadmin, contracts.AllowListContractsAddr, input)
require.NoError(t, saTxn.Wait())
require.True(t, saTxn.Succeed())

// add one more role by admin
input, _ = addresslist.SetEnabledFunc.Encode([]interface{}{rndUserAddress})

saTxn = cluster.MethodTxn(t, admin, contracts.AllowListTransactionsAddr, input)
require.NoError(t, saTxn.Wait())
require.True(t, saTxn.Succeed())

// adding role by normal user should fail
input, _ = addresslist.SetEnabledFunc.Encode([]interface{}{adminAddr})

saTxn = cluster.MethodTxn(t, rndUser, contracts.AllowListContractsAddr, input)
require.NoError(t, saTxn.Wait())
require.True(t, saTxn.Failed())

expectRole(t, cluster, contracts.AllowListTransactionsAddr, adminAddr, addresslist.AdminRole)
expectRole(t, cluster, contracts.AllowListContractsAddr, rndUserAddress, addresslist.EnabledRole)
expectRole(t, cluster, contracts.AllowListTransactionsAddr, rndUserAddress, addresslist.EnabledRole)
expectRole(t, cluster, contracts.AllowListContractsAddr, adminAddr, addresslist.NoRole)
}

{
// Step 4. admin address can send normal transaction, user can deploy contract...
tx := cluster.Transfer(t, admin, types.ZeroAddress, big.NewInt(1))
require.NoError(t, tx.Wait())
require.True(t, tx.Succeed())

tx = cluster.Deploy(t, rndUser, bytecode)
require.NoError(t, tx.Wait())
require.True(t, tx.Succeed())
require.True(t, cluster.ExistsCode(t, tx.Receipt().ContractAddress))

// ... but admin address is not in deployment allow list
tx = cluster.Deploy(t, admin, bytecode)
require.NoError(t, tx.Wait())
require.True(t, tx.Reverted())
require.False(t, cluster.ExistsCode(t, tx.Receipt().ContractAddress))

// remove rndUser address from tx allow list so that address can not send transactions anymore
input, _ := addresslist.SetNoneFunc.Encode([]interface{}{rndUserAddress})

saTxn := cluster.MethodTxn(t, admin, contracts.AllowListTransactionsAddr, input)
require.NoError(t, saTxn.Wait())
require.True(t, saTxn.Succeed())

tx = cluster.Transfer(t, rndUser, types.ZeroAddress, big.NewInt(1))
require.NoError(t, tx.Wait())
require.True(t, tx.Reverted())
}
}

func getDummySmartContract(t *testing.T) []byte {
t.Helper()

bytecode, err := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033")
require.NoError(t, err)

return bytecode
}
14 changes: 11 additions & 3 deletions e2e-polybft/e2e/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,21 @@ func expectRole(t *testing.T, cluster *framework.TestCluster, contract types.Add
out := cluster.Call(t, contract, addresslist.ReadAddressListFunc, addr)

num, ok := out["0"].(*big.Int)
if !ok {
t.Fatal("unexpected")
}

require.True(t, ok)
require.Equal(t, role.Uint64(), num.Uint64())
}

func expectIsEnabled(t *testing.T, cluster *framework.TestCluster, contract types.Address, value bool) {
t.Helper()
out := cluster.Call(t, contract, addresslist.GetListEnabledFunc)

num, ok := out["0"].(bool)

require.True(t, ok)
require.Equal(t, value, num)
}

// getFilteredLogs retrieves Ethereum logs, described by event signature within the block range
func getFilteredLogs(eventSig ethgo.Hash, startBlock, endBlock uint64,
ethEndpoint *jsonrpc.Eth) ([]*ethgo.Log, error) {
Expand Down
11 changes: 11 additions & 0 deletions e2e-polybft/framework/test-cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type TestClusterConfig struct {
NativeTokenConfigRaw string
SecretsCallback func([]types.Address, *TestClusterConfig)

AccessListsSuperAdmin *types.Address
ContractDeployerAllowListAdmin []types.Address
ContractDeployerAllowListEnabled []types.Address
ContractDeployerBlockListAdmin []types.Address
Expand Down Expand Up @@ -266,6 +267,12 @@ func WithNumBlockConfirmations(numBlockConfirmations uint64) ClusterOption {
}
}

func WithAccessListsSuperAdmin(addr types.Address) ClusterOption {
return func(h *TestClusterConfig) {
h.AccessListsSuperAdmin = &addr
}
}

func WithContractDeployerAllowListAdmin(addr types.Address) ClusterOption {
return func(h *TestClusterConfig) {
h.ContractDeployerAllowListAdmin = append(h.ContractDeployerAllowListAdmin, addr)
Expand Down Expand Up @@ -489,6 +496,10 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T
}
}

if cluster.Config.AccessListsSuperAdmin != nil {
args = append(args, "--access-lists-super-admin", cluster.Config.AccessListsSuperAdmin.String())
}

if len(cluster.Config.ContractDeployerAllowListAdmin) != 0 {
args = append(args, "--contract-deployer-allow-list-admin",
strings.Join(sliceAddressToSliceString(cluster.Config.ContractDeployerAllowListAdmin), ","))
Expand Down
Loading
Loading