github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/bc/types/txinput.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/bytom/bytom/encoding/blockchain"
     8  	"github.com/bytom/bytom/errors"
     9  	"github.com/bytom/bytom/protocol/bc"
    10  )
    11  
    12  // serflag variables for input types.
    13  const (
    14  	IssuanceInputType uint8 = iota
    15  	SpendInputType
    16  	CoinbaseInputType
    17  	VetoInputType
    18  )
    19  
    20  var inputTypeMap = map[uint8]func() TypedInput{
    21  	IssuanceInputType: func() TypedInput { return &IssuanceInput{} },
    22  	SpendInputType:    func() TypedInput { return &SpendInput{} },
    23  	CoinbaseInputType: func() TypedInput { return &CoinbaseInput{} },
    24  	VetoInputType:     func() TypedInput { return &VetoInput{} },
    25  }
    26  
    27  func parseTypedInput(r *blockchain.Reader) (TypedInput, error) {
    28  	var inputType [1]byte
    29  	if _, err := io.ReadFull(r, inputType[:]); err != nil {
    30  		return nil, errors.Wrap(err, "reading input type")
    31  	}
    32  
    33  	newInFun, ok := inputTypeMap[inputType[0]]
    34  	if !ok {
    35  		return nil, fmt.Errorf("unsupported input type %d", inputType[0])
    36  	}
    37  
    38  	return newInFun(), nil
    39  }
    40  
    41  type (
    42  	// TxInput is the top level struct of tx input.
    43  	TxInput struct {
    44  		AssetVersion uint64
    45  		TypedInput
    46  		CommitmentSuffix []byte
    47  		WitnessSuffix    []byte
    48  	}
    49  
    50  	// TypedInput return the txinput type.
    51  	TypedInput interface {
    52  		InputType() uint8
    53  		AssetID() bc.AssetID
    54  		readCommitment(*blockchain.Reader) error
    55  		readWitness(*blockchain.Reader) error
    56  		writeCommitment(io.Writer, uint64) error
    57  		writeWitness(w io.Writer) error
    58  	}
    59  )
    60  
    61  // Amount return the asset amount of the txinput
    62  func (t *TxInput) Amount() uint64 {
    63  	switch inp := t.TypedInput.(type) {
    64  	case *IssuanceInput:
    65  		return inp.Amount
    66  	case *SpendInput:
    67  		return inp.Amount
    68  	case *VetoInput:
    69  		return inp.Amount
    70  	}
    71  	return 0
    72  }
    73  
    74  // Arguments get the args for the input
    75  func (t *TxInput) Arguments() [][]byte {
    76  	switch inp := t.TypedInput.(type) {
    77  	case *IssuanceInput:
    78  		return inp.Arguments
    79  	case *SpendInput:
    80  		return inp.Arguments
    81  	case *VetoInput:
    82  		return inp.Arguments
    83  	}
    84  	return nil
    85  }
    86  
    87  // ControlProgram return the control program of the spend input
    88  func (t *TxInput) ControlProgram() []byte {
    89  	switch inp := t.TypedInput.(type) {
    90  	case *SpendInput:
    91  		return inp.ControlProgram
    92  	case *VetoInput:
    93  		return inp.ControlProgram
    94  	case *IssuanceInput:
    95  		return inp.IssuanceProgram
    96  	}
    97  	return nil
    98  }
    99  
   100  // SetArguments set the args for the input
   101  func (t *TxInput) SetArguments(args [][]byte) {
   102  	switch inp := t.TypedInput.(type) {
   103  	case *IssuanceInput:
   104  		inp.Arguments = args
   105  	case *SpendInput:
   106  		inp.Arguments = args
   107  	case *VetoInput:
   108  		inp.Arguments = args
   109  	}
   110  }
   111  
   112  // SpentOutputID calculate the hash of spended output
   113  func (t *TxInput) SpentOutputID() (o bc.Hash, err error) {
   114  	switch inp := t.TypedInput.(type) {
   115  	case *SpendInput:
   116  		o, err = ComputeOutputID(&inp.SpendCommitment, inp.InputType(), nil)
   117  	case *VetoInput:
   118  		o, err = ComputeOutputID(&inp.SpendCommitment, inp.InputType(), inp.Vote)
   119  	}
   120  	return o, err
   121  }
   122  
   123  func (t *TxInput) readFrom(r *blockchain.Reader) (err error) {
   124  	if t.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
   125  		return err
   126  	}
   127  
   128  	t.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
   129  		if t.AssetVersion != 1 {
   130  			return nil
   131  		}
   132  
   133  		if t.TypedInput, err = parseTypedInput(r); err != nil {
   134  			return err
   135  		}
   136  
   137  		return t.readCommitment(r)
   138  	})
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	t.WitnessSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
   144  		if t.AssetVersion == 1 {
   145  			return t.readWitness(r)
   146  		}
   147  
   148  		return nil
   149  	})
   150  
   151  	return err
   152  }
   153  
   154  func (t *TxInput) writeTo(w io.Writer) error {
   155  	if _, err := blockchain.WriteVarint63(w, t.AssetVersion); err != nil {
   156  		return errors.Wrap(err, "writing asset version")
   157  	}
   158  
   159  	if _, err := blockchain.WriteExtensibleString(w, t.CommitmentSuffix, t.writeInputCommitment); err != nil {
   160  		return errors.Wrap(err, "writing input commitment")
   161  	}
   162  
   163  	_, err := blockchain.WriteExtensibleString(w, t.WitnessSuffix, t.writeInputWitness)
   164  	return errors.Wrap(err, "writing input witness")
   165  }
   166  
   167  func (t *TxInput) writeInputCommitment(w io.Writer) (err error) {
   168  	if t.AssetVersion == 1 {
   169  		return t.writeCommitment(w, t.AssetVersion)
   170  	}
   171  	return nil
   172  }
   173  
   174  func (t *TxInput) writeInputWitness(w io.Writer) error {
   175  	if t.AssetVersion == 1 {
   176  		return t.writeWitness(w)
   177  	}
   178  	return nil
   179  }