7 "github.com/bytom/bytom/encoding/blockchain"
8 "github.com/bytom/bytom/errors"
9 "github.com/bytom/bytom/protocol/bc"
13 // OriginalOutputType represent the type of original output
14 OriginalOutputType uint8 = iota
16 // VoteOutputType represent the type of vote output
20 // TxOutput is the top level struct of tx output.
21 type TxOutput struct {
24 // Unconsumed suffixes of the commitment and witness extensible strings.
25 CommitmentSuffix []byte
29 // TypedOutput return the txoutput type.
30 type TypedOutput interface {
32 readFrom(*blockchain.Reader) error
33 writeTo(io.Writer) error
36 var outputTypeMap = map[uint8]func() TypedOutput{
37 OriginalOutputType: func() TypedOutput { return &originalTxOutput{} },
38 VoteOutputType: func() TypedOutput { return &VoteOutput{} },
41 func parseTypedOutput(r *blockchain.Reader) (TypedOutput, error) {
43 if _, err := io.ReadFull(r, outType[:]); err != nil {
44 return nil, errors.Wrap(err, "reading output type")
47 newOutFun, ok := outputTypeMap[outType[0]]
49 return nil, fmt.Errorf("unsupported output type %d", outType[0])
52 return newOutFun(), nil
55 func (to *TxOutput) readFrom(r *blockchain.Reader) (err error) {
56 if to.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
57 return errors.Wrap(err, "reading asset version")
60 to.TypedOutput, err = parseTypedOutput(r)
62 return errors.Wrap(err, "parse typedOutput")
65 if to.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(reader *blockchain.Reader) error {
66 if err := to.TypedOutput.readFrom(reader); err != nil {
70 return to.OutputCommitment.readFrom(reader, to.AssetVersion)
72 return errors.Wrap(err, "reading output commitment")
75 // read and ignore the (empty) output witness
76 _, err = blockchain.ReadVarstr31(r)
77 return errors.Wrap(err, "reading output witness")
80 func (to *TxOutput) writeTo(w io.Writer) error {
81 if _, err := blockchain.WriteVarint63(w, to.AssetVersion); err != nil {
82 return errors.Wrap(err, "writing asset version")
85 if _, err := w.Write([]byte{to.OutputType()}); err != nil {
89 if _, err := blockchain.WriteExtensibleString(w, to.CommitmentSuffix, func(writer io.Writer) error {
90 if err := to.TypedOutput.writeTo(writer); err != nil {
94 return to.OutputCommitment.writeTo(writer, to.AssetVersion)
96 return errors.Wrap(err, "writing output commitment")
99 if _, err := blockchain.WriteVarstr31(w, nil); err != nil {
100 return errors.Wrap(err, "writing witness")
105 // ComputeOutputID assembles an output entry given a spend commitment and
106 // computes and returns its corresponding entry ID.
107 func ComputeOutputID(sc *SpendCommitment) (h bc.Hash, err error) {
109 if r, ok := recover().(error); ok {
113 src := &bc.ValueSource{
115 Value: &sc.AssetAmount,
116 Position: sc.SourcePosition,
119 o := bc.NewOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, &bc.StateData{StateData: sc.StateData}, 0)
120 return bc.EntryID(o), nil