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 }