commit a9781c16b264f6e7bc12984f10333689a5704727
parent a093e52eea3e7d0cf07afc3d6bae1e7dfd5d42f0
Author: Joel-Haeberli <haebu@rubigen.ch>
Date: Fri, 3 May 2024 20:45:36 +0200
fix: wire-gateway queries
Diffstat:
10 files changed, 147 insertions(+), 55 deletions(-)
diff --git a/c2ec/api-wire-gateway.go b/c2ec/api-wire-gateway.go
@@ -1,7 +1,6 @@
package main
import (
- "context"
"errors"
"log"
http "net/http"
@@ -252,7 +251,6 @@ func historyIncoming(res http.ResponseWriter, req *http.Request) {
if longPollMilliPtr, accepted := AcceptOptionalParamOrWriteResponse(
"long_poll_ms", strconv.Atoi, req, res,
); accepted {
- } else {
if longPollMilliPtr != nil {
longPollMilli = *longPollMilliPtr
} else {
@@ -262,27 +260,21 @@ func historyIncoming(res http.ResponseWriter, req *http.Request) {
}
}
- var start int
+ var start = -1 // read most recent entries by default
if startPtr, accepted := AcceptOptionalParamOrWriteResponse(
"start", strconv.Atoi, req, res,
); accepted {
- } else {
if startPtr != nil {
start = *startPtr
}
}
- var delta int
+ var delta = 0
if deltaPtr, accepted := AcceptOptionalParamOrWriteResponse(
"delta", strconv.Atoi, req, res,
); accepted {
- } else {
if deltaPtr != nil {
delta = *deltaPtr
- } else {
- // this means parameter was not given.
- // no long polling (simple get)
- shouldStartLongPoll = false
}
}
@@ -292,12 +284,8 @@ func historyIncoming(res http.ResponseWriter, req *http.Request) {
if shouldStartLongPoll {
- // wait for the completion of the context
- waitMs, cancelFunc := context.WithTimeout(req.Context(), time.Duration(longPollMilli)*time.Millisecond)
- defer cancelFunc()
-
// this will just wait / block until the milliseconds are exceeded.
- <-waitMs.Done()
+ time.Sleep(time.Duration(longPollMilli) * time.Millisecond)
}
withdrawals, err := DB.GetConfirmedWithdrawals(start, delta)
diff --git a/c2ec/c2ec-config.yaml b/c2ec/c2ec-config.yaml
@@ -6,7 +6,7 @@ c2ec:
unix-socket-path: "c2ec.sock"
unix-path-mode: 660
fail-on-missing-attestors: false # forced if prod=true
- credit-account: "payto://iban/CH50030202099498" # this account must be specified at the providers backends as well
+ credit-account: "payto://IBAN/CH50030202099498" # this account must be specified at the providers backends as well
currency: "CHF"
max-retries: 3
retry-delay-ms: 1000
@@ -21,6 +21,6 @@ db:
database: "postgres"
providers:
- name: "Wallee"
- credentials-password: "secret" # dummy terminal password: cNuEkK4iT4NpREqTbpYfZxpM0Skvvw+niJOT47QtM90=
+ credentials-password: "secret"
- name: "Simulation"
credentials-password: "secret"
diff --git a/c2ec/db-postgres.go b/c2ec/db-postgres.go
@@ -52,18 +52,6 @@ const PS_SET_RETRY_COUNTER = "UPDATE " + WITHDRAWAL_TABLE_NAME +
" SET " + WITHDRAWAL_FIELD_NAME_RETRY_COUNTER + "=$1" +
" WHERE " + WITHDRAWAL_FIELD_NAME_ID + "=$2"
-const PS_CONFIRMED_TRANSACTIONS_ASC = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
- " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
- " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " ASC" +
- " LIMIT $1" +
- " OFFSET $2"
-
-const PS_CONFIRMED_TRANSACTIONS_DESC = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
- " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
- " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " DESC" +
- " LIMIT $1" +
- " OFFSET $2"
-
const PS_GET_WITHDRAWAL_BY_RUID = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
" WHERE " + WITHDRAWAL_FIELD_NAME_RUID + "=$1"
@@ -103,6 +91,30 @@ const PS_UPDATE_TRANSFER = "UPDATE " + TRANSFER_TABLE_NAME + " SET (" +
TRANSFER_FIELD_NAME_RETRIES + ") VALUES ($1,$2,$3) WHERE " +
TRANSFER_FIELD_NAME_ID + "=$4"
+const PS_CONFIRMED_TRANSACTIONS_ASC = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
+ " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
+ " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " ASC" +
+ " LIMIT $1" +
+ " OFFSET $2"
+
+const PS_CONFIRMED_TRANSACTIONS_DESC = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
+ " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
+ " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " DESC" +
+ " LIMIT $1" +
+ " OFFSET $2"
+
+const PS_CONFIRMED_TRANSACTIONS_ASC_MAX = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
+ " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
+ " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " ASC" +
+ " LIMIT $1" +
+ " OFFSET ((SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + ")-2)"
+
+const PS_CONFIRMED_TRANSACTIONS_DESC_MAX = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME +
+ " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" +
+ " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " DESC" +
+ " LIMIT $1" +
+ " OFFSET ((SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + ")-2)"
+
const PS_GET_TRANSFERS_ASC = "SELECT * FROM " + TRANSFER_TABLE_NAME +
" ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " ASC" +
" LIMIT $1" +
@@ -113,6 +125,20 @@ const PS_GET_TRANSFERS_DESC = "SELECT * FROM " + TRANSFER_TABLE_NAME +
" LIMIT $1" +
" OFFSET $2"
+const PS_GET_TRANSFERS_ASC_MAX = "SELECT * FROM " + TRANSFER_TABLE_NAME +
+ " ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " ASC" +
+ " LIMIT $1" +
+ " OFFSET ((SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + ")-2)"
+
+const PS_GET_TRANSFERS_DESC_MAX = "SELECT * FROM " + TRANSFER_TABLE_NAME +
+ " ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " DESC" +
+ " LIMIT $1" +
+ " OFFSET ((SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + ")-2)"
+
+const PS_WITHDRAWAL_MAX_OFFSET_QUERY = "((SELECT COUNT(*) FROM withdrawal)-1)" //"(SELECT ((SELECT last_value FROM c2ec.withdrawal_withdrawal_row_id_seq)-(((SELECT last_value FROM c2ec.withdrawal_withdrawal_row_id_seq)-(SELECT COUNT(*) FROM c2ec.withdrawal))))-1)"
+
+const PS_TRANSFER_MAX_OFFSET_QUERY = "(SELECT ((SELECT last_value FROM c2ec.transfer_row_id_seq)-(((SELECT last_value FROM c2ec.transfer_row_id_seq)-(SELECT COUNT(*) FROM c2ec.transfer))))-1)"
+
// Postgres implementation of the C2ECDatabase
type C2ECPostgres struct {
C2ECDatabase
@@ -148,14 +174,14 @@ func PostgresConnectionString(cfg *C2ECDatabseConfig) string {
if pgPassword != "" {
LogInfo("postgres", "pghost was set")
} else {
- pgHost = cfg.Host
+ pgPassword = cfg.Password
}
pgDb := os.Getenv(" PGDATABASE")
if pgDb != "" {
LogInfo("postgres", "pghost was set")
} else {
- pgDb = cfg.Host
+ pgDb = cfg.Database
}
return fmt.Sprintf(
@@ -465,6 +491,13 @@ func (db *C2ECPostgres) GetConfirmedWithdrawals(start int, delta int) ([]*Withdr
query := PS_CONFIRMED_TRANSACTIONS_ASC
if delta < 0 {
query = PS_CONFIRMED_TRANSACTIONS_DESC
+ if start < 0 {
+ query = PS_CONFIRMED_TRANSACTIONS_DESC_MAX
+ }
+ } else {
+ if start < 0 {
+ query = PS_CONFIRMED_TRANSACTIONS_ASC_MAX
+ }
}
limit := math.Abs(float64(delta))
@@ -486,7 +519,6 @@ func (db *C2ECPostgres) GetConfirmedWithdrawals(start int, delta int) ([]*Withdr
db.ctx,
query,
limit,
- "MAX("+WITHDRAWAL_FIELD_NAME_ID+")",
)
} else {
row, err = db.pool.Query(
@@ -714,6 +746,13 @@ func (db *C2ECPostgres) GetTransfers(start int, delta int) ([]*Transfer, error)
query := PS_GET_TRANSFERS_ASC
if delta < 0 {
query = PS_GET_TRANSFERS_DESC
+ if start < 0 {
+ query = PS_GET_TRANSFERS_DESC_MAX
+ }
+ } else {
+ if start < 0 {
+ query = PS_GET_TRANSFERS_ASC_MAX
+ }
}
limit := math.Abs(float64(delta))
@@ -735,7 +774,6 @@ func (db *C2ECPostgres) GetTransfers(start int, delta int) ([]*Transfer, error)
db.ctx,
query,
limit,
- "MAX("+TRANSFER_FIELD_NAME_ROW_ID+")",
)
} else {
row, err = db.pool.Query(
diff --git a/simulation/.gitignore b/simulation/.gitignore
@@ -1 +1,2 @@
-local-config.yaml
-\ No newline at end of file
+local-config.yaml
+online-config.yaml
diff --git a/simulation/c2ec-simulation b/simulation/c2ec-simulation
Binary files differ.
diff --git a/simulation/encoding.go b/simulation/encoding.go
@@ -15,11 +15,6 @@ func talerBinaryEncode(byts []byte) string {
func talerBinaryDecode(str string) ([]byte, error) {
return decodeCrock(str)
- // decoded, err := talerBase32Encoding().DecodeString(strings.ToUpper(str))
- // if err != nil {
- // return nil, err
- // }
- // return decoded, nil
}
func ParseWopid(wopid string) ([]byte, error) {
diff --git a/simulation/main.go b/simulation/main.go
@@ -7,10 +7,6 @@ import (
"gopkg.in/yaml.v3"
)
-const TERMINAL_ACCEPT_CARD_DELAY_MS = 5000
-
-const WALLET_SCAN_QR_CODE_DELAY_MS = 5000
-
var CONFIG SimulationConfig
type SimulatedPhysicalInteraction struct {
@@ -40,6 +36,7 @@ func main() {
kill := make(chan error)
toTerminal := make(chan *SimulatedPhysicalInteraction, 10)
toWallet := make(chan *SimulatedPhysicalInteraction, 10)
+ finish := make(chan interface{})
// start simulated terminal
go Terminal(toTerminal, toWallet, kill)
@@ -47,6 +44,9 @@ func main() {
// start simulated wallet
go Wallet(toWallet, toTerminal, kill)
+ // start simulated wire watch
+ go WireWatch(finish, kill)
+
for err := range kill {
if err == nil {
fmt.Print("simulation successful.")
@@ -55,6 +55,9 @@ func main() {
fmt.Println("simulation error: ", err.Error())
os.Exit(1)
}
+
+ <-finish
+ fmt.Println("simulation ended")
}
func c2ecAlive() bool {
@@ -71,7 +74,7 @@ func c2ecAlive() bool {
return false
}
- fmt.Println("C2EC-Config:", cfg.Name, cfg.Version, cfg.ProviderName, cfg.WireType)
+ fmt.Println("ALIVE :", cfg.Name, cfg.Version, cfg.ProviderName, cfg.WireType)
return true
}
@@ -89,8 +92,10 @@ type SimulationConfig struct {
TerminalLongPollMs string `yaml:"terminal-long-poll-ms"`
TerminalQrCodeBase string `yaml:"terminal-qr-base"`
// simulates the user scanning the QR code presented at the terminal
- WalletScanQrDelay int `yaml:"wallet-scan-qr-delay"`
- WalletLongPollMs string `yaml:"wallet-long-poll-ms"`
+ WalletScanQrDelay int `yaml:"wallet-scan-qr-delay"`
+ WalletLongPollMs string `yaml:"wallet-long-poll-ms"`
+ WireGatewayUsername string `yaml:"wire-gateway-user"`
+ WireGatewayPassword string `yaml:"wire-gateway-password"`
}
func parseSimulationConfig(path string) (*SimulationConfig, error) {
diff --git a/simulation/sim-terminal.go b/simulation/sim-terminal.go
@@ -132,8 +132,8 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical
time.Sleep(time.Duration(10) * time.Millisecond)
if !CONFIG.DisableDelays {
- fmt.Println("TERMINAL: simulating QR Code scan. delay:", WALLET_SCAN_QR_CODE_DELAY_MS)
- time.Sleep(time.Duration(WALLET_SCAN_QR_CODE_DELAY_MS) * time.Millisecond)
+ fmt.Println("TERMINAL: simulating QR Code scan. delay:", CONFIG.WalletScanQrDelay)
+ time.Sleep(time.Duration(CONFIG.WalletScanQrDelay) * time.Millisecond)
} else {
fmt.Println("TERMINAL: simulating QR Code scan.")
}
@@ -143,8 +143,8 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical
case w := <-awaitSelection:
fmt.Println("TERMINAL: parameters selected:", w.ReservePubKey)
if !CONFIG.DisableDelays {
- fmt.Println("TERMINAL: simulating user interaction. customer presents card. delay:", TERMINAL_ACCEPT_CARD_DELAY_MS)
- time.Sleep(time.Duration(TERMINAL_ACCEPT_CARD_DELAY_MS) * time.Millisecond)
+ fmt.Println("TERMINAL: simulating user interaction. customer presents card. delay:", CONFIG.TerminalAcceptCardDelay)
+ time.Sleep(time.Duration(CONFIG.TerminalAcceptCardDelay) * time.Millisecond)
} else {
fmt.Println("TERMINAL: simulating user interaction. customer presents card.")
}
diff --git a/simulation/sim-wallet.go b/simulation/sim-wallet.go
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
- "os"
"strconv"
"strings"
"time"
@@ -26,7 +25,7 @@ func Wallet(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalIn
uriFromQrCode := <-in
if !CONFIG.DisableDelays {
- time.Sleep(time.Duration(WALLET_SCAN_QR_CODE_DELAY_MS) * time.Millisecond)
+ time.Sleep(time.Duration(CONFIG.WalletScanQrDelay) * time.Millisecond)
}
fmt.Println("WALLET : simulated QR code scanning... scanned", uriFromQrCode)
wopid, err := parseTalerWithdrawUri(uriFromQrCode.Msg)
@@ -108,11 +107,9 @@ func Wallet(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalIn
fmt.Println("WALLET : payment processed:", w.Status)
if w.Status == CONFIRMED {
fmt.Println("WALLET : the exchange would now create the reserve and the wallet can withdraw the reserve")
- os.Exit(0)
}
if w.Status == ABORTED {
fmt.Println("WALLET : the withdrawal was aborted. c2ec cleans up withdrawal")
- os.Exit(0)
}
case f := <-longPollFailed:
fmt.Println("WALLET : long-polling for selection failed... error:", f.Error())
diff --git a/simulation/sim-wire-watch.go b/simulation/sim-wire-watch.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "strconv"
+)
+
+type IncomingReserveTransaction struct {
+ Type string `json:"type"`
+ RowId int `json:"row_id"`
+ Date Timestamp `json:"date"`
+ Amount Amount `json:"amount"`
+ DebitAccount string `json:"debit_account"`
+ ReservePub EddsaPublicKey `json:"reserve_pub"`
+}
+
+func WireWatch(finish chan interface{}, kill chan error) {
+
+ var wirewatchLongPoll int
+ if CONFIG.DisableDelays {
+ wirewatchLongPoll = 3000
+ } else {
+ wirewatchLongPoll = CONFIG.ProviderBackendPaymentDelay +
+ CONFIG.TerminalAcceptCardDelay +
+ CONFIG.WalletScanQrDelay +
+ 2000 // add some delay for operations
+ }
+
+ fmt.Println("WIRE-WATCH: long poll to c2ec for ", wirewatchLongPoll, "milliseconds")
+
+ var HISTORY_ENDPOINT = CONFIG.C2ecBaseUrl + "/taler-wire-gateway/history/incoming"
+
+ url := FormatUrl(
+ HISTORY_ENDPOINT,
+ map[string]string{},
+ map[string]string{"long_poll_ms": strconv.Itoa(wirewatchLongPoll)},
+ )
+ fmt.Println("WIRE-WATCH: requesting status update for withdrawal", url)
+ response, status, err := HttpGet(
+ url,
+ map[string]string{"Authorization": WireGatewayAuth()},
+ NewJsonCodec[[]*IncomingReserveTransaction](),
+ )
+ if err != nil {
+ kill <- err
+ return
+ }
+ if status != 200 {
+ kill <- errors.New("wire-watch could not retrieve transaction: " + strconv.Itoa(status))
+ return
+ }
+
+ res := *response
+ for _, r := range res {
+ a := fmt.Sprintf("%d.%d %s", r.Amount.Value, r.Amount.Value, r.Amount.Currency)
+ fmt.Println("WIRE-WATCH: Incoming Reserve Transaction(", r.RowId, r.DebitAccount, a, r.ReservePub, ")")
+ }
+
+ finish <- nil
+}
+
+func WireGatewayAuth() string {
+
+ userAndPw := fmt.Sprintf("%s:%s", CONFIG.WireGatewayUsername, CONFIG.WireGatewayPassword)
+ return "Basic " + base64.StdEncoding.EncodeToString([]byte(userAndPw))
+
+}