github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/blockchain/txbuilder/actions.go (about)

     1  package txbuilder
     2  
     3  import (
     4  	"context"
     5  	stdjson "encoding/json"
     6  	"errors"
     7  
     8  	"github.com/bytom/bytom/common"
     9  	"github.com/bytom/bytom/consensus"
    10  	"github.com/bytom/bytom/encoding/json"
    11  	"github.com/bytom/bytom/protocol/bc"
    12  	"github.com/bytom/bytom/protocol/bc/types"
    13  	"github.com/bytom/bytom/protocol/vm/vmutil"
    14  )
    15  
    16  // DecodeControlAddressAction convert input data to action struct
    17  func DecodeControlAddressAction(data []byte) (Action, error) {
    18  	a := new(controlAddressAction)
    19  	err := stdjson.Unmarshal(data, a)
    20  	return a, err
    21  }
    22  
    23  type controlAddressAction struct {
    24  	bc.AssetAmount
    25  	Address string `json:"address"`
    26  }
    27  
    28  func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) error {
    29  	var missing []string
    30  	if a.Address == "" {
    31  		missing = append(missing, "address")
    32  	}
    33  	if a.AssetId.IsZero() {
    34  		missing = append(missing, "asset_id")
    35  	}
    36  	if a.Amount == 0 {
    37  		missing = append(missing, "amount")
    38  	}
    39  	if len(missing) > 0 {
    40  		return MissingFieldsError(missing...)
    41  	}
    42  
    43  	address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	redeemContract := address.ScriptAddress()
    48  	program := []byte{}
    49  
    50  	switch address.(type) {
    51  	case *common.AddressWitnessPubKeyHash:
    52  		program, err = vmutil.P2WPKHProgram(redeemContract)
    53  	case *common.AddressWitnessScriptHash:
    54  		program, err = vmutil.P2WSHProgram(redeemContract)
    55  	default:
    56  		return errors.New("unsupport address type")
    57  	}
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	out := types.NewOriginalTxOutput(*a.AssetId, a.Amount, program, nil)
    63  	return b.AddOutput(out)
    64  }
    65  
    66  func (a *controlAddressAction) ActionType() string {
    67  	return "control_address"
    68  }
    69  
    70  // DecodeControlProgramAction convert input data to action struct
    71  func DecodeControlProgramAction(data []byte) (Action, error) {
    72  	a := new(controlProgramAction)
    73  	err := stdjson.Unmarshal(data, a)
    74  	return a, err
    75  }
    76  
    77  type controlProgramAction struct {
    78  	bc.AssetAmount
    79  	Program json.HexBytes `json:"control_program"`
    80  }
    81  
    82  func (a *controlProgramAction) Build(ctx context.Context, b *TemplateBuilder) error {
    83  	var missing []string
    84  	if len(a.Program) == 0 {
    85  		missing = append(missing, "control_program")
    86  	}
    87  	if a.AssetId.IsZero() {
    88  		missing = append(missing, "asset_id")
    89  	}
    90  	if a.Amount == 0 {
    91  		missing = append(missing, "amount")
    92  	}
    93  	if len(missing) > 0 {
    94  		return MissingFieldsError(missing...)
    95  	}
    96  
    97  	out := types.NewOriginalTxOutput(*a.AssetId, a.Amount, a.Program, nil)
    98  	return b.AddOutput(out)
    99  }
   100  
   101  func (a *controlProgramAction) ActionType() string {
   102  	return "control_program"
   103  }
   104  
   105  // DecodeRetireAction convert input data to action struct
   106  func DecodeRetireAction(data []byte) (Action, error) {
   107  	a := new(retireAction)
   108  	err := stdjson.Unmarshal(data, a)
   109  	return a, err
   110  }
   111  
   112  type retireAction struct {
   113  	bc.AssetAmount
   114  	Arbitrary json.HexBytes `json:"arbitrary"`
   115  }
   116  
   117  func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error {
   118  	var missing []string
   119  	if a.AssetId.IsZero() {
   120  		missing = append(missing, "asset_id")
   121  	}
   122  	if a.Amount == 0 {
   123  		missing = append(missing, "amount")
   124  	}
   125  	if len(missing) > 0 {
   126  		return MissingFieldsError(missing...)
   127  	}
   128  
   129  	program, err := vmutil.RetireProgram(a.Arbitrary)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	out := types.NewOriginalTxOutput(*a.AssetId, a.Amount, program, nil)
   134  	return b.AddOutput(out)
   135  }
   136  
   137  func (a *retireAction) ActionType() string {
   138  	return "retire"
   139  }
   140  
   141  // DecodeRegisterAction convert input data to action struct
   142  func DecodeRegisterAction(data []byte) (Action, error) {
   143  	a := new(registerAction)
   144  	return a, stdjson.Unmarshal(data, a)
   145  }
   146  
   147  type registerAction struct {
   148  	bc.AssetAmount
   149  	Contract json.HexBytes `json:"contract"`
   150  }
   151  
   152  func (a *registerAction) Build(ctx context.Context, b *TemplateBuilder) error {
   153  	var missing []string
   154  	if a.AssetId.IsZero() {
   155  		missing = append(missing, "asset_id")
   156  	}
   157  	if a.Amount == 0 {
   158  		missing = append(missing, "amount")
   159  	}
   160  	if len(a.Contract) == 0 {
   161  		missing = append(missing, "contract")
   162  	}
   163  	if len(missing) > 0 {
   164  		return MissingFieldsError(missing...)
   165  	}
   166  
   167  	if a.AssetId.String() != consensus.BTMAssetID.String() {
   168  		return errors.New("register contract action asset must be BTM")
   169  	}
   170  
   171  	if a.Amount < consensus.BCRPRequiredBTMAmount {
   172  		return errors.New("less than BCRP required BTM amount")
   173  	}
   174  
   175  	program, err := vmutil.RegisterProgram(a.Contract)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	out := types.NewOriginalTxOutput(*a.AssetId, a.Amount, program, [][]byte{})
   180  	return b.AddOutput(out)
   181  }
   182  
   183  func (a *registerAction) ActionType() string {
   184  	return "register_contract"
   185  }
   186  
   187  // DecodeVoteOutputAction convert input data to action struct
   188  func DecodeVoteOutputAction(data []byte) (Action, error) {
   189  	a := new(voteOutputAction)
   190  	err := stdjson.Unmarshal(data, a)
   191  	return a, err
   192  }
   193  
   194  type voteOutputAction struct {
   195  	bc.AssetAmount
   196  	Address string        `json:"address"`
   197  	Vote    json.HexBytes `json:"vote"`
   198  }
   199  
   200  func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error {
   201  	var missing []string
   202  	if a.Address == "" {
   203  		missing = append(missing, "address")
   204  	}
   205  	if a.AssetId.IsZero() {
   206  		missing = append(missing, "asset_id")
   207  	}
   208  	if a.Amount == 0 {
   209  		missing = append(missing, "amount")
   210  	}
   211  	if len(a.Vote) == 0 {
   212  		missing = append(missing, "vote")
   213  	}
   214  	if len(missing) > 0 {
   215  		return MissingFieldsError(missing...)
   216  	}
   217  
   218  	address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
   219  	if err != nil {
   220  		return err
   221  	}
   222  
   223  	redeemContract := address.ScriptAddress()
   224  	program := []byte{}
   225  	switch address.(type) {
   226  	case *common.AddressWitnessPubKeyHash:
   227  		program, err = vmutil.P2WPKHProgram(redeemContract)
   228  	case *common.AddressWitnessScriptHash:
   229  		program, err = vmutil.P2WSHProgram(redeemContract)
   230  	default:
   231  		return errors.New("unsupport address type")
   232  	}
   233  	if err != nil {
   234  		return err
   235  	}
   236  
   237  	out := types.NewVoteOutput(*a.AssetId, a.Amount, program, a.Vote, nil)
   238  	return b.AddOutput(out)
   239  }
   240  
   241  func (a *voteOutputAction) ActionType() string {
   242  	return "vote_output"
   243  }