Skip to content

Commit

Permalink
Provider cancels fulfillment (#181)
Browse files Browse the repository at this point in the history
fixes #172 

* Add TxCloseFulfillment with Fulfillment field
* Tx changes the fulfillment state to Closed.
* Tx is valid if signed by provider and fulfillment is open.
  • Loading branch information
aastein authored Apr 5, 2018
1 parent 52966ee commit 658db91
Show file tree
Hide file tree
Showing 15 changed files with 549 additions and 112 deletions.
104 changes: 99 additions & 5 deletions app/fulfillment/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,19 @@ func (a *app) AcceptTx(ctx apptypes.Context, tx interface{}) bool {
switch tx.(type) {
case *types.TxPayload_TxCreateFulfillment:
return true
case *types.TxPayload_TxCloseFulfillment:
return true
}
return false
}

func (a *app) CheckTx(ctx apptypes.Context, tx interface{}) tmtypes.ResponseCheckTx {
switch tx := tx.(type) {
case *types.TxPayload_TxCreateFulfillment:
return a.doCheckTx(ctx, tx.TxCreateFulfillment)
return a.doCheckCreateTx(ctx, tx.TxCreateFulfillment)
case *types.TxPayload_TxCloseFulfillment:
_, resp := a.doCheckCloseTx(ctx, tx.TxCloseFulfillment)
return resp
}
return tmtypes.ResponseCheckTx{
Code: code.UNKNOWN_TRANSACTION,
Expand All @@ -54,7 +59,9 @@ func (a *app) CheckTx(ctx apptypes.Context, tx interface{}) tmtypes.ResponseChec
func (a *app) DeliverTx(ctx apptypes.Context, tx interface{}) tmtypes.ResponseDeliverTx {
switch tx := tx.(type) {
case *types.TxPayload_TxCreateFulfillment:
return a.doDeliverTx(ctx, tx.TxCreateFulfillment)
return a.doDeliverCreateTx(ctx, tx.TxCreateFulfillment)
case *types.TxPayload_TxCloseFulfillment:
return a.doDeliverCloseTx(ctx, tx.TxCloseFulfillment)
}
return tmtypes.ResponseDeliverTx{
Code: code.UNKNOWN_TRANSACTION,
Expand Down Expand Up @@ -87,7 +94,7 @@ func (a *app) Query(req tmtypes.RequestQuery) tmtypes.ResponseQuery {
return a.doQuery(*key)
}

func (a *app) doCheckTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) tmtypes.ResponseCheckTx {
func (a *app) doCheckCreateTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) tmtypes.ResponseCheckTx {

if tx.Deployment == nil {
return tmtypes.ResponseCheckTx{
Expand Down Expand Up @@ -207,8 +214,8 @@ func (a *app) doCheckTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) tmt
return tmtypes.ResponseCheckTx{}
}

func (a *app) doDeliverTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) tmtypes.ResponseDeliverTx {
cresp := a.doCheckTx(ctx, tx)
func (a *app) doDeliverCreateTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) tmtypes.ResponseDeliverTx {
cresp := a.doCheckCreateTx(ctx, tx)
if !cresp.IsOK() {
return tmtypes.ResponseDeliverTx{
Code: cresp.Code,
Expand Down Expand Up @@ -237,6 +244,93 @@ func (a *app) doDeliverTx(ctx apptypes.Context, tx *types.TxCreateFulfillment) t
}
}

func (a *app) doCheckCloseTx(ctx apptypes.Context, tx *types.TxCloseFulfillment) (*types.Fulfillment, tmtypes.ResponseCheckTx) {

// lookup fulfillment
fulfillment, err := a.State().Fulfillment().GetByKey(tx.Fulfillment)
if err != nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.ERROR,
Log: err.Error(),
}
}
if fulfillment == nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.INVALID_TRANSACTION,
Log: "fulfillment not found",
}
}
if fulfillment.State != types.Fulfillment_OPEN {
return nil, tmtypes.ResponseCheckTx{
Code: code.INVALID_TRANSACTION,
Log: "fulfillment not open",
}
}

// ensure provider exists
provider, err := a.State().Provider().Get(fulfillment.Provider)
if err != nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.ERROR,
Log: err.Error(),
}
}
if provider == nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.INVALID_TRANSACTION,
Log: "Provider not found",
}
}

// ensure ownder exists
owner, err := a.State().Account().Get(provider.Owner)
if err != nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.ERROR,
Log: err.Error(),
}
}
if owner == nil {
return nil, tmtypes.ResponseCheckTx{
Code: code.INVALID_TRANSACTION,
Log: "Owner not found",
}
}

// ensure tx signed by provider
if !bytes.Equal(ctx.Signer().Address(), owner.Address) {
return nil, tmtypes.ResponseCheckTx{
Code: code.INVALID_TRANSACTION,
Log: "Not signed by provider",
}
}

return fulfillment, tmtypes.ResponseCheckTx{}
}

func (a *app) doDeliverCloseTx(ctx apptypes.Context, tx *types.TxCloseFulfillment) tmtypes.ResponseDeliverTx {
fulfillment, cresp := a.doCheckCloseTx(ctx, tx)
if !cresp.IsOK() {
return tmtypes.ResponseDeliverTx{
Code: cresp.Code,
Log: cresp.Log,
}
}

fulfillment.State = types.Fulfillment_CLOSED

if err := a.State().Fulfillment().Save(fulfillment); err != nil {
return tmtypes.ResponseDeliverTx{
Code: code.INVALID_TRANSACTION,
Log: err.Error(),
}
}

return tmtypes.ResponseDeliverTx{
Tags: apptypes.NewTags(a.Name(), apptypes.TxTypeCloseFulfillment),
}
}

func (a *app) doQuery(key base.Bytes) tmtypes.ResponseQuery {
ful, err := a.State().Fulfillment().GetByKey(key)

Expand Down
50 changes: 35 additions & 15 deletions app/fulfillment/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
tmtypes "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
)

func TestAcceptQuery(t *testing.T) {
Expand Down Expand Up @@ -68,23 +69,42 @@ func TestValidTx(t *testing.T) {
testutil.CreateOrder(t, oapp, taccount, &tkey, deployment.Address, groupSeq, oSeq)
price := uint32(0)

fulfillment := createFulfillment(t, app, provider, &pkey, daddress, groupSeq, oSeq, price)
closeFulfillment(t, app, &pkey, fulfillment)
}

func createFulfillment(t *testing.T, app apptypes.Application, provider *types.Provider,
pkey *crypto.PrivKey, deployment []byte, groupSeq uint64, oSeq uint64, price uint32) *types.Fulfillment {
// create fulfillment
fulfillment := testutil.CreateFulfillment(t, app, provider.Address, &pkey, daddress, groupSeq, oSeq, price)
fulfillment := testutil.CreateFulfillment(t, app, provider.Address, pkey, deployment, groupSeq, oSeq, price)

path := query.FulfillmentPath(fulfillment.Deployment, fulfillment.Group, fulfillment.Order, fulfillment.Provider)
resp := app.Query(tmtypes.RequestQuery{Path: path})
assert.Empty(t, resp.Log)
require.True(t, resp.IsOK())
ful := new(types.Fulfillment)
require.NoError(t, ful.Unmarshal(resp.Value))

assert.Equal(t, fulfillment.Deployment, ful.Deployment)
assert.Equal(t, fulfillment.Group, ful.Group)
assert.Equal(t, fulfillment.Order, ful.Order)
assert.Equal(t, fulfillment.Provider, ful.Provider)
assert.Equal(t, fulfillment.Price, ful.Price)
assert.Equal(t, fulfillment.State, ful.State)

return fulfillment
}

{
path := query.FulfillmentPath(fulfillment.Deployment, fulfillment.Group, fulfillment.Order, fulfillment.Provider)
resp := app.Query(tmtypes.RequestQuery{Path: path})
assert.Empty(t, resp.Log)
require.True(t, resp.IsOK())
ful := new(types.Fulfillment)
require.NoError(t, ful.Unmarshal(resp.Value))

assert.Equal(t, fulfillment.Deployment, ful.Deployment)
assert.Equal(t, fulfillment.Group, ful.Group)
assert.Equal(t, fulfillment.Order, ful.Order)
assert.Equal(t, fulfillment.Provider, ful.Provider)
assert.Equal(t, fulfillment.Price, ful.Price)
}
func closeFulfillment(t *testing.T, app apptypes.Application, key *crypto.PrivKey, fulfillment *types.Fulfillment) {
testutil.CloseFulfillment(t, app, key, fulfillment)
path := query.FulfillmentPath(fulfillment.Deployment, fulfillment.Group, fulfillment.Order, fulfillment.Provider)
resp := app.Query(tmtypes.RequestQuery{Path: path})
assert.Empty(t, resp.Log)
require.True(t, resp.IsOK())
ful := new(types.Fulfillment)
require.NoError(t, ful.Unmarshal(resp.Value))

assert.Equal(t, types.Fulfillment_CLOSED, ful.State)
}

func TestTx_BadTxType(t *testing.T) {
Expand Down
13 changes: 11 additions & 2 deletions app/market/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,21 @@ func BestFulfillment(state state.State, order *types.Order) (*types.Fulfillment,

// match with cheapest order
bestMatch := 0
found := false
for i, fulfillment := range fulfillments {
if fulfillment.Price < fulfillments[bestMatch].Price {
bestMatch = i
if fulfillment.State == types.Fulfillment_OPEN {
found = true
if fulfillment.Price < fulfillments[bestMatch].Price {
bestMatch = i
}
}
}

// no orders to match
if !found {
return nil, nil
}

return fulfillments[bestMatch], nil
}

Expand Down
2 changes: 1 addition & 1 deletion app/types/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ const (

TagAppFulfillment = "fulfillment"
TxTypeCreateFulfillment = "fulfillment-create"
TxTypeCloseFulfillment = "fulfillment-close"

TagAppLease = "lease"
TxTypeCreateLease = "lease-create"
TxTypeCloseLease = "lease-close"

TagAppProvider = "provider"
TxTypeProviderCreate = "provider-create"
Expand Down
5 changes: 4 additions & 1 deletion cmd/akash/marketplace.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ func marketplaceMonitorHandler() marketplace.Handler {
X(tx.Provider), tx.Price)
}).
OnTxCloseDeployment(func(tx *types.TxCloseDeployment) {
fmt.Printf("DEPLOYMENT CLOSED\t%v", X(tx.Deployment))
fmt.Printf("DEPLOYMENT CLOSED\t%v\n", X(tx.Deployment))
}).
OnTxCloseFulfillment(func(tx *types.TxCloseFulfillment) {
fmt.Printf("FULFILLMENT CLOSED\t%v\n", X(tx.Fulfillment))
}).
Create()
}
55 changes: 55 additions & 0 deletions cmd/akash/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func providerCommand() *cobra.Command {

cmd.AddCommand(createProviderCommand())
cmd.AddCommand(runCommand())
cmd.AddCommand(closeFulfillmentCommand())

return cmd
}
Expand Down Expand Up @@ -187,6 +188,9 @@ func doProviderRunCommand(ctx context.Context, cmd *cobra.Command, args []string
fmt.Printf("Bidding on order: %v/%v/%v\n",
X(tx.Deployment), tx.Group, tx.Seq)

fmt.Printf("Fulfillment: %v\n",
X(state.FulfillmentID(tx.Deployment, tx.Group, tx.Seq, *provider)))

txbuf, err := txutil.BuildTx(signer, nonce, ordertx)
if err != nil {
ctx.Log().Error("error building tx", "error", err)
Expand Down Expand Up @@ -244,3 +248,54 @@ func getPrice(ctx context.Context, addr base.Bytes, seq uint64) (uint32, error)
}
return price, nil
}

func closeFulfillmentCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "closef",
Short: "close an open fulfillment",
Args: cobra.ExactArgs(1),
RunE: context.WithContext(context.RequireNode(doCloseFulfillmentCommand)),
}

context.AddFlagKeyType(cmd, cmd.Flags())

return cmd
}

func doCloseFulfillmentCommand(ctx context.Context, cmd *cobra.Command, args []string) error {
signer, _, err := ctx.Signer()
if err != nil {
return err
}

nonce, err := ctx.Nonce()
if err != nil {
return err
}

fulfillment := new(base.Bytes)
if err := fulfillment.DecodeString(args[0]); err != nil {
return err
}

tx, err := txutil.BuildTx(signer, nonce, &types.TxCloseFulfillment{
Fulfillment: *fulfillment,
})
if err != nil {
return err
}

result, err := ctx.Client().BroadcastTxCommit(tx)
if err != nil {
return err
}
if result.CheckTx.IsErr() {
return errors.New(result.CheckTx.GetLog())
}
if result.DeliverTx.IsErr() {
return errors.New(result.DeliverTx.GetLog())
}

return nil
}
14 changes: 14 additions & 0 deletions marketplace/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Handler interface {
OnTxCreateFulfillment(*types.TxCreateFulfillment)
OnTxCreateLease(*types.TxCreateLease)
OnTxCloseDeployment(*types.TxCloseDeployment)
OnTxCloseFulfillment(*types.TxCloseFulfillment)
}

type handler struct {
Expand All @@ -22,6 +23,7 @@ type handler struct {
onTxCreateFulfillment func(*types.TxCreateFulfillment)
onTxCreateLease func(*types.TxCreateLease)
onTxCloseDeployment func(*types.TxCloseDeployment)
onTxCloseFulfillment func(*types.TxCloseFulfillment)
}

func (h handler) OnTxSend(tx *types.TxSend) {
Expand Down Expand Up @@ -66,6 +68,12 @@ func (h handler) OnTxCloseDeployment(tx *types.TxCloseDeployment) {
}
}

func (h handler) OnTxCloseFulfillment(tx *types.TxCloseFulfillment) {
if h.onTxCloseFulfillment != nil {
h.onTxCloseFulfillment(tx)
}
}

type Builder interface {
OnTxSend(func(*types.TxSend)) Builder
OnTxCreateProvider(func(*types.TxCreateProvider)) Builder
Expand All @@ -74,6 +82,7 @@ type Builder interface {
OnTxCreateFulfillment(func(*types.TxCreateFulfillment)) Builder
OnTxCreateLease(func(*types.TxCreateLease)) Builder
OnTxCloseDeployment(func(*types.TxCloseDeployment)) Builder
OnTxCloseFulfillment(func(*types.TxCloseFulfillment)) Builder
Create() Handler
}

Expand Down Expand Up @@ -118,6 +127,11 @@ func (b *builder) OnTxCloseDeployment(fn func(*types.TxCloseDeployment)) Builder
return b
}

func (b *builder) OnTxCloseFulfillment(fn func(*types.TxCloseFulfillment)) Builder {
b.onTxCloseFulfillment = fn
return b
}

func (b *builder) Create() Handler {
return (handler)(*b)
}
Loading

0 comments on commit 658db91

Please sign in to comment.