OSDN Git Service

11d89bb16cc21e3315802e9a01fa98c344acf75a
[bytom/vapor.git] / application / mov / common / type.go
1 package common
2
3 import (
4         "encoding/hex"
5         "fmt"
6         "math/big"
7
8         "github.com/bytom/vapor/consensus/segwit"
9         "github.com/bytom/vapor/errors"
10         "github.com/bytom/vapor/protocol/bc"
11         "github.com/bytom/vapor/protocol/bc/types"
12 )
13
14 // MovUtxo store the utxo information for mov order
15 type MovUtxo struct {
16         SourceID       *bc.Hash
17         SourcePos      uint64
18         Amount         uint64
19         ControlProgram []byte
20 }
21
22 // Order store all the order information
23 type Order struct {
24         FromAssetID      *bc.AssetID
25         ToAssetID        *bc.AssetID
26         Utxo             *MovUtxo
27         RatioNumerator   int64
28         RatioDenominator int64
29 }
30
31 // Rate return the exchange represented by float64
32 func (o *Order) Rate() float64 {
33         if o.RatioDenominator == 0 {
34                 return 0
35         }
36         rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
37         result, _ := rate.Float64()
38         return result
39 }
40
41 // cmpRate compares rate of x and y and returns -1 if x <  y, 0 if x == y, +1 if x >  y
42 func (o *Order) cmpRate(other *Order) int {
43         rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
44         otherRate := big.NewRat(other.RatioNumerator, other.RatioDenominator)
45         return rate.Cmp(otherRate)
46 }
47
48 // Cmp first compare the rate, if rate is equals, then compare the utxo hash
49 func (o *Order) Cmp(other *Order) int {
50         cmp := o.cmpRate(other)
51         if cmp == 0 {
52                 if hex.EncodeToString(o.UTXOHash().Bytes()) < hex.EncodeToString(other.UTXOHash().Bytes()) {
53                         return -1
54                 }
55                 return 1
56         }
57         return cmp
58 }
59
60 // OrderSlice is define for order's sort
61 type OrderSlice []*Order
62
63 func (o OrderSlice) Len() int      { return len(o) }
64 func (o OrderSlice) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
65 func (o OrderSlice) Less(i, j int) bool {
66         return o[i].Cmp(o[j]) < 0
67 }
68
69 // NewOrderFromOutput convert txinput to order
70 func NewOrderFromOutput(tx *types.Tx, outputIndex int) (*Order, error) {
71         outputID := tx.OutputID(outputIndex)
72         output, err := tx.IntraChainOutput(*outputID)
73         if err != nil {
74                 return nil, err
75         }
76
77         contractArgs, err := segwit.DecodeP2WMCProgram(output.ControlProgram.Code)
78         if err != nil {
79                 return nil, err
80         }
81
82         assetAmount := output.Source.Value
83         return &Order{
84                 FromAssetID:      assetAmount.AssetId,
85                 ToAssetID:        &contractArgs.RequestedAsset,
86                 RatioNumerator:   contractArgs.RatioNumerator,
87                 RatioDenominator: contractArgs.RatioDenominator,
88                 Utxo: &MovUtxo{
89                         SourceID:       output.Source.Ref,
90                         Amount:         assetAmount.Amount,
91                         SourcePos:      uint64(outputIndex),
92                         ControlProgram: output.ControlProgram.Code,
93                 },
94         }, nil
95 }
96
97 // NewOrderFromInput convert txoutput to order
98 func NewOrderFromInput(tx *types.Tx, inputIndex int) (*Order, error) {
99         input, ok := tx.Inputs[inputIndex].TypedInput.(*types.SpendInput)
100         if !ok {
101                 return nil, errors.New("input is not type of spend input")
102         }
103
104         contractArgs, err := segwit.DecodeP2WMCProgram(input.ControlProgram)
105         if err != nil {
106                 return nil, err
107         }
108
109         return &Order{
110                 FromAssetID:      input.AssetId,
111                 ToAssetID:        &contractArgs.RequestedAsset,
112                 RatioNumerator:   contractArgs.RatioNumerator,
113                 RatioDenominator: contractArgs.RatioDenominator,
114                 Utxo: &MovUtxo{
115                         SourceID:       &input.SourceID,
116                         Amount:         input.Amount,
117                         SourcePos:      input.SourcePosition,
118                         ControlProgram: input.ControlProgram,
119                 },
120         }, nil
121 }
122
123 // Key return the unique key for representing this order
124 func (o *Order) Key() string {
125         return fmt.Sprintf("%s:%d", o.Utxo.SourceID, o.Utxo.SourcePos)
126 }
127
128 // TradePair return the trade pair info
129 func (o *Order) TradePair() *TradePair {
130         return &TradePair{FromAssetID: o.FromAssetID, ToAssetID: o.ToAssetID}
131 }
132
133 // UTXOHash calculate the utxo hash of this order
134 func (o *Order) UTXOHash() *bc.Hash {
135         prog := &bc.Program{VmVersion: 1, Code: o.Utxo.ControlProgram}
136         src := &bc.ValueSource{
137                 Ref:      o.Utxo.SourceID,
138                 Value:    &bc.AssetAmount{AssetId: o.FromAssetID, Amount: o.Utxo.Amount},
139                 Position: o.Utxo.SourcePos,
140         }
141         hash := bc.EntryID(bc.NewIntraChainOutput(src, prog, 0))
142         return &hash
143 }
144
145 // TradePair is the object for record trade pair info
146 type TradePair struct {
147         FromAssetID *bc.AssetID
148         ToAssetID   *bc.AssetID
149         Count       int
150 }
151
152 // Key return the unique key for representing this trade pair
153 func (t *TradePair) Key() string {
154         return fmt.Sprintf("%s:%s", t.FromAssetID, t.ToAssetID)
155 }
156
157 // Reverse return the reverse trade pair object
158 func (t *TradePair) Reverse() *TradePair {
159         return &TradePair{
160                 FromAssetID: t.ToAssetID,
161                 ToAssetID:   t.FromAssetID,
162         }
163 }
164
165 // MovDatabaseState is object to record DB image status
166 type MovDatabaseState struct {
167         Height uint64
168         Hash   *bc.Hash
169 }