From a29c65991b52c468685520f117cc185cadc44139 Mon Sep 17 00:00:00 2001 From: Stanislas POLU Date: Mon, 31 Jul 2017 10:24:38 -0700 Subject: [PATCH 1/3] Add support for transactions Memo --- mint/endpoint/create_transaction.go | 10 ++++++++++ mint/endpoint/validations.go | 19 +++++++++++++++++++ mint/model/schemas/mint.5.transactions.go | 2 ++ mint/model/transaction.go | 16 ++++++++++++---- mint/protocol.go | 4 ++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/mint/endpoint/create_transaction.go b/mint/endpoint/create_transaction.go index b7be17a..e7a69cc 100644 --- a/mint/endpoint/create_transaction.go +++ b/mint/endpoint/create_transaction.go @@ -44,6 +44,7 @@ type CreateTransaction struct { Amount big.Int Destination string Path []string + Memo *string // State Tx *model.Transaction @@ -133,6 +134,13 @@ func (e *CreateTransaction) Validate( return errors.Trace(err) } e.Path = path + + // Validate memo. + memo, err := ValidateMemo(ctx, r.PostFormValue("memo")) + if err != nil { + return errors.Trace(err) + } + e.Memo = memo } return nil @@ -172,6 +180,7 @@ func (e *CreateTransaction) ExecuteCanonical( e.Destination, model.OfPath(e.Path), mint.TxStPending, + e.Memo, ) if err != nil { return nil, nil, errors.Trace(err) // 500 @@ -326,6 +335,7 @@ func (e *CreateTransaction) ExecutePropagated( model.OfPath(e.Path), mint.TxStPending, transaction.Lock, + transaction.Memo, ) if err != nil { return nil, nil, errors.Trace(err) // 500 diff --git a/mint/endpoint/validations.go b/mint/endpoint/validations.go index e7c77b0..ae98a07 100644 --- a/mint/endpoint/validations.go +++ b/mint/endpoint/validations.go @@ -259,3 +259,22 @@ func ValidatePropagation( return &p, nil } + +// ValidateMemo validates a memo. +func ValidateMemo( + ctx context.Context, + memo string, +) (*string, error) { + if int64(len(memo)) > mint.MemoMaxLength { + return nil, errors.Trace(errors.NewUserErrorf(nil, + 400, "memo_invalid", + "The memo you provided exceeds the maximum length (%d): %s.", + mint.MemoMaxLength, memo, + )) + } + + if len(memo) == 0 { + return nil, nil + } + return &memo, nil +} diff --git a/mint/model/schemas/mint.5.transactions.go b/mint/model/schemas/mint.5.transactions.go index 18caacb..e198753 100644 --- a/mint/model/schemas/mint.5.transactions.go +++ b/mint/model/schemas/mint.5.transactions.go @@ -20,6 +20,8 @@ CREATE TABLE IF NOT EXISTS transactions( lock VARCHAR(256) NOT NULL, -- lock = hex(scrypt(secret, id)) secret VARCHAR(256), -- lock secret + memo VARCHAR(1024), -- memo + PRIMARY KEY(owner, token) ); ` diff --git a/mint/model/transaction.go b/mint/model/transaction.go index 5e2169e..3682e64 100644 --- a/mint/model/transaction.go +++ b/mint/model/transaction.go @@ -35,6 +35,8 @@ type Transaction struct { Lock string Secret *string + + Memo *string } // NewTransactionResource generates a new resource. @@ -57,6 +59,7 @@ func NewTransactionResource( Path: []string(transaction.Path), Status: transaction.Status, Lock: transaction.Lock, + Memo: transaction.Memo, Operations: []mint.OperationResource{}, Crossings: []mint.CrossingResource{}, } @@ -84,6 +87,7 @@ func CreateCanonicalTransaction( destination string, path []string, status mint.TxStatus, + memo *string, ) (*Transaction, error) { tok := token.New("transaction") @@ -109,16 +113,18 @@ func CreateCanonicalTransaction( Lock: lock, Secret: &secret, + + Memo: memo, } ext := db.Ext(ctx, "mint") if _, err := sqlx.NamedExec(ext, ` INSERT INTO transactions (owner, token, created, propagation, base_asset, quote_asset, - amount, destination, path, status, lock, secret) + amount, destination, path, status, lock, secret, memo) VALUES (:owner, :token, :created, :propagation, :base_asset, :quote_asset, - :amount, :destination, :path, :status, :lock, :secret) + :amount, :destination, :path, :status, :lock, :secret, :memo) `, transaction); err != nil { switch err := err.(type) { case *pq.Error: @@ -150,6 +156,7 @@ func CreatePropagatedTransaction( path []string, status mint.TxStatus, lock string, + memo *string, ) (*Transaction, error) { transaction := Transaction{ Owner: owner, @@ -165,16 +172,17 @@ func CreatePropagatedTransaction( Status: status, Lock: lock, Secret: nil, + Memo: memo, } ext := db.Ext(ctx, "mint") if _, err := sqlx.NamedExec(ext, ` INSERT INTO transactions (owner, token, created, propagation, base_asset, quote_asset, - amount, destination, path, status, lock, secret) + amount, destination, path, status, lock, secret, memo) VALUES (:owner, :token, :created, :propagation, :base_asset, :quote_asset, - :amount, :destination, :path, :status, :lock, :secret) + :amount, :destination, :path, :status, :lock, :secret, :memo) `, transaction); err != nil { switch err := err.(type) { case *pq.Error: diff --git a/mint/protocol.go b/mint/protocol.go index 862d22d..0e7f4fc 100644 --- a/mint/protocol.go +++ b/mint/protocol.go @@ -11,6 +11,8 @@ const ( // TransactionExpiryMs is the time it takes to attempt to cancel a // transaction for this mint. Expressed in ms. TransactionExpiryMs int64 = 1000 * 60 * 60 + // MemoMaxLength is the maximal length of a transaction's memo string. + MemoMaxLength int64 = 1024 ) // PgType is the propagation type of an object. @@ -140,6 +142,8 @@ type TransactionResource struct { Lock string `json:"lock"` Secret *string `json:"secret"` + Memo *string `json:"memo"` + Operations []OperationResource `json:"operations"` Crossings []CrossingResource `json:"crossings"` } From f36694727fed51a436645827368d72dc777cd191 Mon Sep 17 00:00:00 2001 From: Stanislas POLU Date: Mon, 7 Aug 2017 08:53:23 -0700 Subject: [PATCH 2/3] Tests for transaction memos --- TODO | 4 ++-- mint/test/functional/create_transaction_test.go | 6 ++++++ mint/test/functional/settle_transaction_test.go | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index 834d99b..8e8b692 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ # mint - [ ] allow cancellation from hop 0 by attempted propagation to last node - [ ] transaction reference and metadata + [ ] allow cancellation from hop k Date: Mon, 7 Aug 2017 09:09:06 -0700 Subject: [PATCH 3/3] Fix tests --- mint/test/functional/settle_transaction_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mint/test/functional/settle_transaction_test.go b/mint/test/functional/settle_transaction_test.go index c877ce0..ee32a0e 100644 --- a/mint/test/functional/settle_transaction_test.go +++ b/mint/test/functional/settle_transaction_test.go @@ -247,7 +247,6 @@ func TestSettleTransactionWithRemoteBaseAsset( "pair": {fmt.Sprintf("%s/%s", a[1].Name, a[1].Name)}, "amount": {"11"}, "destination": {u[0].Address}, - "memo": {"test-20162017"}, "path[]": {}, }) @@ -269,6 +268,7 @@ func TestSettleTransactionWithRemoteBaseAsset( "pair": {fmt.Sprintf("%s/%s", a[1].Name, a[2].Name)}, "amount": {"10"}, "destination": {u[2].Address}, + "memo": {"test-20162017"}, "path[]": { o[2].ID, }, @@ -292,7 +292,7 @@ func TestSettleTransactionWithRemoteBaseAsset( assert.Equal(t, mint.TxStSettled, tx0.Status) assert.Equal(t, 0, len(tx0.Operations)) assert.Equal(t, 0, len(tx0.Crossings)) - assert.Equal(t, "test-20162107", *tx0.Memo) + assert.Equal(t, "test-20162017", *tx0.Memo) // Check transaction on m[1]. status, raw = m[1].Get(t, nil, fmt.Sprintf("/transactions/%s", tx0.ID)) @@ -305,7 +305,7 @@ func TestSettleTransactionWithRemoteBaseAsset( assert.Equal(t, mint.TxStSettled, tx1.Status) assert.Equal(t, 0, len(tx1.Crossings)) assert.Equal(t, 1, len(tx1.Operations)) - assert.Equal(t, "test-20162107", *tx1.Memo) + assert.Equal(t, "test-20162017", *tx1.Memo) assert.Equal(t, mint.TxStSettled, tx1.Operations[0].Status) @@ -320,7 +320,7 @@ func TestSettleTransactionWithRemoteBaseAsset( assert.Equal(t, mint.TxStSettled, tx2.Status) assert.Equal(t, 1, len(tx2.Crossings)) assert.Equal(t, 1, len(tx2.Operations)) - assert.Equal(t, "test-20162107", *tx2.Memo) + assert.Equal(t, "test-20162017", *tx2.Memo) assert.Equal(t, mint.TxStSettled, tx2.Crossings[0].Status) assert.Equal(t, mint.TxStSettled, tx2.Operations[0].Status)