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
19 // TxOutput is the top level struct of tx output.
23 // Unconsumed suffixes of the commitment and witness extensible strings.
24 CommitmentSuffix []byte
27 // TypedOutput return the txoutput type.
28 TypedOutput interface {
33 // OutputCommitment return the OutputCommitment of a txoutput.
34 func (to *TxOutput) OutputCommitment() OutputCommitment {
35 switch outp := to.TypedOutput.(type) {
36 case *IntraChainOutput:
37 return outp.OutputCommitment
39 case *CrossChainOutput:
40 return outp.OutputCommitment
43 return OutputCommitment{}
47 // AssetAmount return the asset id and amount of a txoutput.
48 func (to *TxOutput) AssetAmount() bc.AssetAmount {
49 switch outp := to.TypedOutput.(type) {
50 case *IntraChainOutput:
51 return outp.AssetAmount
53 case *CrossChainOutput:
54 return outp.AssetAmount
57 return bc.AssetAmount{}
61 // ControlProgram return the control program of the txoutput
62 func (to *TxOutput) ControlProgram() []byte {
63 switch outp := to.TypedOutput.(type) {
64 case *IntraChainOutput:
65 return outp.ControlProgram
67 case *CrossChainOutput:
68 return outp.ControlProgram
75 // VMVersion return the VM version of the txoutput
76 func (to *TxOutput) VMVersion() uint64 {
77 switch outp := to.TypedOutput.(type) {
78 case *IntraChainOutput:
81 case *CrossChainOutput:
89 func (to *TxOutput) readFrom(r *blockchain.Reader) (err error) {
90 if to.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
91 return errors.Wrap(err, "reading asset version")
94 to.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
95 if to.AssetVersion != 1 {
100 if _, err = io.ReadFull(r, outType[:]); err != nil {
101 return errors.Wrap(err, "reading output type")
105 case IntraChainOutputType:
106 out := new(IntraChainOutput)
108 if out.CommitmentSuffix, err = out.OutputCommitment.readFrom(r, to.AssetVersion); err != nil {
109 return errors.Wrap(err, "reading intra-chain output commitment")
112 case CrossChainOutputType:
113 out := new(CrossChainOutput)
115 if out.CommitmentSuffix, err = out.OutputCommitment.readFrom(r, to.AssetVersion); err != nil {
116 return errors.Wrap(err, "reading cross-chain output commitment")
120 return fmt.Errorf("unsupported output type %d", outType[0])
130 // read and ignore the (empty) output witness
131 _, err = blockchain.ReadVarstr31(r)
132 return errors.Wrap(err, "reading output witness")
135 func (to *TxOutput) writeTo(w io.Writer) error {
136 if _, err := blockchain.WriteVarint63(w, to.AssetVersion); err != nil {
137 return errors.Wrap(err, "writing asset version")
140 if _, err := blockchain.WriteExtensibleString(w, to.CommitmentSuffix, to.writeOutputCommitment); err != nil {
141 return errors.Wrap(err, "writing output commitment")
144 if _, err := blockchain.WriteVarstr31(w, nil); err != nil {
145 return errors.Wrap(err, "writing witness")
151 func (to *TxOutput) writeOutputCommitment(w io.Writer) error {
152 if to.AssetVersion != 1 {
156 switch outp := to.TypedOutput.(type) {
157 case *IntraChainOutput:
158 if _, err := w.Write([]byte{IntraChainOutputType}); err != nil {
161 return outp.OutputCommitment.writeExtensibleString(w, outp.CommitmentSuffix, to.AssetVersion)
163 case *CrossChainOutput:
164 if _, err := w.Write([]byte{CrossChainOutputType}); err != nil {
167 return outp.OutputCommitment.writeExtensibleString(w, outp.CommitmentSuffix, to.AssetVersion)
174 // ComputeOutputID assembles an intra-chain(!) output entry given a spend
175 // commitment and computes and returns its corresponding entry ID.
176 func ComputeOutputID(sc *SpendCommitment) (h bc.Hash, err error) {
178 if r, ok := recover().(error); ok {
182 src := &bc.ValueSource{
184 Value: &sc.AssetAmount,
185 Position: sc.SourcePosition,
187 o := bc.NewIntraChainOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0)