diff --git a/chain/params.go b/chain/params.go index e577296977..a4c9710781 100644 --- a/chain/params.go +++ b/chain/params.go @@ -26,6 +26,8 @@ type Params struct { ContractDeployerBlockList *AddressListConfig `json:"contractDeployerBlockList,omitempty"` TransactionsAllowList *AddressListConfig `json:"transactionsAllowList,omitempty"` TransactionsBlockList *AddressListConfig `json:"transactionsBlockList,omitempty"` + BridgeAllowList *AddressListConfig `json:"bridgeAllowList,omitempty"` + BridgeBlockList *AddressListConfig `json:"bridgeBlockList,omitempty"` // Governance contract where the token will be sent to and burn in london fork BurnContract map[uint64]string `json:"burnContract"` diff --git a/command/genesis/genesis.go b/command/genesis/genesis.go index 1ad107836d..a277960878 100644 --- a/command/genesis/genesis.go +++ b/command/genesis/genesis.go @@ -291,6 +291,34 @@ func setFlags(cmd *cobra.Command) { []string{}, "list of addresses to enable by default in the transactions block list", ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeAllowListAdmin, + bridgeAllowListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the bridge allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeAllowListEnabled, + bridgeAllowListEnabledFlag, + []string{}, + "list of addresses to enable by default in the bridge allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeBlockListAdmin, + bridgeBlockListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the bridge block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeBlockListEnabled, + bridgeBlockListEnabledFlag, + []string{}, + "list of addresses to enable by default in the bridge block list", + ) } } diff --git a/command/genesis/params.go b/command/genesis/params.go index 87d8f3f8e4..c2be9bf5c5 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -113,6 +113,10 @@ type genesisParams struct { transactionsAllowListEnabled []string transactionsBlockListAdmin []string transactionsBlockListEnabled []string + bridgeAllowListAdmin []string + bridgeAllowListEnabled []string + bridgeBlockListAdmin []string + bridgeBlockListEnabled []string mintableNativeToken bool nativeTokenConfigRaw string diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 92ca6bb813..25d79ce7f7 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -49,6 +49,10 @@ const ( transactionsAllowListEnabledFlag = "transactions-allow-list-enabled" transactionsBlockListAdminFlag = "transactions-block-list-admin" transactionsBlockListEnabledFlag = "transactions-block-list-enabled" + bridgeAllowListAdminFlag = "bridge-allow-list-admin" + bridgeAllowListEnabledFlag = "bridge-allow-list-enabled" + bridgeBlockListAdminFlag = "bridge-block-list-admin" + bridgeBlockListEnabledFlag = "bridge-block-list-enabled" bootnodePortStart = 30301 @@ -231,6 +235,24 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er } } + if len(p.bridgeAllowListAdmin) != 0 { + // only enable allow list if there is at least one address as **admin**, otherwise + // the allow list could never be updated + chainConfig.Params.BridgeAllowList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.bridgeAllowListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.bridgeAllowListEnabled), + } + } + + if len(p.bridgeBlockListAdmin) != 0 { + // only enable block list if there is at least one address as **admin**, otherwise + // the block list could never be updated + chainConfig.Params.BridgeBlockList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.bridgeBlockListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.bridgeBlockListEnabled), + } + } + return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath) } diff --git a/contracts/system_addresses.go b/contracts/system_addresses.go index 859e47cd3c..6bfdaeff10 100644 --- a/contracts/system_addresses.go +++ b/contracts/system_addresses.go @@ -46,4 +46,8 @@ var ( AllowListTransactionsAddr = types.StringToAddress("0x0200000000000000000000000000000000000002") // BlockListTransactionsAddr is the address of the transactions block list BlockListTransactionsAddr = types.StringToAddress("0x0300000000000000000000000000000000000002") + // AllowListBridgeAddr is the address of the bridge allow list + AllowListBridgeAddr = types.StringToAddress("0x0200000000000000000000000000000000000004") + // BlockListBridgeAddr is the address of the bridge block list + BlockListBridgeAddr = types.StringToAddress("0x0300000000000000000000000000000000000004") ) diff --git a/e2e-polybft/e2e/acls_test.go b/e2e-polybft/e2e/acls_test.go index 3fd100129f..f6079ceb25 100644 --- a/e2e-polybft/e2e/acls_test.go +++ b/e2e-polybft/e2e/acls_test.go @@ -363,3 +363,37 @@ func TestE2E_BlockList_Transactions(t *testing.T) { require.True(t, targetTxn.Reverted()) } } + +func TestE2E_AddressLists_Bridge(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + other, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + otherAddr := types.Address(other.Address()) + + cluster := framework.NewTestCluster(t, 3, + framework.WithPremine(adminAddr, targetAddr, otherAddr), + framework.WithBridgeAllowListAdmin(adminAddr), + framework.WithBridgeAllowListEnabled(otherAddr), + framework.WithBridgeBlockListAdmin(adminAddr), + framework.WithBridgeBlockListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + { + // Step 0. Check the role of both accounts + expectRole(t, cluster, contracts.AllowListBridgeAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.AllowListBridgeAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.AllowListBridgeAddr, otherAddr, addresslist.EnabledRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, otherAddr, addresslist.EnabledRole) + } +} diff --git a/e2e-polybft/framework/test-cluster.go b/e2e-polybft/framework/test-cluster.go index f990df32d0..7ab24d1b38 100644 --- a/e2e-polybft/framework/test-cluster.go +++ b/e2e-polybft/framework/test-cluster.go @@ -97,6 +97,10 @@ type TestClusterConfig struct { TransactionsAllowListEnabled []types.Address TransactionsBlockListAdmin []types.Address TransactionsBlockListEnabled []types.Address + BridgeAllowListAdmin []types.Address + BridgeAllowListEnabled []types.Address + BridgeBlockListAdmin []types.Address + BridgeBlockListEnabled []types.Address NumBlockConfirmations uint64 @@ -315,6 +319,30 @@ func WithTransactionsBlockListEnabled(addr types.Address) ClusterOption { } } +func WithBridgeAllowListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeAllowListAdmin = append(h.BridgeAllowListAdmin, addr) + } +} + +func WithBridgeAllowListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeAllowListEnabled = append(h.BridgeAllowListEnabled, addr) + } +} + +func WithBridgeBlockListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeBlockListAdmin = append(h.BridgeBlockListAdmin, addr) + } +} + +func WithBridgeBlockListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeBlockListEnabled = append(h.BridgeBlockListEnabled, addr) + } +} + func WithPropertyTestLogging() ClusterOption { return func(h *TestClusterConfig) { h.IsPropertyTest = true @@ -509,6 +537,26 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T strings.Join(sliceAddressToSliceString(cluster.Config.TransactionsBlockListEnabled), ",")) } + if len(cluster.Config.BridgeAllowListAdmin) != 0 { + args = append(args, "--bridge-allow-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeAllowListAdmin), ",")) + } + + if len(cluster.Config.BridgeAllowListEnabled) != 0 { + args = append(args, "--bridge-allow-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeAllowListEnabled), ",")) + } + + if len(cluster.Config.BridgeBlockListAdmin) != 0 { + args = append(args, "--bridge-block-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeBlockListAdmin), ",")) + } + + if len(cluster.Config.BridgeBlockListEnabled) != 0 { + args = append(args, "--bridge-block-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeBlockListEnabled), ",")) + } + // run genesis command with all the arguments err = cluster.cmdRun(args...) require.NoError(t, err) diff --git a/server/server.go b/server/server.go index f98f110171..960f8952ee 100644 --- a/server/server.go +++ b/server/server.go @@ -236,6 +236,18 @@ func NewServer(config *Config) (*Server, error) { m.config.Chain.Params.TransactionsBlockList) } + // apply bridge allow list genesis data + if m.config.Chain.Params.BridgeAllowList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.AllowListBridgeAddr, + m.config.Chain.Params.BridgeAllowList) + } + + // apply bridge block list genesis data + if m.config.Chain.Params.BridgeBlockList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.BlockListBridgeAddr, + m.config.Chain.Params.BridgeBlockList) + } + var initialStateRoot = types.ZeroHash if ConsensusType(engineName) == PolyBFTConsensus { diff --git a/state/executor.go b/state/executor.go index 4c7880424a..a95c54f41c 100644 --- a/state/executor.go +++ b/state/executor.go @@ -234,6 +234,15 @@ func (e *Executor) BeginTxn( txn.txnBlockList = addresslist.NewAddressList(txn, contracts.BlockListTransactionsAddr) } + // enable transactions allow list (if any) + if e.config.BridgeAllowList != nil { + txn.bridgeAllowList = addresslist.NewAddressList(txn, contracts.AllowListBridgeAddr) + } + + if e.config.BridgeBlockList != nil { + txn.bridgeBlockList = addresslist.NewAddressList(txn, contracts.BlockListBridgeAddr) + } + return txn, nil } @@ -265,6 +274,8 @@ type Transition struct { deploymentBlockList *addresslist.AddressList txnAllowList *addresslist.AddressList txnBlockList *addresslist.AddressList + bridgeAllowList *addresslist.AddressList + bridgeBlockList *addresslist.AddressList } func NewTransition(config chain.ForksInTime, snap Snapshot, radix *Txn) *Transition { @@ -703,6 +714,16 @@ func (t *Transition) run(contract *runtime.Contract, host runtime.Host) *runtime } } + // check bridge allow list (if any) + if t.bridgeAllowList != nil && t.bridgeAllowList.Addr() == contract.CodeAddress { + return t.bridgeAllowList.Run(contract, host, &t.config) + } + + // check contract deployment block list (if any) + if t.bridgeBlockList != nil && t.bridgeBlockList.Addr() == contract.CodeAddress { + return t.bridgeBlockList.Run(contract, host, &t.config) + } + // check the precompiles if t.precompiles.CanRun(contract, host, &t.config) { return t.precompiles.Run(contract, host, &t.config)