Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

send order hash during failed match validations #130

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ COPY . .
ARG SUBNET_EVM_COMMIT
ARG CURRENT_BRANCH

RUN export SUBNET_EVM_COMMIT=$SUBNET_EVM_COMMIT && export CURRENT_BRANCH=$CURRENT_BRANCH && ./scripts/build.sh /build/o1Fg94YukvVRijwyThAavybVfwVJH3dhyz94g6qYRGdQ5Arqp
RUN export SUBNET_EVM_COMMIT=$SUBNET_EVM_COMMIT && export CURRENT_BRANCH=$CURRENT_BRANCH && ./scripts/build.sh /build/jvrKsTB9MfYGnAXtxbzFYpXKceXr9J8J8ej6uWGrYM5tXswhJ

# ============= Cleanup Stage ================
FROM avaplatform/avalanchego:$AVALANCHE_VERSION AS builtImage

# Copy the evm binary into the correct location in the container
COPY --from=builder /build/o1Fg94YukvVRijwyThAavybVfwVJH3dhyz94g6qYRGdQ5Arqp /avalanchego/build/plugins/o1Fg94YukvVRijwyThAavybVfwVJH3dhyz94g6qYRGdQ5Arqp
COPY --from=builder /build/jvrKsTB9MfYGnAXtxbzFYpXKceXr9J8J8ej6uWGrYM5tXswhJ /avalanchego/build/plugins/jvrKsTB9MfYGnAXtxbzFYpXKceXr9J8J8ej6uWGrYM5tXswhJ
4 changes: 4 additions & 0 deletions genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"maxBlockGasCost": 5000000,
"blockGasCostStep": 10000
},
"contractNativeMinterConfig": {
"blockTimestamp": 0,
"adminAddresses": ["0x70997970C51812dc3A010C7d01b50e0d17dc79C8","0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"]
},
"contractDeployerAllowListConfig": {
"blockTimestamp": 0,
"adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC","0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]
Expand Down
2 changes: 1 addition & 1 deletion plugin/evm/orderbook/contract_events_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (cep *ContractEventsProcessor) handleOrderBookEvent(event *types.Log) {
}
orderId := event.Topics[1]
if !removed {
log.Info("OrderMatchingError", "args", args, "orderId", orderId.String(), "number", event.BlockNumber)
log.Info("OrderMatchingError", "args", args, "orderId", orderId.String(), "TxHash", event.TxHash, "number", event.BlockNumber)
if err := cep.database.SetOrderStatus(orderId, Execution_Failed, args["err"].(string), event.BlockNumber); err != nil {
log.Error("error in SetOrderStatus", "method", "OrderMatchingError", "err", err)
return
Expand Down
1 change: 1 addition & 0 deletions plugin/evm/orderbook/matching_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func (pipeline *MatchingPipeline) Run(blockNumber *big.Int) bool {
// reset ticker
pipeline.MatchingTicker.Reset(matchingTickerDuration)
markets := pipeline.GetActiveMarkets()
log.Info("MatchingPipeline:Run", "blockNumber", blockNumber)

if len(markets) == 0 {
return false
Expand Down
18 changes: 15 additions & 3 deletions precompile/contracts/juror/ioc_orders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,10 @@ func TestValidateExecuteIOCOrder(t *testing.T) {
ReduceOnly: false,
},
}
_, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
m, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
assert.EqualError(t, err, "not ioc order")
hash, _ := order.Hash()
assert.Equal(t, m.OrderHash, hash)
})

t.Run("ioc expired", func(t *testing.T) {
Expand All @@ -458,8 +460,10 @@ func TestValidateExecuteIOCOrder(t *testing.T) {
}
mockBibliophile.EXPECT().GetTimeStamp().Return(uint64(1000))

_, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
m, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
assert.EqualError(t, err, "ioc expired")
hash, _ := order.Hash()
assert.Equal(t, m.OrderHash, hash)
})

t.Run("valid order", func(t *testing.T) {
Expand All @@ -485,8 +489,16 @@ func TestValidateExecuteIOCOrder(t *testing.T) {
mockBibliophile.EXPECT().IOC_GetOrderStatus(hash).Return(int64(1))
mockBibliophile.EXPECT().IOC_GetBlockPlaced(hash).Return(big.NewInt(21))

_, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
m, err := validateExecuteIOCOrder(mockBibliophile, &order, Long, big.NewInt(10))
assert.Nil(t, err)
assertMetadataEquality(t, &Metadata{
AmmIndex: new(big.Int).Set(order.AmmIndex),
Trader: trader,
BaseAssetQuantity: new(big.Int).Set(order.BaseAssetQuantity),
BlockPlaced: big.NewInt(21),
Price: new(big.Int).Set(order.Price),
OrderHash: hash,
}, m)
})

t.Run("valid order - reduce only", func(t *testing.T) {
Expand Down
76 changes: 43 additions & 33 deletions precompile/contracts/juror/matching_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,47 +86,53 @@ const (
// Business Logic
func ValidateOrdersAndDetermineFillPrice(bibliophile b.BibliophileClient, inputStruct *ValidateOrdersAndDetermineFillPriceInput) ValidateOrdersAndDetermineFillPriceOutput {
if len(inputStruct.Data) != 2 {
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrTwoOrders, Generic)
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrTwoOrders, Generic, common.Hash{})
}

if inputStruct.FillAmount.Sign() <= 0 {
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrInvalidFillAmount, Generic)
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrInvalidFillAmount, Generic, common.Hash{})
}

decodeStep0, err := ob.DecodeTypeAndEncodedOrder(inputStruct.Data[0])
if err != nil {
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order0)
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order0, common.Hash{})
}
m0, err := validateOrder(bibliophile, decodeStep0.OrderType, decodeStep0.EncodedOrder, Long, inputStruct.FillAmount)
if err != nil {
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order0)
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order0, m0.OrderHash)
}

decodeStep1, err := ob.DecodeTypeAndEncodedOrder(inputStruct.Data[1])
if err != nil {
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order1)
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order1, common.Hash{})
}
m1, err := validateOrder(bibliophile, decodeStep1.OrderType, decodeStep1.EncodedOrder, Short, new(big.Int).Neg(inputStruct.FillAmount))
if err != nil {
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order1)
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, Order1, m1.OrderHash)
}

if m0.AmmIndex.Cmp(m1.AmmIndex) != 0 {
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNotSameAMM, Generic)
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNotSameAMM, Generic, common.Hash{})
}

if m0.Price.Cmp(m1.Price) < 0 {
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNoMatch, Generic)
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNoMatch, Generic, common.Hash{})
}

minSize := bibliophile.GetMinSizeRequirement(m0.AmmIndex.Int64())
if new(big.Int).Mod(inputStruct.FillAmount, minSize).Cmp(big.NewInt(0)) != 0 {
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNotMultiple, Generic)
return getValidateOrdersAndDetermineFillPriceErrorOutput(ErrNotMultiple, Generic, common.Hash{})
}

fillPriceAndModes, err, element := determineFillPrice(bibliophile, m0, m1)
if err != nil {
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, element)
orderHash := common.Hash{}
if element == Order0 {
orderHash = m0.OrderHash
} else if element == Order1 {
orderHash = m1.OrderHash
}
return getValidateOrdersAndDetermineFillPriceErrorOutput(err, element, orderHash)
}

return ValidateOrdersAndDetermineFillPriceOutput{
Expand Down Expand Up @@ -230,16 +236,16 @@ func determineFillPrice(bibliophile b.BibliophileClient, m0, m1 *Metadata) (*Fil
func ValidateLiquidationOrderAndDetermineFillPrice(bibliophile b.BibliophileClient, inputStruct *ValidateLiquidationOrderAndDetermineFillPriceInput) ValidateLiquidationOrderAndDetermineFillPriceOutput {
fillAmount := new(big.Int).Set(inputStruct.LiquidationAmount)
if fillAmount.Sign() <= 0 {
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(ErrInvalidFillAmount, Generic)
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(ErrInvalidFillAmount, Generic, common.Hash{})
}

decodeStep0, err := ob.DecodeTypeAndEncodedOrder(inputStruct.Data)
if err != nil {
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0)
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0, common.Hash{})
}
m0, err := validateOrder(bibliophile, decodeStep0.OrderType, decodeStep0.EncodedOrder, Liquidation, fillAmount)
if err != nil {
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0)
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0, m0.OrderHash)
}

if m0.BaseAssetQuantity.Sign() < 0 {
Expand All @@ -248,12 +254,12 @@ func ValidateLiquidationOrderAndDetermineFillPrice(bibliophile b.BibliophileClie

minSize := bibliophile.GetMinSizeRequirement(m0.AmmIndex.Int64())
if new(big.Int).Mod(fillAmount, minSize).Cmp(big.NewInt(0)) != 0 {
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(ErrNotMultiple, Generic)
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(ErrNotMultiple, Generic, common.Hash{})
}

fillPrice, err := determineLiquidationFillPrice(bibliophile, m0)
if err != nil {
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0)
return getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err, Order0, m0.OrderHash)
}

return ValidateLiquidationOrderAndDetermineFillPriceOutput{
Expand Down Expand Up @@ -299,11 +305,7 @@ func validateOrder(bibliophile b.BibliophileClient, orderType ob.OrderType, enco
if err != nil {
return nil, err
}
orderHash, err := order.Hash()
if err != nil {
return nil, err
}
return validateExecuteLimitOrder(bibliophile, order, side, fillAmount, orderHash)
return validateExecuteLimitOrder(bibliophile, order, side, fillAmount)
}
if orderType == ob.IOC {
order, err := ob.DecodeIOCOrder(encodedOrder)
Expand All @@ -315,10 +317,14 @@ func validateOrder(bibliophile b.BibliophileClient, orderType ob.OrderType, enco
return nil, errors.New("invalid order type")
}

func validateExecuteLimitOrder(bibliophile b.BibliophileClient, order *ob.LimitOrder, side Side, fillAmount *big.Int, orderHash [32]byte) (metadata *Metadata, err error) {
if err := validateLimitOrderLike(bibliophile, &order.BaseOrder, bibliophile.GetOrderFilledAmount(orderHash), OrderStatus(bibliophile.GetOrderStatus(orderHash)), side, fillAmount); err != nil {
func validateExecuteLimitOrder(bibliophile b.BibliophileClient, order *ob.LimitOrder, side Side, fillAmount *big.Int) (metadata *Metadata, err error) {
orderHash, err := order.Hash()
if err != nil {
return nil, err
}
if err := validateLimitOrderLike(bibliophile, &order.BaseOrder, bibliophile.GetOrderFilledAmount(orderHash), OrderStatus(bibliophile.GetOrderStatus(orderHash)), side, fillAmount); err != nil {
return &Metadata{OrderHash: orderHash}, err
}
return &Metadata{
AmmIndex: order.AmmIndex,
Trader: order.Trader,
Expand All @@ -332,18 +338,18 @@ func validateExecuteLimitOrder(bibliophile b.BibliophileClient, order *ob.LimitO
}

func validateExecuteIOCOrder(bibliophile b.BibliophileClient, order *ob.IOCOrder, side Side, fillAmount *big.Int) (metadata *Metadata, err error) {
if ob.OrderType(order.OrderType) != ob.IOC {
return nil, errors.New("not ioc order")
}
if order.ExpireAt.Uint64() < bibliophile.GetTimeStamp() {
return nil, errors.New("ioc expired")
}
orderHash, err := order.Hash()
if err != nil {
return nil, err
}
if ob.OrderType(order.OrderType) != ob.IOC {
return &Metadata{OrderHash: orderHash}, errors.New("not ioc order")
}
if order.ExpireAt.Uint64() < bibliophile.GetTimeStamp() {
return &Metadata{OrderHash: orderHash}, errors.New("ioc expired")
}
if err := validateLimitOrderLike(bibliophile, &order.BaseOrder, bibliophile.IOC_GetOrderFilledAmount(orderHash), OrderStatus(bibliophile.IOC_GetOrderStatus(orderHash)), side, fillAmount); err != nil {
return nil, err
return &Metadata{OrderHash: orderHash}, err
}
return &Metadata{
AmmIndex: order.AmmIndex,
Expand Down Expand Up @@ -475,7 +481,7 @@ func formatOrder(orderBytes []byte) interface{} {
return nil
}

func getValidateOrdersAndDetermineFillPriceErrorOutput(err error, element BadElement) ValidateOrdersAndDetermineFillPriceOutput {
func getValidateOrdersAndDetermineFillPriceErrorOutput(err error, element BadElement, orderHash common.Hash) ValidateOrdersAndDetermineFillPriceOutput {
// need to provide an empty res because PackValidateOrdersAndDetermineFillPriceOutput fails if FillPrice is nil, and if res.Instructions[0].AmmIndex is nil
emptyRes := IOrderHandlerMatchingValidationRes{
Instructions: [2]IClearingHouseInstruction{
Expand All @@ -492,11 +498,13 @@ func getValidateOrdersAndDetermineFillPriceErrorOutput(err error, element BadEle
// should always be true
errorString = err.Error()
}

if (element == Order0 || element == Order1) && orderHash != (common.Hash{}) {
emptyRes.Instructions[element].OrderHash = orderHash
}
return ValidateOrdersAndDetermineFillPriceOutput{Err: errorString, Element: uint8(element), Res: emptyRes}
}

func getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err error, element BadElement) ValidateLiquidationOrderAndDetermineFillPriceOutput {
func getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err error, element BadElement, orderHash common.Hash) ValidateLiquidationOrderAndDetermineFillPriceOutput {
emptyRes := IOrderHandlerLiquidationMatchingValidationRes{
Instruction: IClearingHouseInstruction{AmmIndex: big.NewInt(0)},
OrderType: 0,
Expand All @@ -510,6 +518,8 @@ func getValidateLiquidationOrderAndDetermineFillPriceErrorOutput(err error, elem
// should always be true
errorString = err.Error()
}

if element == Order0 && orderHash != (common.Hash{}) {
emptyRes.Instruction.OrderHash = orderHash
}
return ValidateLiquidationOrderAndDetermineFillPriceOutput{Err: errorString, Element: uint8(element), Res: emptyRes}
}
14 changes: 13 additions & 1 deletion precompile/contracts/juror/matching_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func TestValidateExecuteLimitOrder(t *testing.T) {
mockBibliophile.EXPECT().GetBlockPlaced(orderHash).Return(blockPlaced).Times(1) // placed
mockBibliophile.EXPECT().GetMarketAddressFromMarketID(order.AmmIndex.Int64()).Return(marketAddress).Times(1) // placed

m, err := validateExecuteLimitOrder(mockBibliophile, order, Long, fillAmount, orderHash)
m, err := validateExecuteLimitOrder(mockBibliophile, order, Long, fillAmount)
assert.Nil(t, err)
assertMetadataEquality(t, &Metadata{
AmmIndex: new(big.Int).Set(order.AmmIndex),
Expand All @@ -243,6 +243,18 @@ func TestValidateExecuteLimitOrder(t *testing.T) {
OrderHash: orderHash,
}, m)
})

t.Run("validateExecuteLimitOrder returns orderHash even when validation fails", func(t *testing.T) {
orderHash, err := order.Hash()
assert.Nil(t, err)

mockBibliophile.EXPECT().GetOrderFilledAmount(orderHash).Return(filledAmount).Times(1)
mockBibliophile.EXPECT().GetOrderStatus(orderHash).Return(int64(2)).Times(1) // Filled

m, err := validateExecuteLimitOrder(mockBibliophile, order, Long, fillAmount)
assert.EqualError(t, err, ErrInvalidOrder.Error())
assert.Equal(t, orderHash, m.OrderHash)
})
}

func assertMetadataEquality(t *testing.T, expected, actual *Metadata) {
Expand Down