package common
-import "github.com/bytom/vapor/protocol/bc"
+import (
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "github.com/bytom/vapor/consensus/segwit"
+ "github.com/bytom/vapor/errors"
+ "github.com/bytom/vapor/protocol/bc"
+ "github.com/bytom/vapor/protocol/bc/types"
+)
+
+// MovUtxo store the utxo information for mov order
type MovUtxo struct {
SourceID *bc.Hash
SourcePos uint64
ControlProgram []byte
}
+// Order store all the order information
type Order struct {
- FromAssetID *bc.AssetID
- ToAssetID *bc.AssetID
- Utxo *MovUtxo
- Rate float64
+ FromAssetID *bc.AssetID
+ ToAssetID *bc.AssetID
+ Utxo *MovUtxo
+ RatioNumerator int64
+ RatioDenominator int64
+}
+
+// Rate return the exchange represented by float64
+func (o *Order) Rate() float64 {
+ if o.RatioDenominator == 0 {
+ return 0
+ }
+ rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
+ result, _ := rate.Float64()
+ return result
+}
+
+// cmpRate compares rate of x and y and returns -1 if x < y, 0 if x == y, +1 if x > y
+func (o *Order) cmpRate(other *Order) int {
+ rate := big.NewRat(o.RatioNumerator, o.RatioDenominator)
+ otherRate := big.NewRat(other.RatioNumerator, other.RatioDenominator)
+ return rate.Cmp(otherRate)
+}
+
+// Cmp first compare the rate, if rate is equals, then compare the utxo hash
+func (o *Order) Cmp(other *Order) int {
+ cmp := o.cmpRate(other)
+ if cmp == 0 {
+ if hex.EncodeToString(o.UTXOHash().Bytes()) < hex.EncodeToString(other.UTXOHash().Bytes()) {
+ return -1
+ }
+ return 1
+ }
+ return cmp
+}
+
+// OrderSlice is define for order's sort
+type OrderSlice []*Order
+
+func (o OrderSlice) Len() int { return len(o) }
+func (o OrderSlice) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
+func (o OrderSlice) Less(i, j int) bool {
+ return o[i].Cmp(o[j]) < 0
+}
+
+// NewOrderFromOutput convert txinput to order
+func NewOrderFromOutput(tx *types.Tx, outputIndex int) (*Order, error) {
+ outputID := tx.OutputID(outputIndex)
+ output, err := tx.IntraChainOutput(*outputID)
+ if err != nil {
+ return nil, err
+ }
+
+ contractArgs, err := segwit.DecodeP2WMCProgram(output.ControlProgram.Code)
+ if err != nil {
+ return nil, err
+ }
+
+ assetAmount := output.Source.Value
+ return &Order{
+ FromAssetID: assetAmount.AssetId,
+ ToAssetID: &contractArgs.RequestedAsset,
+ RatioNumerator: contractArgs.RatioNumerator,
+ RatioDenominator: contractArgs.RatioDenominator,
+ Utxo: &MovUtxo{
+ SourceID: output.Source.Ref,
+ Amount: assetAmount.Amount,
+ SourcePos: uint64(outputIndex),
+ ControlProgram: output.ControlProgram.Code,
+ },
+ }, nil
+}
+
+// NewOrderFromInput convert txoutput to order
+func NewOrderFromInput(tx *types.Tx, inputIndex int) (*Order, error) {
+ input, ok := tx.Inputs[inputIndex].TypedInput.(*types.SpendInput)
+ if !ok {
+ return nil, errors.New("input is not type of spend input")
+ }
+
+ contractArgs, err := segwit.DecodeP2WMCProgram(input.ControlProgram)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Order{
+ FromAssetID: input.AssetId,
+ ToAssetID: &contractArgs.RequestedAsset,
+ RatioNumerator: contractArgs.RatioNumerator,
+ RatioDenominator: contractArgs.RatioDenominator,
+ Utxo: &MovUtxo{
+ SourceID: &input.SourceID,
+ Amount: input.Amount,
+ SourcePos: input.SourcePosition,
+ ControlProgram: input.ControlProgram,
+ },
+ }, nil
+}
+
+// Key return the unique key for representing this order
+func (o *Order) Key() string {
+ return fmt.Sprintf("%s:%d", o.Utxo.SourceID, o.Utxo.SourcePos)
}
+// TradePair return the trade pair info
+func (o *Order) TradePair() *TradePair {
+ return &TradePair{FromAssetID: o.FromAssetID, ToAssetID: o.ToAssetID}
+}
+
+// UTXOHash calculate the utxo hash of this order
+func (o *Order) UTXOHash() *bc.Hash {
+ prog := &bc.Program{VmVersion: 1, Code: o.Utxo.ControlProgram}
+ src := &bc.ValueSource{
+ Ref: o.Utxo.SourceID,
+ Value: &bc.AssetAmount{AssetId: o.FromAssetID, Amount: o.Utxo.Amount},
+ Position: o.Utxo.SourcePos,
+ }
+ hash := bc.EntryID(bc.NewIntraChainOutput(src, prog, 0))
+ return &hash
+}
+
+// TradePair is the object for record trade pair info
type TradePair struct {
FromAssetID *bc.AssetID
ToAssetID *bc.AssetID
Count int
}
+// Key return the unique key for representing this trade pair
+func (t *TradePair) Key() string {
+ return fmt.Sprintf("%s:%s", t.FromAssetID, t.ToAssetID)
+}
+
+// Reverse return the reverse trade pair object
+func (t *TradePair) Reverse() *TradePair {
+ return &TradePair{
+ FromAssetID: t.ToAssetID,
+ ToAssetID: t.FromAssetID,
+ }
+}
+
+// MovDatabaseState is object to record DB image status
type MovDatabaseState struct {
Height uint64
Hash *bc.Hash