github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/proposal_handler.go (about)

     1  package keeper
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    11  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    12  	govtypes "github.com/fibonacci-chain/fbc/x/gov/types"
    13  	"github.com/fibonacci-chain/fbc/x/wasm/types"
    14  )
    15  
    16  // NewWasmProposalHandler creates a new governance Handler for wasm proposals
    17  func NewWasmProposalHandler(k decoratedKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler {
    18  	return NewWasmProposalHandlerX(NewGovPermissionKeeper(k), enabledProposalTypes)
    19  }
    20  
    21  // NewWasmProposalHandlerX creates a new governance Handler for wasm proposals
    22  func NewWasmProposalHandlerX(k types.ContractOpsKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler {
    23  	enabledTypes := make(map[string]struct{}, len(enabledProposalTypes))
    24  	for i := range enabledProposalTypes {
    25  		enabledTypes[string(enabledProposalTypes[i])] = struct{}{}
    26  	}
    27  	return func(ctx sdk.Context, proposal *govtypes.Proposal) sdk.Error {
    28  		if !types2.HigherThanEarth(ctx.BlockHeight()) {
    29  			errMsg := fmt.Sprintf("wasm not supprt at height %d", ctx.BlockHeight())
    30  			return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
    31  		}
    32  		content := proposal.Content
    33  		if content == nil {
    34  			return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "content must not be empty")
    35  		}
    36  		if _, ok := enabledTypes[content.ProposalType()]; !ok {
    37  			return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unsupported wasm proposal content type: %q", content.ProposalType())
    38  		}
    39  		switch c := content.(type) {
    40  		case *types.StoreCodeProposal:
    41  			return handleStoreCodeProposal(ctx, k, *c)
    42  		case *types.InstantiateContractProposal:
    43  			return handleInstantiateProposal(ctx, k, *c)
    44  		case *types.MigrateContractProposal:
    45  			return handleMigrateProposal(ctx, k, *c)
    46  		case *types.SudoContractProposal:
    47  			return handleSudoProposal(ctx, k, *c)
    48  		case *types.ExecuteContractProposal:
    49  			return handleExecuteProposal(ctx, k, *c)
    50  		case *types.UpdateAdminProposal:
    51  			return handleUpdateAdminProposal(ctx, k, *c)
    52  		case *types.ClearAdminProposal:
    53  			return handleClearAdminProposal(ctx, k, *c)
    54  		case *types.PinCodesProposal:
    55  			return handlePinCodesProposal(ctx, k, *c)
    56  		case *types.UnpinCodesProposal:
    57  			return handleUnpinCodesProposal(ctx, k, *c)
    58  		case *types.UpdateInstantiateConfigProposal:
    59  			return handleUpdateInstantiateConfigProposal(ctx, k, *c)
    60  		case *types.UpdateDeploymentWhitelistProposal:
    61  			return handleUpdateDeploymentWhitelistProposal(ctx, k, *c)
    62  		case *types.UpdateWASMContractMethodBlockedListProposal:
    63  			return handleUpdateWASMContractMethodBlockedListProposal(ctx, k, *c)
    64  		default:
    65  			return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized wasm proposal content type: %T", c)
    66  		}
    67  	}
    68  }
    69  
    70  func handleStoreCodeProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.StoreCodeProposal) error {
    71  	if err := p.ValidateBasic(); err != nil {
    72  		return err
    73  	}
    74  
    75  	runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs)
    76  	if err != nil {
    77  		return sdkerrors.Wrap(err, "run as address")
    78  	}
    79  	codeID, err := k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return k.PinCode(ctx, codeID)
    84  }
    85  
    86  func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.InstantiateContractProposal) error {
    87  	if err := p.ValidateBasic(); err != nil {
    88  		return err
    89  	}
    90  	runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs)
    91  	if err != nil {
    92  		return sdkerrors.Wrap(err, "run as address")
    93  	}
    94  	var adminAddr sdk.AccAddress
    95  	if p.Admin != "" {
    96  		if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil {
    97  			return sdkerrors.Wrap(err, "admin")
    98  		}
    99  	}
   100  
   101  	_, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, sdk.CoinAdaptersToCoins(p.Funds))
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	ctx.EventManager().EmitEvent(sdk.NewEvent(
   107  		types.EventTypeGovContractResult,
   108  		sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
   109  	))
   110  	return nil
   111  }
   112  
   113  func handleMigrateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.MigrateContractProposal) error {
   114  	if err := p.ValidateBasic(); err != nil {
   115  		return err
   116  	}
   117  
   118  	contractAddr, err := sdk.AccAddressFromBech32(p.Contract)
   119  	if err != nil {
   120  		return sdkerrors.Wrap(err, "contract")
   121  	}
   122  	if err != nil {
   123  		return sdkerrors.Wrap(err, "run as address")
   124  	}
   125  
   126  	if err = k.ClearContractAdmin(ctx, contractAddr, contractAddr); err != nil {
   127  		return err
   128  	}
   129  
   130  	// runAs is not used if this is permissioned, so just put any valid address there (second contractAddr)
   131  	data, err := k.Migrate(ctx, contractAddr, contractAddr, p.CodeID, p.Msg)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	ctx.EventManager().EmitEvent(sdk.NewEvent(
   137  		types.EventTypeGovContractResult,
   138  		sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
   139  	))
   140  	return nil
   141  }
   142  
   143  func handleSudoProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.SudoContractProposal) error {
   144  	if err := p.ValidateBasic(); err != nil {
   145  		return err
   146  	}
   147  
   148  	contractAddr, err := sdk.AccAddressFromBech32(p.Contract)
   149  	if err != nil {
   150  		return sdkerrors.Wrap(err, "contract")
   151  	}
   152  	data, err := k.Sudo(ctx, contractAddr, p.Msg)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	ctx.EventManager().EmitEvent(sdk.NewEvent(
   158  		types.EventTypeGovContractResult,
   159  		sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
   160  	))
   161  	return nil
   162  }
   163  
   164  func handleExecuteProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ExecuteContractProposal) error {
   165  	if err := p.ValidateBasic(); err != nil {
   166  		return err
   167  	}
   168  
   169  	contractAddr, err := sdk.AccAddressFromBech32(p.Contract)
   170  	if err != nil {
   171  		return sdkerrors.Wrap(err, "contract")
   172  	}
   173  	runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs)
   174  	if err != nil {
   175  		return sdkerrors.Wrap(err, "run as address")
   176  	}
   177  	data, err := k.Execute(ctx, contractAddr, runAsAddr, p.Msg, sdk.CoinAdaptersToCoins(p.Funds))
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	ctx.EventManager().EmitEvent(sdk.NewEvent(
   183  		types.EventTypeGovContractResult,
   184  		sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
   185  	))
   186  	return nil
   187  }
   188  
   189  func handleUpdateAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateAdminProposal) error {
   190  	if err := p.ValidateBasic(); err != nil {
   191  		return err
   192  	}
   193  	contractAddr, err := sdk.AccAddressFromBech32(p.Contract)
   194  	if err != nil {
   195  		return sdkerrors.Wrap(err, "contract")
   196  	}
   197  	newAdminAddr, err := sdk.AccAddressFromBech32(p.NewAdmin)
   198  	if err != nil {
   199  		return sdkerrors.Wrap(err, "run as address")
   200  	}
   201  
   202  	return k.UpdateContractAdmin(ctx, contractAddr, nil, newAdminAddr)
   203  }
   204  
   205  func handleClearAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ClearAdminProposal) error {
   206  	if err := p.ValidateBasic(); err != nil {
   207  		return err
   208  	}
   209  
   210  	contractAddr, err := sdk.AccAddressFromBech32(p.Contract)
   211  	if err != nil {
   212  		return sdkerrors.Wrap(err, "contract")
   213  	}
   214  	if err := k.ClearContractAdmin(ctx, contractAddr, nil); err != nil {
   215  		return err
   216  	}
   217  	return nil
   218  }
   219  
   220  func handlePinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.PinCodesProposal) error {
   221  	if err := p.ValidateBasic(); err != nil {
   222  		return err
   223  	}
   224  	for _, v := range p.CodeIDs {
   225  		if err := k.PinCode(ctx, v); err != nil {
   226  			return sdkerrors.Wrapf(err, "code id: %d", v)
   227  		}
   228  	}
   229  	return nil
   230  }
   231  
   232  func handleUnpinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UnpinCodesProposal) error {
   233  	if err := p.ValidateBasic(); err != nil {
   234  		return err
   235  	}
   236  	for _, v := range p.CodeIDs {
   237  		if err := k.UnpinCode(ctx, v); err != nil {
   238  			return sdkerrors.Wrapf(err, "code id: %d", v)
   239  		}
   240  	}
   241  	return nil
   242  }
   243  
   244  func handleUpdateInstantiateConfigProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateInstantiateConfigProposal) error {
   245  	if err := p.ValidateBasic(); err != nil {
   246  		return err
   247  	}
   248  
   249  	for _, accessConfigUpdate := range p.AccessConfigUpdates {
   250  		if err := k.SetAccessConfig(ctx, accessConfigUpdate.CodeID, accessConfigUpdate.InstantiatePermission); err != nil {
   251  			return sdkerrors.Wrapf(err, "code id: %d", accessConfigUpdate.CodeID)
   252  		}
   253  	}
   254  	return nil
   255  }
   256  
   257  func handleUpdateDeploymentWhitelistProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateDeploymentWhitelistProposal) error {
   258  	if err := p.ValidateBasic(); err != nil {
   259  		return err
   260  	}
   261  
   262  	var config types.AccessConfig
   263  	if len(p.DistributorAddrs) == 0 {
   264  		config.Permission = types.AccessTypeNobody
   265  	} else if types.IsAllAddress(p.DistributorAddrs) {
   266  		config.Permission = types.AccessTypeEverybody
   267  	} else {
   268  		sort.Strings(p.DistributorAddrs)
   269  		config.Permission = types.AccessTypeOnlyAddress
   270  		config.Address = strings.Join(p.DistributorAddrs, ",")
   271  	}
   272  
   273  	k.UpdateUploadAccessConfig(ctx, config)
   274  	return nil
   275  }
   276  
   277  func handleUpdateWASMContractMethodBlockedListProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateWASMContractMethodBlockedListProposal) error {
   278  	if err := p.ValidateBasic(); err != nil {
   279  		return err
   280  	}
   281  	contractAddr, err := sdk.AccAddressFromBech32(p.BlockedMethods.ContractAddr)
   282  	if err != nil {
   283  		return sdkerrors.Wrap(err, "contract")
   284  	}
   285  	if err = k.ClearContractAdmin(ctx, contractAddr, contractAddr); err != nil {
   286  		return err
   287  	}
   288  	return k.UpdateContractMethodBlockedList(ctx, p.BlockedMethods, p.IsDelete)
   289  }