cashless2ecash

cashless2ecash: pay with cards for digital cash (experimental)
Log | Files | Refs | README

commit a9781c16b264f6e7bc12984f10333689a5704727
parent a093e52eea3e7d0cf07afc3d6bae1e7dfd5d42f0
Author: Joel-Haeberli <haebu@rubigen.ch>
Date:   Fri,  3 May 2024 20:45:36 +0200

fix: wire-gateway queries

Diffstat:
Mc2ec/api-wire-gateway.go | 18+++---------------
Mc2ec/c2ec-config.yaml | 4++--
Mc2ec/db-postgres.go | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msimulation/.gitignore | 4++--
Msimulation/c2ec-simulation | 0
Msimulation/encoding.go | 5-----
Msimulation/main.go | 19++++++++++++-------
Msimulation/sim-terminal.go | 8++++----
Msimulation/sim-wallet.go | 5+----
Asimulation/sim-wire-watch.go | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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)) + +}