Skip to content

Commit

Permalink
send order hash during failed match validations (#130)
Browse files Browse the repository at this point in the history
* send order hash during match validations

* update vmid

* add logs

* tests
  • Loading branch information
atvanguard authored Oct 4, 2023
1 parent 06d0c5a commit 3cf0921
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 40 deletions.
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

0 comments on commit 3cf0921

Please sign in to comment.