7 "github.com/vapor/encoding/blockchain"
8 "github.com/vapor/errors"
9 "github.com/vapor/protocol/bc"
12 // serflag variables for output types.
14 IntraChainOutputType uint8 = iota
20 // TxOutput is the top level struct of tx output.
24 // Unconsumed suffixes of the commitment and witness extensible strings.
25 CommitmentSuffix []byte
28 // TypedOutput return the txoutput type.
29 TypedOutput interface {
34 // OutputCommitment return the OutputCommitment of a txoutput.
35 func (to *TxOutput) OutputCommitment() OutputCommitment {
36 switch outp := to.TypedOutput.(type) {
37 case *IntraChainOutput:
38 return outp.OutputCommitment
40 case *CrossChainOutput:
41 return outp.OutputCommitment
44 return outp.OutputCommitment
47 return OutputCommitment{}
51 // AssetAmount return the asset id and amount of a txoutput.
52 func (to *TxOutput) AssetAmount() bc.AssetAmount {
53 switch outp := to.TypedOutput.(type) {
54 case *IntraChainOutput:
55 return outp.AssetAmount
57 case *CrossChainOutput:
58 return outp.AssetAmount
61 return outp.AssetAmount
64 return bc.AssetAmount{}
68 // ControlProgram return the control program of the txoutput
69 func (to *TxOutput) ControlProgram() []byte {
70 switch outp := to.TypedOutput.(type) {
71 case *IntraChainOutput:
72 return outp.ControlProgram
74 case *CrossChainOutput:
75 return outp.ControlProgram
78 return outp.ControlProgram
85 // VMVersion return the VM version of the txoutput
86 func (to *TxOutput) VMVersion() uint64 {
87 switch outp := to.TypedOutput.(type) {
88 case *IntraChainOutput:
91 case *CrossChainOutput:
102 func (to *TxOutput) readFrom(r *blockchain.Reader) (err error) {
103 if to.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
104 return errors.Wrap(err, "reading asset version")
107 to.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
108 if to.AssetVersion != 1 {
113 if _, err = io.ReadFull(r, outType[:]); err != nil {
114 return errors.Wrap(err, "reading output type")
118 case IntraChainOutputType:
119 out := new(IntraChainOutput)
121 if out.CommitmentSuffix, err = out.OutputCommitment.readFrom(r, to.AssetVersion); err != nil {
122 return errors.Wrap(err, "reading intra-chain output commitment")
125 case CrossChainOutputType:
126 out := new(CrossChainOutput)
128 if out.CommitmentSuffix, err = out.OutputCommitment.readFrom(r, to.AssetVersion); err != nil {
129 return errors.Wrap(err, "reading cross-chain output commitment")
133 out := new(VoteTxOutput)
135 if out.Vote, err = blockchain.ReadVarstr31(r); err != nil {
136 return errors.Wrap(err, "reading vote output vote")
139 if out.CommitmentSuffix, err = out.OutputCommitment.readFrom(r, to.AssetVersion); err != nil {
140 return errors.Wrap(err, "reading vote output commitment")
144 return fmt.Errorf("unsupported output type %d", outType[0])
154 // read and ignore the (empty) output witness
155 _, err = blockchain.ReadVarstr31(r)
156 return errors.Wrap(err, "reading output witness")
159 func (to *TxOutput) writeTo(w io.Writer) error {
160 if _, err := blockchain.WriteVarint63(w, to.AssetVersion); err != nil {
161 return errors.Wrap(err, "writing asset version")
164 if _, err := blockchain.WriteExtensibleString(w, to.CommitmentSuffix, to.writeOutputCommitment); err != nil {
165 return errors.Wrap(err, "writing output commitment")
168 if _, err := blockchain.WriteVarstr31(w, nil); err != nil {
169 return errors.Wrap(err, "writing witness")
175 func (to *TxOutput) writeOutputCommitment(w io.Writer) error {
176 if to.AssetVersion != 1 {
180 switch outp := to.TypedOutput.(type) {
181 case *IntraChainOutput:
182 if _, err := w.Write([]byte{IntraChainOutputType}); err != nil {
185 return outp.OutputCommitment.writeExtensibleString(w, outp.CommitmentSuffix, to.AssetVersion)
187 case *CrossChainOutput:
188 if _, err := w.Write([]byte{CrossChainOutputType}); err != nil {
191 return outp.OutputCommitment.writeExtensibleString(w, outp.CommitmentSuffix, to.AssetVersion)
194 if _, err := w.Write([]byte{VoteOutputType}); err != nil {
197 if _, err := blockchain.WriteVarstr31(w, outp.Vote); err != nil {
200 return outp.OutputCommitment.writeExtensibleString(w, outp.CommitmentSuffix, to.AssetVersion)
207 // ComputeOutputID assembles an intra-chain(!) output entry given a spend
208 // commitment and computes and returns its corresponding entry ID.
209 func ComputeOutputID(sc *SpendCommitment, inputType uint8, vote []byte) (h bc.Hash, err error) {
211 if r, ok := recover().(error); ok {
215 src := &bc.ValueSource{
217 Value: &sc.AssetAmount,
218 Position: sc.SourcePosition,
223 o = bc.NewIntraChainOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0)
224 case UnvoteInputType:
225 o = bc.NewVoteOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0, vote)
227 return h, fmt.Errorf("Input type error:[%v]", inputType)