diff --git a/clientdb/order.go b/clientdb/order.go index 6986bd3a3..3ca9a5d77 100644 --- a/clientdb/order.go +++ b/clientdb/order.go @@ -297,6 +297,28 @@ func (db *DB) GetOrders() ([]order.Order, error) { return orders, nil } +// DeleteOrder removes the order with the given nonce. If no order with that +// nonce exists in the store, ErrNoOrder is returned. +// +// NOTE: This is part of the Store interface. +func (db *DB) DeleteOrder(nonce order.Nonce) error { + return db.Update(func(tx *bbolt.Tx) error { + // First, we'll grab our main order bucket key. + rootBucket, err := getBucket(tx, ordersBucketKey) + if err != nil { + return err + } + + // Check that the order exists in the main bucket. + orderBucket := rootBucket.Bucket(nonce[:]) + if orderBucket == nil { + return ErrNoOrder + } + + return rootBucket.DeleteBucket(nonce[:]) + }) +} + // storeOrderTX saves a byte serialized order in its specific sub bucket within // the root orders bucket. func storeOrderTX(rootBucket *bbolt.Bucket, nonce order.Nonce, diff --git a/cmd/pool/debug.go b/cmd/pool/debug.go index aad81ac51..9c3a57bda 100644 --- a/cmd/pool/debug.go +++ b/cmd/pool/debug.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "encoding/hex" "fmt" "path" "path/filepath" @@ -27,6 +28,7 @@ var debugCommands = []cli.Command{ dumpOrdersCommand, dumpPendingBatcheCommand, removePendingBatchCommand, + deleteOrderCommand, }, }, } @@ -163,6 +165,55 @@ func dumpOrders(ctx *cli.Context) error { return nil } +var deleteOrderCommand = cli.Command{ + Name: "deleteorder", + Usage: "delete an order from the local database", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "order_nonce", + Usage: "the order nonce of the order to delete", + }, + cli.StringFlag{ + Name: "db", + Usage: "the specific pool database to use instead " + + "of the default one on ~/.pool//" + + "pool.db", + }, + }, + Action: deleteOrder, +} + +func deleteOrder(ctx *cli.Context) error { + var ( + nonceHex string + args = ctx.Args() + ) + + db, err := getPoolDB(ctx) + if err != nil { + return fmt.Errorf("error loading DB: %v", err) + } + + switch { + case ctx.IsSet("order_nonce"): + nonceHex = ctx.String("order_nonce") + case args.Present(): + nonceHex = args.First() + default: + return fmt.Errorf("order_nonce argument missing") + } + + decodedOnce, err := hex.DecodeString(nonceHex) + if err != nil { + return fmt.Errorf("cannot hex decode order nonce: %v", err) + } + + var nonce order.Nonce + copy(nonce[:], decodedOnce) + + return db.DeleteOrder(nonce) +} + var dumpPendingBatcheCommand = cli.Command{ Name: "dumppendingbatch", ShortName: "dpb", diff --git a/order/interfaces.go b/order/interfaces.go index debf49e33..d222fdd68 100644 --- a/order/interfaces.go +++ b/order/interfaces.go @@ -757,6 +757,12 @@ type Store interface { // GetOrders returns all orders that are currently known to the store. GetOrders() ([]Order, error) + // DeleteOrder removes the order with the given Nonce. + // + // Note: this method deletes the order without checking if it is + // referenced somewhere else (e.g. pending batch). + DeleteOrder(Nonce) error + // StorePendingBatch atomically stages all modified orders/accounts as a // result of a pending batch. If any single operation fails, the whole // set of changes is rolled back. Once the batch has been diff --git a/order/mock_interfaces.go b/order/mock_interfaces.go index 21aeb5416..83d1422ce 100644 --- a/order/mock_interfaces.go +++ b/order/mock_interfaces.go @@ -131,6 +131,20 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder { return m.recorder } +// DeleteOrder mocks base method. +func (m *MockStore) DeleteOrder(arg0 Nonce) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteOrder", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteOrder indicates an expected call of DeleteOrder. +func (mr *MockStoreMockRecorder) DeleteOrder(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOrder", reflect.TypeOf((*MockStore)(nil).DeleteOrder), arg0) +} + // GetOrder mocks base method. func (m *MockStore) GetOrder(arg0 Nonce) (Order, error) { m.ctrl.T.Helper() diff --git a/order/mock_test.go b/order/mock_test.go index 76e148d9c..dca23cb72 100644 --- a/order/mock_test.go +++ b/order/mock_test.go @@ -83,8 +83,8 @@ func (s *mockStore) GetOrders() ([]Order, error) { return orders, nil } -// DelOrder removes the order with the given nonce from the local store. -func (s *mockStore) DelOrder(nonce Nonce) error { +// DeleteOrder removes the order with the given nonce from the local store. +func (s *mockStore) DeleteOrder(nonce Nonce) error { delete(s.orders, nonce) return nil } diff --git a/server.go b/server.go index dac9478d2..dcde7cd41 100644 --- a/server.go +++ b/server.go @@ -770,7 +770,8 @@ func (s *Server) syncLocalOrderState() error { context.Background(), orderNonce, ) if err != nil { - return fmt.Errorf("unable to fetch order state: %v", err) + return fmt.Errorf("unable to fetch order(%v): %v", + orderNonce, err) } remoteOrderState, err := rpcOrderStateToDBState( orderStateResp.State,