Skip to content

Commit

Permalink
Permission smart contract deployment (0xPolygon#692)
Browse files Browse the repository at this point in the history
* Add contract deployment whitelist CLI commands

* Validate smart contract deployment in txPool

* Remove whitelist from genesis if nill

* code clean up

* Fix linter errors

* Add command for listing all whitelists

* Add unit tests

* Typo, replace comma with dot

* Fix typo in addAddress flag

* Convert flags to snake-case

* Alocate arrays to specific size

* Fix comment for adding addresses

* Make deployment result omitempty

* change show command description

* Fix typo in whitelist command description

* Change permission smart contract error

* Make global test var local

* Extract errors

* Make deployment whitelist key const

* Remove genesis config dependecy from show command

* Fix lint

* extract unmarshalling raw addresses

* Switch commands to kebab-case

* Refactor unmarshall raw address

* Fix lint

* Remove test

* make addressExists exportable

* make canDeployContract helper method

* Rename methods

* Rename attribute

* Reserve space for whitelist

* Rename config param

* extract config helper to seperate file

* Change methods names

* Optimize list insertion and deletion

* Tidy whotelist object in command

* Fix variable names

* Tidy txpool

* Rename typo

* Extract init deploymentWhitelist

* Remove unused methods

* Remove canDeploy method
  • Loading branch information
0xAleksaOpacic authored Aug 31, 2022
1 parent 5d2db1e commit 74ab62e
Show file tree
Hide file tree
Showing 14 changed files with 590 additions and 12 deletions.
8 changes: 8 additions & 0 deletions chain/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package chain

import (
"math/big"

"github.com/0xPolygon/polygon-edge/types"
)

// Params are all the set of params for the chain
type Params struct {
Forks *Forks `json:"forks"`
ChainID int `json:"chainID"`
Engine map[string]interface{} `json:"engine"`
Whitelists *Whitelists `json:"whitelists,omitempty"`
BlockGasTarget uint64 `json:"blockGasTarget"`
}

Expand All @@ -21,6 +24,11 @@ func (p *Params) GetEngine() string {
return ""
}

// Whitelists specifies supported whitelists
type Whitelists struct {
Deployment []types.Address `json:"deployment,omitempty"`
}

// Forks specifies when each fork is activated
type Forks struct {
Homestead *Fork `json:"homestead,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions command/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/0xPolygon/polygon-edge/command/status"
"github.com/0xPolygon/polygon-edge/command/txpool"
"github.com/0xPolygon/polygon-edge/command/version"
"github.com/0xPolygon/polygon-edge/command/whitelist"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -51,6 +52,7 @@ func (rc *RootCommand) registerSubCommands() {
backup.GetCommand(),
genesis.GetCommand(),
server.GetCommand(),
whitelist.GetCommand(),
license.GetCommand(),
)
}
Expand Down
66 changes: 66 additions & 0 deletions command/whitelist/deployment/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package deployment

import (
"fmt"

"github.com/0xPolygon/polygon-edge/command"
"github.com/spf13/cobra"
)

func GetCommand() *cobra.Command {
deploymentCmd := &cobra.Command{
Use: "deployment",
Short: "Top level command for updating smart contract deployment whitelist. Only accepts subcommands",
PreRunE: runPreRun,
Run: runCommand,
}

setFlags(deploymentCmd)

return deploymentCmd
}

func setFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(
&params.genesisPath,
chainFlag,
fmt.Sprintf("./%s", command.DefaultGenesisFileName),
"the genesis file to update",
)
cmd.Flags().StringArrayVar(
&params.addAddressRaw,
addAddressFlag,
[]string{},
"adds a new address to the contract deployment whitelist",
)

cmd.Flags().StringArrayVar(
&params.removeAddressRaw,
removeAddressFlag,
[]string{},
"removes a new address from the contract deployment whitelist",
)
}

func runPreRun(_ *cobra.Command, _ []string) error {
return params.initRawParams()
}

func runCommand(cmd *cobra.Command, _ []string) {
outputter := command.InitializeOutputter(cmd)
defer outputter.WriteOutput()

if err := params.updateGenesisConfig(); err != nil {
outputter.SetError(err)

return
}

if err := params.overrideGenesisConfig(); err != nil {
outputter.SetError(err)

return
}

outputter.SetCommandResult(params.getResult())
}
162 changes: 162 additions & 0 deletions command/whitelist/deployment/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package deployment

import (
"fmt"
"os"

"github.com/0xPolygon/polygon-edge/chain"
"github.com/0xPolygon/polygon-edge/command"
"github.com/0xPolygon/polygon-edge/command/helper"
"github.com/0xPolygon/polygon-edge/helper/config"
"github.com/0xPolygon/polygon-edge/types"
)

const (
chainFlag = "chain"
addAddressFlag = "add"
removeAddressFlag = "remove"
)

var (
params = &deploymentParams{}
)

type deploymentParams struct {
// raw addresses, entered by CLI commands
addAddressRaw []string
removeAddressRaw []string

// addresses, converted from raw addresses
addAddresses []types.Address
removeAddresses []types.Address

// genesis file
genesisPath string
genesisConfig *chain.Chain

// deployment whitelist from genesis configuration
whitelist []types.Address
}

func (p *deploymentParams) initRawParams() error {
// convert raw addresses to appropriate format
if err := p.initRawAddresses(); err != nil {
return err
}

// init genesis configuration
if err := p.initChain(); err != nil {
return err
}

return nil
}

func (p *deploymentParams) initRawAddresses() error {
// convert addresses to be added from string to type.Address
p.addAddresses = unmarshallRawAddresses(p.addAddressRaw)

// convert addresses to be removed from string to type.Address
p.removeAddresses = unmarshallRawAddresses(p.removeAddressRaw)

return nil
}

func (p *deploymentParams) initChain() error {
// import genesis configuration
cc, err := chain.Import(p.genesisPath)
if err != nil {
return fmt.Errorf(
"failed to load chain config from %s: %w",
p.genesisPath,
err,
)
}

// set genesis configuration
p.genesisConfig = cc

return nil
}

func (p *deploymentParams) updateGenesisConfig() error {
// Fetch contract deployment whitelist from genesis config
deploymentWhitelist, err := config.GetDeploymentWhitelist(p.genesisConfig)
if err != nil {
return err
}

doesExist := map[types.Address]bool{}

for _, a := range deploymentWhitelist {
doesExist[a] = true
}

for _, a := range p.addAddresses {
doesExist[a] = true
}

for _, a := range p.removeAddresses {
doesExist[a] = false
}

newDeploymentWhitelist := make([]types.Address, 0)

for addr, exists := range doesExist {
if exists {
newDeploymentWhitelist = append(newDeploymentWhitelist, addr)
}
}

// Set whitelist in genesis configuration
whitelistConfig := config.GetWhitelist(p.genesisConfig)

if whitelistConfig == nil {
whitelistConfig = &chain.Whitelists{}
}

whitelistConfig.Deployment = newDeploymentWhitelist
p.genesisConfig.Params.Whitelists = whitelistConfig

// Save whitelist for result
p.whitelist = newDeploymentWhitelist

return nil
}

func (p *deploymentParams) overrideGenesisConfig() error {
// Remove the current genesis configuration from the disk
if err := os.Remove(p.genesisPath); err != nil {
return err
}

// Save the new genesis configuration
if err := helper.WriteGenesisConfigToDisk(
p.genesisConfig,
p.genesisPath,
); err != nil {
return err
}

return nil
}

func (p *deploymentParams) getResult() command.CommandResult {
result := &DeploymentResult{
AddAddresses: p.addAddresses,
RemoveAddresses: p.removeAddresses,
Whitelist: p.whitelist,
}

return result
}

func unmarshallRawAddresses(addresses []string) []types.Address {
marshalledAddresses := make([]types.Address, len(addresses))

for indx, address := range addresses {
marshalledAddresses[indx] = types.StringToAddress(address)
}

return marshalledAddresses
}
32 changes: 32 additions & 0 deletions command/whitelist/deployment/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package deployment

import (
"bytes"
"fmt"

"github.com/0xPolygon/polygon-edge/types"
)

type DeploymentResult struct {
AddAddresses []types.Address `json:"addAddress,omitempty"`
RemoveAddresses []types.Address `json:"removeAddress,omitempty"`
Whitelist []types.Address `json:"whitelist"`
}

func (r *DeploymentResult) GetOutput() string {
var buffer bytes.Buffer

buffer.WriteString("\n[CONTRACT DEPLOYMENT WHITELIST]\n\n")

if len(r.AddAddresses) != 0 {
buffer.WriteString(fmt.Sprintf("Added addresses: %s,\n", r.AddAddresses))
}

if len(r.RemoveAddresses) != 0 {
buffer.WriteString(fmt.Sprintf("Removed addresses: %s,\n", r.RemoveAddresses))
}

buffer.WriteString(fmt.Sprintf("Contract deployment whitelist : %s,\n", r.Whitelist))

return buffer.String()
}
72 changes: 72 additions & 0 deletions command/whitelist/show/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package show

import (
"fmt"

"github.com/0xPolygon/polygon-edge/chain"
"github.com/0xPolygon/polygon-edge/command"
"github.com/0xPolygon/polygon-edge/helper/config"
"github.com/0xPolygon/polygon-edge/types"
)

const (
chainFlag = "chain"
)

var (
params = &showParams{}
)

type showParams struct {
// genesis file path
genesisPath string

// deployment whitelist
whitelists Whitelists
}

type Whitelists struct {
deployment []types.Address
}

func (p *showParams) initRawParams() error {
// init genesis configuration
if err := p.initWhitelists(); err != nil {
return err
}

return nil
}

func (p *showParams) initWhitelists() error {
// import genesis configuration
genesisConfig, err := chain.Import(p.genesisPath)
if err != nil {
return fmt.Errorf(
"failed to load chain config from %s: %w",
p.genesisPath,
err,
)
}

// fetch whitelists
deploymentWhitelist, err := config.GetDeploymentWhitelist(genesisConfig)
if err != nil {
return err
}

// set whitelists
p.whitelists = Whitelists{
deployment: deploymentWhitelist,
}

return nil
}

func (p *showParams) getResult() command.CommandResult {
result := &ShowResult{
Whitelists: p.whitelists,
}

return result
}
Loading

0 comments on commit 74ab62e

Please sign in to comment.