github.com/aergoio/aergo@v1.3.1/contract/enterprise/execute.go (about)

     1  package enterprise
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/aergoio/aergo-lib/log"
    11  	"github.com/aergoio/aergo/consensus"
    12  
    13  	"github.com/aergoio/aergo/state"
    14  	"github.com/aergoio/aergo/types"
    15  )
    16  
    17  var (
    18  	entLogger *log.Logger
    19  
    20  	ErrNotSupportedMethod                      = errors.New("Not supported Enterprise Tx")
    21  	ErrTxEnterpriseAlreadyIncludeChangeCluster = errors.New("Enterprise Tx of Change cluster type already included in the block")
    22  )
    23  
    24  type EnterpriseContext struct {
    25  	Call    *types.CallInfo
    26  	Args    []string
    27  	ArgsAny []interface{}
    28  	Admins  [][]byte
    29  	Conf    *Conf
    30  }
    31  
    32  func init() {
    33  	entLogger = log.NewLogger("enterprise")
    34  }
    35  
    36  func (e *EnterpriseContext) IsAdminExist(addr []byte) bool {
    37  	for _, a := range e.Admins {
    38  		if bytes.Equal(a, addr) {
    39  			return true
    40  		}
    41  	}
    42  	return false
    43  }
    44  
    45  func (e *EnterpriseContext) HasConfValue(value string) bool {
    46  	if e.Conf != nil {
    47  		for _, v := range e.Conf.Values {
    48  			if v == value {
    49  				return true
    50  			}
    51  		}
    52  	}
    53  	return false
    54  }
    55  
    56  func ExecuteEnterpriseTx(bs *state.BlockState, ccc consensus.ChainConsensusCluster, scs *state.ContractState, txBody *types.TxBody,
    57  	sender, receiver *state.V, blockNo types.BlockNo) ([]*types.Event, error) {
    58  
    59  	context, err := ValidateEnterpriseTx(txBody, sender, scs, blockNo)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	var events []*types.Event
    64  	switch context.Call.Name {
    65  	case AppendAdmin:
    66  		requestAddress := types.ToAddress(context.Args[0])
    67  		err := setAdmins(scs,
    68  			append(context.Admins, requestAddress))
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  		jsonArgs, err := json.Marshal(context.Args[0])
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		events = append(events, &types.Event{
    77  			ContractAddress: receiver.ID(),
    78  			EventName:       "Append ADMIN",
    79  			EventIdx:        0,
    80  			JsonArgs:        string(jsonArgs),
    81  		})
    82  	case RemoveAdmin:
    83  		for i, v := range context.Admins {
    84  			if bytes.Equal(v, types.ToAddress(context.Args[0])) {
    85  				context.Admins = append(context.Admins[:i], context.Admins[i+1:]...)
    86  				break
    87  			}
    88  		}
    89  		err := setAdmins(scs, context.Admins)
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  		jsonArgs, err := json.Marshal(context.Args[0])
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		events = append(events, &types.Event{
    98  			ContractAddress: receiver.ID(),
    99  			EventName:       "Remove ADMIN",
   100  			EventIdx:        0,
   101  			JsonArgs:        string(jsonArgs),
   102  		})
   103  	case SetConf, AppendConf, RemoveConf:
   104  		key := context.Args[0]
   105  		err = setConf(scs, []byte(key), context.Conf)
   106  		if err != nil {
   107  			return nil, err
   108  		}
   109  		events, err = createSetEvent(receiver.ID(), key, context.Conf.Values)
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  	case EnableConf:
   114  		key := context.Args[0]
   115  		err = setConf(scs, []byte(key), context.Conf)
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  		jsonArgs, err := json.Marshal(context.Call.Args[1])
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  		events = append(events, &types.Event{
   124  			ContractAddress: receiver.ID(),
   125  			EventName:       "Enable " + strings.ToUpper(string(key)),
   126  			EventIdx:        0,
   127  			JsonArgs:        string(jsonArgs),
   128  		})
   129  	case ChangeCluster:
   130  		if bs.CCProposal != nil {
   131  			return nil, ErrTxEnterpriseAlreadyIncludeChangeCluster
   132  		}
   133  
   134  		ccReq, ok := context.ArgsAny[0].(*types.MembershipChange)
   135  		if !ok {
   136  			return nil, fmt.Errorf("invalid argument of cluster change request")
   137  		}
   138  
   139  		var (
   140  			ccChange *consensus.ConfChangePropose
   141  			err      error
   142  		)
   143  
   144  		// MakeConfChangeProposal can make different results depending on the raft status. therefore the result shouldn not be written on receipt
   145  		if ccChange, err = ccc.MakeConfChangeProposal(ccReq); err != nil {
   146  			if err != consensus.ErrorMembershipChangeSkip {
   147  				entLogger.Error().Str("cluster change", ccReq.ToString()).Err(err).Msg("Enterprise tx: failed to make cluster change proposal")
   148  			} else {
   149  				entLogger.Info().Str("cluster change", ccReq.ToString()).Msg("Enterprise tx: skipped since this node is not leader")
   150  			}
   151  		} else {
   152  			bs.CCProposal = ccChange
   153  		}
   154  
   155  		/*
   156  			jsonArgs, err := json.Marshal(context.Call.Args[0])
   157  			if err != nil {
   158  				return nil, err
   159  			}
   160  
   161  			entLogger.Debug().Str("jsonarg", string(jsonArgs)).Msg("make event")
   162  
   163  			events = append(events, &types.Event{
   164  					ContractAddress: []byte(types.AergoEnterprise),
   165  					EventName:       "ChangeCluster ",
   166  					EventIdx:        0,
   167  					JsonArgs:        string(jsonArgs),
   168  			})
   169  		*/
   170  	default:
   171  		return nil, fmt.Errorf("unsupported call in enterprise contract")
   172  	}
   173  	return events, nil
   174  }
   175  
   176  func createSetEvent(addr []byte, name string, v []string) ([]*types.Event, error) {
   177  	jsonArgs, err := json.Marshal(v)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return []*types.Event{
   182  		&types.Event{
   183  			ContractAddress: addr,
   184  			EventName:       "Set " + strings.ToUpper(name),
   185  			EventIdx:        0,
   186  			JsonArgs:        string(jsonArgs),
   187  		},
   188  	}, nil
   189  }