import (
"encoding/hex"
"math"
+ "math/big"
"github.com/vapor/application/mov/common"
"github.com/vapor/application/mov/contract"
}
func CalcRequestAmount(fromAmount uint64, contractArg *vmutil.MagneticContractArgs) uint64 {
- return uint64(int64(fromAmount) * contractArg.RatioNumerator / contractArg.RatioDenominator)
+ res := big.NewInt(0).SetUint64(fromAmount)
+ res.Mul(res, big.NewInt(contractArg.RatioNumerator)).Div(res, big.NewInt(contractArg.RatioDenominator))
+ if !res.IsUint64() {
+ return 0
+ }
+ return res.Uint64()
}
func calcShouldPayAmount(receiveAmount uint64, contractArg *vmutil.MagneticContractArgs) uint64 {
"github.com/vapor/consensus/segwit"
dbm "github.com/vapor/database/leveldb"
"github.com/vapor/errors"
- "github.com/vapor/math/checked"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
)
errNumeratorOfRatioIsOverflow = errors.New("ratio numerator of contract args product input amount is overflow")
errLengthOfInputIsIncorrect = errors.New("length of matched tx input is not equals to actual matched tx input")
errSpendOutputIDIsIncorrect = errors.New("spend output id of matched tx is not equals to actual matched tx")
- errRequestAmountLessThenOne = errors.New("request amount of order less than one")
+ errRequestAmountMath = errors.New("request amount of order less than one or big than max of int64")
)
// MovCore represent the core logic of the match module, which include generate match transactions before packing the block,
return errRatioOfTradeLessThanZero
}
- if _, ok := checked.MulInt64(int64(fromAmount), contractArgs.RatioNumerator); !ok {
- return errNumeratorOfRatioIsOverflow
- }
-
if match.CalcRequestAmount(fromAmount, contractArgs) < 1 {
- return errRequestAmountLessThenOne
+ return errRequestAmountMath
}
return nil
}
wantError: errRatioOfTradeLessThanZero,
},
{
- desc: "ratio numerator product input amount is overflow",
+ desc: "want amount is overflow",
block: &types.Block{
Transactions: []*types.Tx{
types.NewTx(types.TxData{
Inputs: []*types.TxInput{types.NewSpendInput(nil, *mock.Btc2EthOrders[0].Utxo.SourceID, *mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.Btc2EthOrders[0].Utxo.SourcePos, []byte{0x51})},
- Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("51"), math.MaxInt64, 10))},
+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*mock.Btc2EthOrders[0].FromAssetID, mock.Btc2EthOrders[0].Utxo.Amount, mock.MustCreateP2WMCProgram(mock.ETH, testutil.MustDecodeHexString("51"), math.MaxInt64, 1))},
}),
},
},
verifyResults: []*bc.TxVerifyResult{{StatusFail: false}},
- wantError: errNumeratorOfRatioIsOverflow,
+ wantError: errRequestAmountMath,
},
}
import (
"math"
+ "math/big"
"github.com/vapor/math/checked"
)
}
return vm.pushBool(x >= min && x < max, true)
}
+
+func opMulFraction(vm *virtualMachine) error {
+ if err := vm.applyCost(8); err != nil {
+ return err
+ }
+
+ z, err := vm.popInt64(true)
+ if err != nil {
+ return err
+ }
+
+ if z == 0 {
+ return ErrDivZero
+ }
+
+ y, err := vm.popInt64(true)
+ if err != nil {
+ return err
+ }
+
+ x, err := vm.popInt64(true)
+ if err != nil {
+ return err
+ }
+
+ res := big.NewInt(x)
+ res.Mul(res, big.NewInt(y)).Div(res, big.NewInt(z))
+ if !res.IsInt64() {
+ return ErrRange
+ }
+
+ return vm.pushInt64(res.Int64(), true)
+}
deferredCost: -18,
dataStack: [][]byte{{1}},
},
+ }, {
+ op: OP_MULFRACTION,
+ startVM: &virtualMachine{
+ runLimit: 50000,
+ dataStack: [][]byte{{15}, {2}, {3}},
+ },
+ wantVM: &virtualMachine{
+ runLimit: 49992,
+ deferredCost: -18,
+ dataStack: [][]byte{{10}},
+ },
+ }, {
+ op: OP_MULFRACTION,
+ startVM: &virtualMachine{
+ runLimit: 50000,
+ dataStack: [][]byte{Int64Bytes(-654), {3}, {2}},
+ },
+ wantVM: &virtualMachine{
+ runLimit: 49992,
+ deferredCost: -18,
+ dataStack: [][]byte{Int64Bytes(-981)},
+ },
+ }, {
+ op: OP_MULFRACTION,
+ startVM: &virtualMachine{
+ runLimit: 50000,
+ dataStack: [][]byte{Int64Bytes(-654), {3}, {}},
+ },
+ wantVM: &virtualMachine{
+ runLimit: 49992,
+ deferredCost: -18,
+ dataStack: [][]byte{},
+ },
+ wantErr: ErrDivZero,
}}
numops := []Op{
OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT, OP_BOOLAND,
OP_BOOLOR, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN,
OP_LESSTHANOREQUAL, OP_GREATERTHAN, OP_GREATERTHANOREQUAL, OP_MIN, OP_MAX, OP_WITHIN,
+ OP_MULFRACTION,
}
for _, op := range numops {
{fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)), true},
{fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)/2), false},
{fmt.Sprintf("%d 2 LSHIFT", int64(math.MinInt64)/2), true},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MaxInt64)/2-1, 2, 1), false},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MaxInt64)/2+1, 2, 1), true},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MinInt64)/2+1, 2, 1), false},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MinInt64)/2-1, 2, 1), true},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MaxInt64), 3, 2), true},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MaxInt64), 2, 3), false},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MinInt64), 3, 2), true},
+ {fmt.Sprintf("%d %d %d MULFRACTION", int64(math.MinInt64), 2, 3), false},
}
for i, c := range cases {
OP_MIN Op = 0xa3
OP_MAX Op = 0xa4
OP_WITHIN Op = 0xa5
+ OP_MULFRACTION Op = 0xa6
OP_SHA256 Op = 0xa8
OP_SHA3 Op = 0xaa
OP_MIN: {OP_MIN, "MIN", opMin},
OP_MAX: {OP_MAX, "MAX", opMax},
OP_WITHIN: {OP_WITHIN, "WITHIN", opWithin},
+ OP_MULFRACTION: {OP_MULFRACTION, "MULFRACTION", opMulFraction},
OP_SHA256: {OP_SHA256, "SHA256", opSha256},
OP_SHA3: {OP_SHA3, "SHA3", opSha3},
// PICK [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount]
// 3 [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount 3]
// ROLL [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator]
-// MUL [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset (exchangeAmount * ratioDenominator)]
-// 2 [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset (exchangeAmount * ratioDenominator) 2]
-// ROLL [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset (exchangeAmount * ratioDenominator) ratioNumerator]
-// DIV [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
+// 3 [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator 3]
+// ROLL [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset exchangeAmount ratioDenominator ratioNumerator]
+// MULFRACTION [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
// AMOUNT [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount]
// OVER [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount]
// 0 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount 0]
// AMOUNT [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount]
// 2 [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount 2]
// ROLL [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator]
-// MUL [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset (valueAmount * ratioNumerator)]
-// 2 [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset (valueAmount * ratioNumerator) 2]
-// ROLL [... sellerKey standardProgram sellerProgram requestedAsset (valueAmount * ratioNumerator) ratioDenominator]
-// DIV [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
+// 3 [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator 3]
+// ROLL [... sellerKey standardProgram sellerProgram requestedAsset valueAmount ratioNumerator ratioDenominator]
+// MULFRACTION [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
// DUP [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount]
// 0 [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount 0]
// GREATERTHAN [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount (requestedAmount > 0)]
builder.AddOp(vm.OP_PICK)
builder.AddOp(vm.OP_3)
builder.AddOp(vm.OP_ROLL)
- builder.AddOp(vm.OP_MUL)
- builder.AddOp(vm.OP_ROT)
- builder.AddOp(vm.OP_DIV)
+ builder.AddOp(vm.OP_3)
+ builder.AddOp(vm.OP_ROLL)
+ builder.AddOp(vm.OP_MULFRACTION)
builder.AddOp(vm.OP_AMOUNT)
builder.AddOp(vm.OP_OVER)
builder.AddOp(vm.OP_0)
builder.SetJumpTarget(1)
builder.AddOp(vm.OP_AMOUNT)
builder.AddOp(vm.OP_ROT)
- builder.AddOp(vm.OP_MUL)
- builder.AddOp(vm.OP_ROT)
- builder.AddOp(vm.OP_DIV)
+ builder.AddOp(vm.OP_3)
+ builder.AddOp(vm.OP_ROLL)
+ builder.AddOp(vm.OP_MULFRACTION)
builder.AddOp(vm.OP_DUP)
builder.AddOp(vm.OP_0)
builder.AddOp(vm.OP_GREATERTHAN)