Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1410 from OpenBazaar/1409-postordercancel-coin-mi…
Browse files Browse the repository at this point in the history
…ssing-fix

1409 coin missing fix
  • Loading branch information
cpacia authored Jan 17, 2019
2 parents 7215406 + 30962dd commit 0ffe952
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 64 deletions.
111 changes: 88 additions & 23 deletions api/jsonapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -1544,11 +1544,18 @@ func (i *jsonAPIHandler) POSTOrderConfirmation(w http.ResponseWriter, r *http.Re
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
contract, state, funded, records, _, _, err := i.node.Datastore.Sales().GetByOrderId(conf.OrderID)
contract, state, funded, records, _, paymentCoin, err := i.node.Datastore.Sales().GetByOrderId(conf.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, err.Error())
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", conf.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if state != pb.OrderState_PENDING {
ErrorResponse(w, http.StatusBadRequest, "order has already been confirmed")
return
Expand Down Expand Up @@ -1584,12 +1591,18 @@ func (i *jsonAPIHandler) POSTOrderCancel(w http.ResponseWriter, r *http.Request)
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
contract, state, _, records, _, _, err := i.node.Datastore.Purchases().GetByOrderId(can.OrderID)
contract, state, _, records, _, paymentCoin, err := i.node.Datastore.Purchases().GetByOrderId(can.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "order not found")
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", can.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if !((state == pb.OrderState_PENDING || state == pb.OrderState_PROCESSING_ERROR) && len(records) > 0) || !(state == pb.OrderState_PENDING || state == pb.OrderState_PROCESSING_ERROR) || contract.BuyerOrder.Payment.Method == pb.Order_Payment_MODERATED {
ErrorResponse(w, http.StatusBadRequest, "order must be PENDING or PROCESSING_ERROR and only a direct payment to cancel")
return
Expand Down Expand Up @@ -1721,7 +1734,7 @@ func (i *jsonAPIHandler) POSTRefund(w http.ResponseWriter, r *http.Request) {
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
contract, state, _, records, _, _, err := i.node.Datastore.Sales().GetByOrderId(can.OrderID)
contract, state, _, records, _, paymentCoin, err := i.node.Datastore.Sales().GetByOrderId(can.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "order not found")
return
Expand All @@ -1730,6 +1743,13 @@ func (i *jsonAPIHandler) POSTRefund(w http.ResponseWriter, r *http.Request) {
ErrorResponse(w, http.StatusBadRequest, "order must be AWAITING_FULFILLMENT, or PARTIALLY_FULFILLED")
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", can.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

err = i.node.RefundOrder(contract, records)
if err != nil {
ErrorResponse(w, http.StatusInternalServerError, err.Error())
Expand Down Expand Up @@ -1911,11 +1931,18 @@ func (i *jsonAPIHandler) POSTOrderFulfill(w http.ResponseWriter, r *http.Request
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
contract, state, _, records, _, _, err := i.node.Datastore.Sales().GetByOrderId(fulfill.OrderId)
contract, state, _, records, _, paymentCoin, err := i.node.Datastore.Sales().GetByOrderId(fulfill.OrderId)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "order not found")
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", fulfill.OrderId)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if state != pb.OrderState_AWAITING_FULFILLMENT && state != pb.OrderState_PARTIALLY_FULFILLED {
ErrorResponse(w, http.StatusBadRequest, "order must be in state AWAITING_FULFILLMENT or PARTIALLY_FULFILLED to fulfill")
return
Expand Down Expand Up @@ -1943,12 +1970,18 @@ func (i *jsonAPIHandler) POSTOrderComplete(w http.ResponseWriter, r *http.Reques
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
contract, state, _, records, _, _, err := i.node.Datastore.Purchases().GetByOrderId(or.OrderID)
contract, state, _, records, _, paymentCoin, err := i.node.Datastore.Purchases().GetByOrderId(or.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "order not found")
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", or.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if state != pb.OrderState_FULFILLED &&
state != pb.OrderState_RESOLVED &&
state != pb.OrderState_PAYMENT_FINALIZED {
Expand Down Expand Up @@ -2012,19 +2045,29 @@ func (i *jsonAPIHandler) POSTOpenDispute(w http.ResponseWriter, r *http.Request)
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var isSale bool
var contract *pb.RicardianContract
var state pb.OrderState
var records []*wallet.TransactionRecord
contract, state, _, records, _, _, err = i.node.Datastore.Purchases().GetByOrderId(d.OrderID)
var (
isSale bool
contract *pb.RicardianContract
state pb.OrderState
records []*wallet.TransactionRecord
paymentCoin *repo.CurrencyCode
)
contract, state, _, records, _, paymentCoin, err = i.node.Datastore.Purchases().GetByOrderId(d.OrderID)
if err != nil {
contract, state, _, records, _, _, err = i.node.Datastore.Sales().GetByOrderId(d.OrderID)
contract, state, _, records, _, paymentCoin, err = i.node.Datastore.Sales().GetByOrderId(d.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "Order not found")
return
}
isSale = true
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", d.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if contract.BuyerOrder.Payment.Method != pb.Order_Payment_MODERATED {
ErrorResponse(w, http.StatusBadRequest, "Only moderated orders can be disputed")
return
Expand Down Expand Up @@ -2053,21 +2096,26 @@ func (i *jsonAPIHandler) POSTOpenDispute(w http.ResponseWriter, r *http.Request)
}

func (i *jsonAPIHandler) POSTCloseDispute(w http.ResponseWriter, r *http.Request) {
type dispute struct {
type disputeParams struct {
OrderID string `json:"orderId"`
Resolution string `json:"resolution"`
BuyerPercentage float32 `json:"buyerPercentage"`
VendorPercentage float32 `json:"vendorPercentage"`
}
decoder := json.NewDecoder(r.Body)
var d dispute
var d disputeParams
err := decoder.Decode(&d)
if err != nil {
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

err = i.node.CloseDispute(d.OrderID, d.BuyerPercentage, d.VendorPercentage, d.Resolution)
disputeCase, err := i.node.Datastore.Cases().GetByCaseID(d.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, err.Error())
}

err = i.node.CloseDispute(disputeCase.CaseID, d.BuyerPercentage, d.VendorPercentage, d.Resolution, disputeCase.PaymentCoin)
if err != nil {
switch err {
case core.ErrCaseNotFound:
Expand Down Expand Up @@ -2141,17 +2189,27 @@ func (i *jsonAPIHandler) POSTReleaseFunds(w http.ResponseWriter, r *http.Request
ErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var contract *pb.RicardianContract
var state pb.OrderState
var records []*wallet.TransactionRecord
contract, state, _, records, _, _, err = i.node.Datastore.Purchases().GetByOrderId(rel.OrderID)
var (
contract *pb.RicardianContract
state pb.OrderState
records []*wallet.TransactionRecord
paymentCoin *repo.CurrencyCode
)
contract, state, _, records, _, paymentCoin, err = i.node.Datastore.Purchases().GetByOrderId(rel.OrderID)
if err != nil {
contract, state, _, records, _, _, err = i.node.Datastore.Sales().GetByOrderId(rel.OrderID)
contract, state, _, records, _, paymentCoin, err = i.node.Datastore.Sales().GetByOrderId(rel.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "Order not found")
return
}
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", rel.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if state == pb.OrderState_DECIDED {
err = i.node.ReleaseFunds(contract, records)
if err != nil {
Expand All @@ -2170,9 +2228,10 @@ func (i *jsonAPIHandler) POSTReleaseEscrow(w http.ResponseWriter, r *http.Reques
rel struct {
OrderID string `json:"orderId"`
}
contract *pb.RicardianContract
state pb.OrderState
records []*wallet.TransactionRecord
contract *pb.RicardianContract
state pb.OrderState
records []*wallet.TransactionRecord
paymentCoin *repo.CurrencyCode
)

decoder := json.NewDecoder(r.Body)
Expand All @@ -2182,12 +2241,18 @@ func (i *jsonAPIHandler) POSTReleaseEscrow(w http.ResponseWriter, r *http.Reques
return
}

contract, state, _, records, _, _, err = i.node.Datastore.Sales().GetByOrderId(rel.OrderID)
contract, state, _, records, _, paymentCoin, err = i.node.Datastore.Sales().GetByOrderId(rel.OrderID)
if err != nil {
ErrorResponse(w, http.StatusNotFound, "Order not found")
return
}

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(contract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", rel.OrderID)
contract.BuyerOrder.Payment.Coin = paymentCoin.String()
}

if state != pb.OrderState_PENDING && state != pb.OrderState_FULFILLED && state != pb.OrderState_DISPUTED {
ErrorResponse(w, http.StatusBadRequest, "Release escrow can only be called when sale is pending, fulfilled, or disputed")
return
Expand Down
5 changes: 4 additions & 1 deletion api/jsonapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,10 @@ func TestPosts(t *testing.T) {

func TestCloseDisputeBlocksWhenExpired(t *testing.T) {
dbSetup := func(testRepo *test.Repository) error {
paymentCoin := repo.CurrencyCode("BTC")
expired := factory.NewExpiredDisputeCaseRecord()
expired.CaseID = "expiredCase"
expired.PaymentCoin = &paymentCoin
for _, r := range []*repo.DisputeCaseRecord{expired} {
if err := testRepo.DB.Cases().PutRecord(r); err != nil {
return err
Expand Down Expand Up @@ -652,12 +654,13 @@ func TestPurchasesGet(t *testing.T) {
}

func TestCasesGet(t *testing.T) {
paymentCoinCode := repo.CurrencyCode("BTC")
disputeCaseRecord := factory.NewDisputeCaseRecord()
disputeCaseRecord.BuyerContract.VendorListings[0].Metadata.AcceptedCurrencies = []string{"BTC"}
disputeCaseRecord.BuyerContract.VendorListings[0].Metadata.CoinType = "ZEC"
disputeCaseRecord.BuyerContract.VendorListings[0].Metadata.ContractType = pb.Listing_Metadata_CRYPTOCURRENCY
disputeCaseRecord.CoinType = "ZEC"
disputeCaseRecord.PaymentCoin = "BTC"
disputeCaseRecord.PaymentCoin = &paymentCoinCode
dbSetup := func(testRepo *test.Repository) error {
return testRepo.DB.Cases().PutRecord(disputeCaseRecord)
}
Expand Down
8 changes: 7 additions & 1 deletion core/disputes.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ func (n *OpenBazaarNode) ProcessDisputeOpen(rc *pb.RicardianContract, peerID str
}

// CloseDispute - close a dispute
func (n *OpenBazaarNode) CloseDispute(orderID string, buyerPercentage, vendorPercentage float32, resolution string) error {
func (n *OpenBazaarNode) CloseDispute(orderID string, buyerPercentage, vendorPercentage float32, resolution string, paymentCoinHint *repo.CurrencyCode) error {
var payDivision = repo.PayoutRatio{Buyer: buyerPercentage, Vendor: vendorPercentage}
if err := payDivision.Validate(); err != nil {
return err
Expand Down Expand Up @@ -468,6 +468,12 @@ func (n *OpenBazaarNode) CloseDispute(orderID string, buyerPercentage, vendorPer
}
preferredContract := dispute.ResolutionPaymentContract(payDivision)

// TODO: Remove once broken contracts are migrated
if _, err := repo.NewCurrencyCode(preferredContract.BuyerOrder.Payment.Coin); err != nil {
log.Warningf("missing contract BuyerOrder.Payment.Coin on order (%s)", orderID)
preferredContract.BuyerOrder.Payment.Coin = paymentCoinHint.String()
}

var d = new(pb.DisputeResolution)

// Add timestamp
Expand Down
53 changes: 33 additions & 20 deletions repo/db/cases.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (c *CasesDB) PutRecord(dispute *repo.DisputeCaseRecord) error {
dispute.Claim,
"",
"",
dispute.PaymentCoin,
dispute.PaymentCoin.String(),
dispute.CoinType,
)
if err != nil {
Expand All @@ -65,12 +65,16 @@ func (c *CasesDB) PutRecord(dispute *repo.DisputeCaseRecord) error {
}

func (c *CasesDB) Put(caseID string, state pb.OrderState, buyerOpened bool, claim string, paymentCoin string, coinType string) error {
paymentCoinCode, err := repo.NewCurrencyCode(paymentCoin)
if err != nil {
return fmt.Errorf("verifying paymentCoin: %s", err.Error())
}
record := &repo.DisputeCaseRecord{
CaseID: caseID,
Claim: claim,
IsBuyerInitiated: buyerOpened,
OrderState: state,
PaymentCoin: paymentCoin,
PaymentCoin: paymentCoinCode,
CoinType: coinType,
Timestamp: time.Now(),
}
Expand Down Expand Up @@ -388,22 +392,30 @@ func (c *CasesDB) GetCaseMetadata(caseID string) (buyerContract, vendorContract
func (c *CasesDB) GetByCaseID(caseID string) (*repo.DisputeCaseRecord, error) {
c.lock.Lock()
defer c.lock.Unlock()
var buyerCon []byte
var vendorCon []byte
var buyerOuts []byte
var vendorOuts []byte
var buyerAddr string
var vendorAddr string
var stateInt int
var isBuyerInitiated int
var buyerInitiated bool
var createdAt int64
var (
buyerAddr string
buyerCon []byte
buyerInitiated bool
buyerOuts []byte
createdAt int64
isBuyerInitiated int
paymentCoin string
stateInt int
vendorAddr string
vendorCon []byte
vendorOuts []byte
)

stmt, err := c.db.Prepare("select buyerContract, vendorContract, buyerPayoutAddress, vendorPayoutAddress, buyerOutpoints, vendorOutpoints, state, buyerOpened, timestamp from cases where caseID=?")
stmt, err := c.db.Prepare("select buyerContract, vendorContract, buyerPayoutAddress, vendorPayoutAddress, buyerOutpoints, vendorOutpoints, state, buyerOpened, timestamp, paymentCoin from cases where caseID=?")
if err != nil {
return nil, err
}
err = stmt.QueryRow(caseID).Scan(&buyerCon, &vendorCon, &buyerAddr, &vendorAddr, &buyerOuts, &vendorOuts, &stateInt, &isBuyerInitiated, &createdAt)
err = stmt.QueryRow(caseID).Scan(&buyerCon, &vendorCon, &buyerAddr, &vendorAddr, &buyerOuts, &vendorOuts, &stateInt, &isBuyerInitiated, &createdAt, &paymentCoin)
if err != nil {
return nil, err
}

paymentCoinCode, err := repo.NewCurrencyCode(paymentCoin)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -458,16 +470,17 @@ func (c *CasesDB) GetByCaseID(caseID string) (*repo.DisputeCaseRecord, error) {
return ret
}
return &repo.DisputeCaseRecord{
CaseID: caseID,
IsBuyerInitiated: buyerInitiated,
BuyerContract: brc,
BuyerPayoutAddress: buyerAddr,
BuyerOutpoints: toPointer(buyerOutpointsOut),
VendorContract: vrc,
VendorPayoutAddress: vendorAddr,
VendorOutpoints: toPointer(vendorOutpointsOut),
BuyerPayoutAddress: buyerAddr,
CaseID: caseID,
IsBuyerInitiated: buyerInitiated,
OrderState: pb.OrderState(stateInt),
PaymentCoin: paymentCoinCode,
Timestamp: time.Unix(createdAt, 0),
VendorContract: vrc,
VendorOutpoints: toPointer(vendorOutpointsOut),
VendorPayoutAddress: vendorAddr,
}, nil
}

Expand Down
Loading

0 comments on commit 0ffe952

Please sign in to comment.