├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github ├── settings.yml └── workflows │ └── go.yml ├── .gitignore ├── .golangci.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── README.md ├── SECURITY.md ├── cmd ├── client.go ├── client_eventstreams.go ├── client_eventstreams_delete.go ├── client_eventstreams_delete_test.go ├── client_eventstreams_list.go ├── client_eventstreams_list_test.go ├── client_listeners.go ├── client_listeners_delete.go ├── client_listeners_delete_test.go ├── client_listeners_list.go ├── client_listeners_list_test.go ├── client_test.go ├── migrate.go └── migrate_test.go ├── codecov.yml ├── config.md ├── db └── migrations │ └── postgres │ ├── 000001_create_transactions_table.down.sql │ ├── 000001_create_transactions_table.up.sql │ ├── 000002_create_receipts_table.down.sql │ ├── 000002_create_receipts_table.up.sql │ ├── 000003_create_confirmations_table.down.sql │ ├── 000003_create_confirmations_table.up.sql │ ├── 000004_create_txhistory_table.down.sql │ ├── 000004_create_txhistory_table.up.sql │ ├── 000005_create_checkpoints_table.down.sql │ ├── 000005_create_checkpoints_table.up.sql │ ├── 000006_create_eventstreams_table.down.sql │ ├── 000006_create_eventstreams_table.up.sql │ ├── 000007_create_listeners_table.down.sql │ ├── 000007_create_listeners_table.up.sql │ ├── 000008_create_txhistory_idx.down.sql │ ├── 000008_create_txhistory_idx.up.sql │ ├── 000009_add_transactions_status_index.down.sql │ ├── 000009_add_transactions_status_index.up.sql │ ├── 000010_add_listeners_type.down.sql │ └── 000010_add_listeners_type.up.sql ├── go.mod ├── go.sum ├── grafana_dash └── Event process metrics-1717595375618.json ├── images ├── fftm_event_streams_architecture.jpg └── firefly_connector_framework_architecture.jpg ├── internal ├── apiclient │ ├── eventstreams.go │ ├── eventstreams_test.go │ ├── fftm_client.go │ └── fftm_client_test.go ├── blocklistener │ ├── blocklistener.go │ └── blocklistener_test.go ├── confirmations │ ├── confirmations.go │ ├── confirmations_test.go │ ├── confirmed_block_listener.go │ ├── confirmed_block_listener_test.go │ ├── receipt_checker.go │ └── receipt_checker_test.go ├── events │ ├── eventstream.go │ ├── eventstream_test.go │ ├── listener.go │ ├── webhooks.go │ ├── webhooks_test.go │ ├── websockets.go │ └── websockets_test.go ├── metrics │ ├── event_metrics.go │ ├── event_metrics_test.go │ ├── metrics.go │ └── metrics_test.go ├── persistence │ ├── dbmigration │ │ ├── leveldb2postgres.go │ │ ├── leveldb2postgres_test.go │ │ ├── migration.go │ │ └── migration_test.go │ ├── leveldb │ │ ├── leveldb_persistence.go │ │ ├── leveldb_persistence_test.go │ │ ├── nonces.go │ │ └── nonces_test.go │ ├── persistence.go │ ├── persistence_test.go │ └── postgres │ │ ├── checkpoints.go │ │ ├── checkpoints_test.go │ │ ├── confirmations.go │ │ ├── confirmations_test.go │ │ ├── eventstreams.go │ │ ├── eventstreams_test.go │ │ ├── listeners.go │ │ ├── listeners_test.go │ │ ├── postgres.go │ │ ├── postgres_test.go │ │ ├── receipts.go │ │ ├── receipts_test.go │ │ ├── sqlpersistence.go │ │ ├── sqlpersistence_test.go │ │ ├── transaction_writer.go │ │ ├── transaction_writer_test.go │ │ ├── transactions.go │ │ ├── transactions_test.go │ │ ├── txhistory.go │ │ └── txhistory_test.go ├── tmconfig │ ├── tmconfig.go │ └── tmconfig_test.go ├── tmmsgs │ ├── en_api_descriptions.go │ ├── en_config_descriptions.go │ └── en_error_messages.go └── ws │ ├── wsconn.go │ ├── wsserver.go │ └── wsserver_test.go ├── mocks ├── apiclientmocks │ └── fftm_client.go ├── confirmationsmocks │ └── manager.go ├── eventsmocks │ └── stream.go ├── ffcapimocks │ └── api.go ├── metricsmocks │ ├── event_metrics_emitter.go │ └── transaction_handler_metrics.go ├── persistencemocks │ ├── persistence.go │ ├── rich_query.go │ └── transaction_persistence.go ├── txhandlermocks │ ├── managed_tx_event_handler.go │ └── transaction_handler.go └── wsmocks │ ├── web_socket_channels.go │ └── web_socket_server.go ├── pkg ├── apitypes │ ├── api_types.go │ ├── api_types_test.go │ ├── base_request.go │ ├── base_request_test.go │ ├── managed_tx.go │ ├── managed_tx_test.go │ ├── query_request.go │ ├── tx_request.go │ ├── txreceipt_request.go │ ├── ulid.go │ └── ulid_test.go ├── ffcapi │ ├── address_balance.go │ ├── api.go │ ├── api_test.go │ ├── block_info_by_hash.go │ ├── block_info_by_number.go │ ├── contract_deploy_prepare.go │ ├── event_listener_add.go │ ├── event_listener_hwm.go │ ├── event_listener_remove.go │ ├── event_stream_start.go │ ├── event_stream_stopped.go │ ├── gas_estimate.go │ ├── gas_price_estimate.go │ ├── is_live.go │ ├── is_ready.go │ ├── method_call.go │ ├── new_block_listener.go │ ├── next_nonce_for_signer.go │ ├── submission_error.go │ ├── submission_error_test.go │ ├── transaction_prepare.go │ ├── transaction_receipt.go │ └── transaction_send.go ├── fftm │ ├── address_management.go │ ├── address_management_test.go │ ├── api.go │ ├── api_test.go │ ├── config_docs_generate_test.go │ ├── config_docs_test.go │ ├── gas_management.go │ ├── manager.go │ ├── manager_test.go │ ├── route__root_command.go │ ├── route_delete_eventstream.go │ ├── route_delete_eventstream_listener.go │ ├── route_delete_eventstream_listener_test.go │ ├── route_delete_eventstream_test.go │ ├── route_delete_subscription.go │ ├── route_delete_subscription_test.go │ ├── route_delete_transaction.go │ ├── route_delete_transaction_test.go │ ├── route_get_address_balance.go │ ├── route_get_address_balance_test.go │ ├── route_get_eventstream.go │ ├── route_get_eventstream_listener.go │ ├── route_get_eventstream_listener_test.go │ ├── route_get_eventstream_listeners.go │ ├── route_get_eventstream_listeners_test.go │ ├── route_get_eventstream_test.go │ ├── route_get_eventstreams.go │ ├── route_get_eventstreams_test.go │ ├── route_get_gas_price.go │ ├── route_get_gas_price_test.go │ ├── route_get_status_live.go │ ├── route_get_status_live_test.go │ ├── route_get_status_ready.go │ ├── route_get_status_ready_test.go │ ├── route_get_subscription.go │ ├── route_get_subscription_test.go │ ├── route_get_subscriptions.go │ ├── route_get_subscriptions_test.go │ ├── route_get_transaction.go │ ├── route_get_transaction_confirmations.go │ ├── route_get_transaction_confirmations_test.go │ ├── route_get_transaction_history.go │ ├── route_get_transaction_history_test.go │ ├── route_get_transaction_receipt.go │ ├── route_get_transaction_receipt_test.go │ ├── route_get_transaction_test.go │ ├── route_get_transactions.go │ ├── route_get_transactions_test.go │ ├── route_patch_eventstream.go │ ├── route_patch_eventstream_listener.go │ ├── route_patch_eventstream_listener_test.go │ ├── route_patch_eventstream_test.go │ ├── route_patch_subscription.go │ ├── route_patch_subscription_test.go │ ├── route_post_eventstream.go │ ├── route_post_eventstream_listener_reset.go │ ├── route_post_eventstream_listener_reset_test.go │ ├── route_post_eventstream_listeners.go │ ├── route_post_eventstream_listeners_test.go │ ├── route_post_eventstream_resume.go │ ├── route_post_eventstream_resume_test.go │ ├── route_post_eventstream_suspend.go │ ├── route_post_eventstream_suspend_test.go │ ├── route_post_eventstream_test.go │ ├── route_post_subscription_reset.go │ ├── route_post_subscription_reset_test.go │ ├── route_post_subscriptions.go │ ├── route_post_subscriptions_test.go │ ├── route_post_transaction_resume.go │ ├── route_post_transaction_resume_test.go │ ├── route_post_transaction_suspend.go │ ├── route_post_transaction_suspend_test.go │ ├── routes.go │ ├── status_management.go │ ├── status_management_test.go │ ├── stream_management.go │ ├── stream_management_test.go │ ├── transaction_events_handler.go │ ├── transaction_events_handler_test.go │ ├── transaction_management.go │ └── transaction_management_test.go └── txhandler │ ├── registry │ ├── registry.go │ └── registry_test.go │ ├── simple │ ├── config.go │ ├── metrics.go │ ├── policyloop.go │ ├── policyloop_test.go │ ├── simple_transaction_hander_test.go │ └── simple_transaction_handler.go │ └── txhandler.go └── test ├── empty-config.fftm.yaml ├── firefly.fftm.yaml └── quick-fail.fftm.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/coverage 3 | **/.nyc_output 4 | firefly-transaction-manager -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{yaml,yml,json}] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.go licensefile=.githooks/license-maintainer/LICENSE-go -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | name: firefly-transaction-manager 3 | default_branch: main 4 | has_downloads: false 5 | has_issues: true 6 | has_projects: false 7 | has_wiki: false 8 | archived: false 9 | private: false 10 | allow_squash_merge: false 11 | allow_merge_commit: false 12 | allow_rebase_merge: true 13 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | container: golang:1.23-bookworm 14 | defaults: 15 | run: 16 | shell: bash # needed for codecov 17 | services: 18 | postgres: 19 | image: postgres 20 | env: 21 | POSTGRES_PASSWORD: f1refly 22 | options: >- 23 | --health-cmd pg_isready 24 | --health-interval 10s 25 | --health-timeout 5s 26 | --health-retries 5 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 31 | 32 | - name: Fetch history # See https://github.com/actions/checkout/issues/477 33 | run: |- 34 | git config --global --add safe.directory $PWD 35 | git fetch origin 36 | 37 | - name: Build and Test 38 | env: 39 | TEST_FLAGS: -v 40 | POSTGRES_HOSTNAME: postgres 41 | POSTGRES_PASSWORD: f1refly 42 | POSTGRES_PORT: 5432 43 | run: make 44 | 45 | - name: Upload coverage 46 | run: bash <(curl -s https://codecov.io/bash) 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.jar 2 | firefly-transaction-manager 3 | coverage.txt 4 | **/debug.test 5 | .DS_Store 6 | __debug* 7 | .vscode/*.log 8 | *.iml 9 | .idea/ 10 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | tests: false 3 | skip-dirs: 4 | - "mocks" 5 | linters-settings: 6 | golint: {} 7 | gocritic: 8 | enabled-checks: [] 9 | disabled-checks: 10 | - regexpMust 11 | gosec: 12 | excludes: 13 | - G402 14 | goheader: 15 | values: 16 | regexp: 17 | COMPANY: .* 18 | YEAR_FUZZY: '\d\d\d\d(,\d\d\d\d)?' 19 | template: |- 20 | Copyright © {{ YEAR_FUZZY }} {{ COMPANY }} 21 | 22 | SPDX-License-Identifier: Apache-2.0 23 | 24 | Licensed under the Apache License, Version 2.0 (the "License"); 25 | you may not use this file except in compliance with the License. 26 | You may obtain a copy of the License at 27 | 28 | http://www.apache.org/licenses/LICENSE-2.0 29 | 30 | Unless required by applicable law or agreed to in writing, software 31 | distributed under the License is distributed on an "AS IS" BASIS, 32 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 33 | See the License for the specific language governing permissions and 34 | limitations under the License. 35 | linters: 36 | disable-all: false 37 | enable: 38 | - bodyclose 39 | - dogsled 40 | - errcheck 41 | - goconst 42 | - gocritic 43 | - gocyclo 44 | - gofmt 45 | - goheader 46 | - goimports 47 | - goprintffuncname 48 | - gosec 49 | - gosimple 50 | - govet 51 | - ineffassign 52 | - misspell 53 | - nakedret 54 | - revive 55 | - staticcheck 56 | - stylecheck 57 | - typecheck 58 | - unconvert 59 | - unparam 60 | - unused 61 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "go.formatFlags": ["-s"], 3 | "go.lintTool": "golangci-lint", 4 | "cSpell.words": [ 5 | "apiclient", 6 | "APIID", 7 | "apitypes", 8 | "badurl", 9 | "blocklistener", 10 | "ccache", 11 | "Compat", 12 | "confirmationsmocks", 13 | "dataexchange", 14 | "Debugf", 15 | "devdocs", 16 | "Devel", 17 | "distmode", 18 | "Dont", 19 | "ehtype", 20 | "estype", 21 | "ethconnect", 22 | "ethtypes", 23 | "eventsmocks", 24 | "eventstream", 25 | "eventstreams", 26 | "fabconnect", 27 | "ffapi", 28 | "ffcapi", 29 | "ffcapimocks", 30 | "ffcore", 31 | "FFDX", 32 | "ffenum", 33 | "ffexclude", 34 | "ffexcludeinput", 35 | "ffexcludeoutput", 36 | "ffievents", 37 | "FFIID", 38 | "ffimethods", 39 | "ffresty", 40 | "ffstruct", 41 | "fftm", 42 | "fftmrequest", 43 | "fftypes", 44 | "finalizers", 45 | "getkin", 46 | "GJSON", 47 | "goleveldb", 48 | "httpserver", 49 | "hyperledger", 50 | "idempotence", 51 | "Infof", 52 | "IPFS", 53 | "jsonmap", 54 | "Kaleido", 55 | "leveldb", 56 | "loadbalanced", 57 | "logrus", 58 | "metricsmocks", 59 | "mtxs", 60 | "NATS", 61 | "Nowarn", 62 | "oapispec", 63 | "oklog", 64 | "openapi", 65 | "optype", 66 | "persistencemocks", 67 | "pluggable", 68 | "policyengine", 69 | "policyloop", 70 | "protocolid", 71 | "restapi", 72 | "resty", 73 | "santhosh", 74 | "secp", 75 | "sigs", 76 | "stretchr", 77 | "syndtr", 78 | "sysmessaging", 79 | "tekuri", 80 | "tmconfig", 81 | "tmmsgs", 82 | "Tracef", 83 | "txcommon", 84 | "txcommonmocks", 85 | "txhandler", 86 | "txhandlerfactory", 87 | "txhandlermocks", 88 | "txhistory", 89 | "txid", 90 | "txns", 91 | "txtype", 92 | "txwriter", 93 | "unflushed", 94 | "unmarshalled", 95 | "unmarshalling", 96 | "upgrader", 97 | "upsert", 98 | "upserts", 99 | "Warnf", 100 | "whconfig", 101 | "workloaddistribution", 102 | "wsclient", 103 | "wsconfig", 104 | "wsmocks" 105 | ], 106 | "go.testTimeout": "20s" 107 | } 108 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | [FireFly Transaction Manager Releases](https://github.com/hyperledger/firefly-transaction-manager/releases) 4 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | * @hyperledger/firefly-transaction-manager-maintainers 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct Guidelines 2 | 3 | Please review the Hyperledger [Code of 4 | Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) 5 | before participating. It is important that we keep things civil. 6 | 7 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | We welcome contributions to the FireFly Project in many forms, and 4 | there's always plenty to do! 5 | 6 | Please visit the 7 | [contributors guide](https://hyperledger.github.io/firefly//contributors/contributors.html) in the 8 | docs to learn how to make contributions to this exciting project. 9 | 10 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 11 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # firefly-transaction-manager-maintainers 2 | 3 | The following is the list of current maintainers this repo: 4 | 5 | | Name | GitHub | Email | LFID | 6 | | ----------------- | --------------- | ---------------------------- | ----------------- | 7 | | Peter Broadhurst | peterbroadhurst | peter.broadhurst@kaleido.io | peterbroadhurst | 8 | | Enrique Lacal | enriquel8 | enrique.lacal@kaleido.io | enriquelacal | 9 | | Andrew Richardson | awrichar | andrew.richardson@kaleido.io | Andrew.Richardson | 10 | | Chengxuan Xing | Chengxuan | chengxuan.xing@kaleido.io | chengxuanxing | 11 | 12 | This list is to be kept up to date as maintainers are added or removed. 13 | 14 | For the full list of maintainers across all repos, the expectations of a maintainer and the process for becoming a maintainer, please see the [FireFly Maintainers page on the Hyperledger Wiki](https://wiki.hyperledger.org/display/FIR/Maintainers). 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VGO=go 2 | GOFILES := $(shell find internal pkg -name '*.go' -print) 3 | GOBIN := $(shell $(VGO) env GOPATH)/bin 4 | LINT := $(GOBIN)/golangci-lint 5 | MOCKERY := $(GOBIN)/mockery 6 | 7 | # Expect that FireFly compiles with CGO disabled 8 | CGO_ENABLED=0 9 | GOGC=30 10 | 11 | .DELETE_ON_ERROR: 12 | 13 | all: build test go-mod-tidy 14 | test: deps lint 15 | $(VGO) test ./internal/... ./pkg/... -cover -coverprofile=coverage.txt -covermode=atomic -timeout=30s ${TEST_FLAGS} 16 | coverage.html: 17 | $(VGO) tool cover -html=coverage.txt 18 | coverage: test coverage.html 19 | lint: 20 | $(VGO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 21 | GOGC=20 $(LINT) run -v --timeout 5m 22 | 23 | ${MOCKERY}: 24 | $(VGO) install github.com/vektra/mockery/v2@v2.43.1 25 | 26 | define makemock 27 | mocks: mocks-$(strip $(1))-$(strip $(2)) 28 | mocks-$(strip $(1))-$(strip $(2)): ${MOCKERY} 29 | ${MOCKERY} --case underscore --dir $(1) --name $(2) --outpkg $(3) --output mocks/$(strip $(3)) 30 | endef 31 | 32 | $(eval $(call makemock, pkg/ffcapi, API, ffcapimocks)) 33 | $(eval $(call makemock, pkg/txhandler, TransactionHandler, txhandlermocks)) 34 | $(eval $(call makemock, pkg/txhandler, ManagedTxEventHandler, txhandlermocks)) 35 | $(eval $(call makemock, internal/metrics, TransactionHandlerMetrics, metricsmocks)) 36 | $(eval $(call makemock, internal/metrics, EventMetricsEmitter, metricsmocks)) 37 | $(eval $(call makemock, internal/confirmations, Manager, confirmationsmocks)) 38 | $(eval $(call makemock, internal/persistence, Persistence, persistencemocks)) 39 | $(eval $(call makemock, internal/persistence, TransactionPersistence, persistencemocks)) 40 | $(eval $(call makemock, internal/persistence, RichQuery, persistencemocks)) 41 | $(eval $(call makemock, internal/ws, WebSocketChannels, wsmocks)) 42 | $(eval $(call makemock, internal/ws, WebSocketServer, wsmocks)) 43 | $(eval $(call makemock, internal/events, Stream, eventsmocks)) 44 | $(eval $(call makemock, internal/apiclient, FFTMClient, apiclientmocks)) 45 | 46 | go-mod-tidy: .ALWAYS 47 | $(VGO) mod tidy 48 | build: test 49 | .ALWAYS: ; 50 | clean: 51 | $(VGO) clean 52 | deps: 53 | $(VGO) get ./internal/... ./pkg/... 54 | $(VGO) get -t ./internal/... ./pkg/... 55 | reference: 56 | $(VGO) test ./pkg/fftm -timeout=10s -tags docs 57 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Hyperledger Security Policy 2 | 3 | ## Reporting a Security Bug 4 | 5 | If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to 6 | hear from you. We will take all security bugs seriously and if confirmed upon investigation we will 7 | patch it within a reasonable amount of time and release a public security bulletin discussing the 8 | impact and credit the discoverer. 9 | 10 | There are two ways to report a security bug. The easiest is to email a description of the flaw and 11 | any related information (e.g. reproduction steps, version) to 12 | [security at hyperledger dot org](mailto:security@hyperledger.org). 13 | 14 | The other way is to file a confidential security bug in our 15 | [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to 16 | “Security issue”. 17 | 18 | The process by which the Hyperledger Security Team handles security bugs is documented further in 19 | our [Defect Response page](https://wiki.hyperledger.org/display/SEC/Defect+Response) on our 20 | [wiki](https://wiki.hyperledger.org). -------------------------------------------------------------------------------- /cmd/client_eventstreams.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | var eventStreamID string 25 | 26 | func clientEventStreamsCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 27 | clientEventStreamsCmd := &cobra.Command{ 28 | Use: "eventstreams ", 29 | Short: "Make API requests to an blockchain connector instance", 30 | } 31 | clientEventStreamsCmd.AddCommand(clientEventStreamsListCommand(clientFactory)) 32 | clientEventStreamsCmd.AddCommand(clientEventStreamsDeleteCommand(clientFactory)) 33 | return clientEventStreamsCmd 34 | } 35 | -------------------------------------------------------------------------------- /cmd/client_eventstreams_delete.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "strings" 23 | 24 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | func clientEventStreamsDeleteCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 29 | clientEventStreamsDeleteCmd := &cobra.Command{ 30 | Use: "delete", 31 | Short: "Delete event streams", 32 | Long: "", 33 | RunE: func(_ *cobra.Command, _ []string) error { 34 | client, err := clientFactory() 35 | if err != nil { 36 | return err 37 | } 38 | if eventStreamID == "" && nameRegex == "" { 39 | return fmt.Errorf("eventstream or name flag must be set") 40 | } 41 | if eventStreamID != "" && nameRegex != "" { 42 | return fmt.Errorf("eventstream and name flags cannot be combined") 43 | } 44 | if eventStreamID != "" { 45 | err := client.DeleteEventStream(context.Background(), eventStreamID) 46 | if err != nil { 47 | if !(strings.Contains(err.Error(), "FF21046") && ignoreNotFound) { 48 | return err 49 | } 50 | } 51 | } 52 | if nameRegex != "" { 53 | err := client.DeleteEventStreamsByName(context.Background(), nameRegex) 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | return nil 59 | }, 60 | } 61 | clientEventStreamsDeleteCmd.Flags().StringVarP(&eventStreamID, "eventstream", "", "", "The ID of the event stream") 62 | clientEventStreamsDeleteCmd.Flags().StringVarP(&nameRegex, "name", "", "", "A regular expression for matching the event stream name") 63 | return clientEventStreamsDeleteCmd 64 | } 65 | -------------------------------------------------------------------------------- /cmd/client_eventstreams_list.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | "encoding/json" 22 | "fmt" 23 | 24 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | func clientEventStreamsListCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 29 | clientEventStreamsListCmd := &cobra.Command{ 30 | Use: "list", 31 | Short: "List event streams", 32 | Long: "", 33 | RunE: func(_ *cobra.Command, _ []string) error { 34 | client, err := clientFactory() 35 | if err != nil { 36 | return err 37 | } 38 | eventStreams, err := client.GetEventStreams(context.Background()) 39 | if err != nil { 40 | return err 41 | } 42 | json, _ := json.MarshalIndent(eventStreams, "", " ") 43 | fmt.Println(string(json)) 44 | return nil 45 | }, 46 | } 47 | return clientEventStreamsListCmd 48 | } 49 | -------------------------------------------------------------------------------- /cmd/client_eventstreams_list_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 24 | "github.com/hyperledger/firefly-transaction-manager/mocks/apiclientmocks" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestEventStreamsList(t *testing.T) { 31 | mc := apiclientmocks.NewFFTMClient(t) 32 | cmd := buildClientCommand(func() (apiclient.FFTMClient, error) { return mc, nil }) 33 | cmd.SetArgs([]string{"eventstreams", "list"}) 34 | mc.On("GetEventStreams", mock.Anything).Return([]apitypes.EventStream{}, nil) 35 | err := cmd.Execute() 36 | assert.NoError(t, err) 37 | mc.AssertExpectations(t) 38 | } 39 | 40 | func TestEventStreamsListError(t *testing.T) { 41 | mc := apiclientmocks.NewFFTMClient(t) 42 | cmd := buildClientCommand(func() (apiclient.FFTMClient, error) { return mc, nil }) 43 | cmd.SetArgs([]string{"eventstreams", "list"}) 44 | mc.On("GetEventStreams", mock.Anything).Return(nil, fmt.Errorf("pop")) 45 | err := cmd.Execute() 46 | assert.Regexp(t, "pop", err) 47 | mc.AssertExpectations(t) 48 | } 49 | 50 | func TestEventStreamsListBadClientConfig(t *testing.T) { 51 | mc := apiclientmocks.NewFFTMClient(t) 52 | cmd := buildClientCommand(func() (apiclient.FFTMClient, error) { return mc, fmt.Errorf("pop") }) 53 | cmd.SetArgs([]string{"eventstreams", "list"}) 54 | err := cmd.Execute() 55 | assert.Regexp(t, "pop", err) 56 | mc.AssertExpectations(t) 57 | } 58 | -------------------------------------------------------------------------------- /cmd/client_listeners.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | var listenerID string 25 | 26 | func clientListenersCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 27 | clientListenersCmd := &cobra.Command{ 28 | Use: "listeners ", 29 | Short: "Make API requests to an blockchain connector instance", 30 | } 31 | clientListenersCmd.PersistentFlags().StringVarP(&eventStreamID, "eventstream", "", "", "The event stream ID") 32 | clientListenersCmd.AddCommand(clientListenersListCommand(clientFactory)) 33 | clientListenersCmd.AddCommand(clientListenersDeleteCommand(clientFactory)) 34 | return clientListenersCmd 35 | } 36 | -------------------------------------------------------------------------------- /cmd/client_listeners_delete.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "strings" 23 | 24 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | func clientListenersDeleteCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 29 | clientListenersDeleteCmd := &cobra.Command{ 30 | Use: "delete", 31 | Short: "Delete event streams", 32 | Long: "", 33 | RunE: func(_ *cobra.Command, _ []string) error { 34 | client, err := clientFactory() 35 | if err != nil { 36 | return err 37 | } 38 | if eventStreamID == "" { 39 | return fmt.Errorf("eventstream flag not set") 40 | } 41 | if listenerID == "" && nameRegex == "" { 42 | return fmt.Errorf("listener or name flag must be set") 43 | } 44 | if listenerID != "" && nameRegex != "" { 45 | return fmt.Errorf("listener and name flags cannot be combined") 46 | } 47 | if listenerID != "" { 48 | err := client.DeleteListener(context.Background(), eventStreamID, listenerID) 49 | if err != nil { 50 | if !(strings.Contains(err.Error(), "FF21046") && ignoreNotFound) { 51 | return err 52 | } 53 | } 54 | } 55 | if nameRegex != "" { 56 | err := client.DeleteListenersByName(context.Background(), eventStreamID, nameRegex) 57 | if err != nil { 58 | return err 59 | } 60 | } 61 | return nil 62 | }, 63 | } 64 | clientListenersDeleteCmd.Flags().StringVarP(&listenerID, "listener", "", "", "The ID of the listener") 65 | clientListenersDeleteCmd.Flags().StringVarP(&nameRegex, "name", "", "", "A regular expression for matching the listener name") 66 | return clientListenersDeleteCmd 67 | } 68 | -------------------------------------------------------------------------------- /cmd/client_listeners_list.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | "encoding/json" 22 | "fmt" 23 | 24 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | func clientListenersListCommand(clientFactory func() (apiclient.FFTMClient, error)) *cobra.Command { 29 | clientListenersListCmd := &cobra.Command{ 30 | Use: "list", 31 | Short: "List listeners", 32 | Long: "", 33 | RunE: func(_ *cobra.Command, _ []string) error { 34 | client, err := clientFactory() 35 | if err != nil { 36 | return err 37 | } 38 | if eventStreamID == "" { 39 | return fmt.Errorf("eventstream flag not set") 40 | } 41 | listeners, err := client.GetListeners(context.Background(), eventStreamID) 42 | if err != nil { 43 | return err 44 | } 45 | json, _ := json.MarshalIndent(listeners, "", " ") 46 | fmt.Println(string(json)) 47 | return nil 48 | }, 49 | } 50 | return clientListenersListCmd 51 | } 52 | -------------------------------------------------------------------------------- /cmd/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/config" 23 | "github.com/hyperledger/firefly-common/pkg/fftls" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/apiclient" 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestClientCommand(t *testing.T) { 29 | cmd := ClientCommand() 30 | err := cmd.Execute() 31 | assert.NoError(t, err) 32 | } 33 | 34 | func TestCreateDefaultClient(t *testing.T) { 35 | client, err := createClient() 36 | assert.NotNil(t, client) 37 | assert.NoError(t, err) 38 | } 39 | 40 | func TestCreateClientTLSFail(t *testing.T) { 41 | cfg := config.RootSection("fftm_client") 42 | apiclient.InitConfig(cfg) 43 | tlsConf := cfg.SubSection("tls") 44 | tlsConf.Set(fftls.HTTPConfTLSEnabled, true) 45 | tlsConf.Set(fftls.HTTPConfTLSCAFile, "!!!badness") 46 | _, err := createClient() 47 | assert.Regexp(t, "FF00153", err) 48 | } 49 | -------------------------------------------------------------------------------- /cmd/migrate.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence/dbmigration" 23 | "github.com/spf13/cobra" 24 | ) 25 | 26 | func MigrateCommand(initConfig func() error) *cobra.Command { 27 | return buildMigrateCommand(initConfig) 28 | } 29 | 30 | func buildMigrateCommand(initConfig func() error) *cobra.Command { 31 | migrateCmd := &cobra.Command{ 32 | Use: "migrate ", 33 | Short: "Migration tools", 34 | } 35 | migrateCmd.AddCommand(buildLeveldb2postgresCommand(initConfig)) 36 | 37 | return migrateCmd 38 | } 39 | 40 | func buildLeveldb2postgresCommand(initConfig func() error) *cobra.Command { 41 | leveldb2postgresEventStreamsCmd := &cobra.Command{ 42 | Use: "leveldb2postgres", 43 | Short: "Migrate from LevelDB to PostgreSQL persistence", 44 | RunE: func(_ *cobra.Command, _ []string) error { 45 | if err := initConfig(); err != nil { 46 | return err 47 | } 48 | return dbmigration.MigrateLevelDBToPostgres(context.Background()) 49 | }, 50 | } 51 | return leveldb2postgresEventStreamsCmd 52 | } 53 | -------------------------------------------------------------------------------- /cmd/migrate_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmconfig" 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | func TestMigrateCommandFailInit(t *testing.T) { 28 | cmd := MigrateCommand(func() error { 29 | return fmt.Errorf("pop") 30 | }) 31 | cmd.SetArgs([]string{"leveldb2postgres"}) 32 | err := cmd.Execute() 33 | assert.Regexp(t, "pop", err) 34 | } 35 | 36 | func TestMigrateCommandFailRun(t *testing.T) { 37 | cmd := MigrateCommand(func() error { 38 | tmconfig.Reset() 39 | return nil 40 | }) 41 | cmd.SetArgs([]string{"leveldb2postgres"}) 42 | err := cmd.Execute() 43 | assert.Regexp(t, "FF21050", err) 44 | } 45 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | threshold: 0.1% 6 | patch: 7 | default: 8 | threshold: 0.1% 9 | ignore: 10 | - "mocks/**/*.go" 11 | -------------------------------------------------------------------------------- /db/migrations/postgres/000001_create_transactions_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX transactions_id; 3 | DROP INDEX transactions_nonce; 4 | DROP TABLE transactions; 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /db/migrations/postgres/000001_create_transactions_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE transactions ( 3 | seq SERIAL PRIMARY KEY, 4 | id TEXT NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | status VARCHAR(65) NOT NULL, 8 | delete BIGINT, 9 | tx_from TEXT, 10 | tx_to TEXT, 11 | tx_nonce VARCHAR(65), 12 | tx_gas VARCHAR(65), 13 | tx_value VARCHAR(65), 14 | tx_gasprice TEXT, 15 | tx_data TEXT NOT NULL, 16 | tx_hash TEXT NOT NULL, 17 | policy_info TEXT, 18 | first_submit BIGINT, 19 | last_submit BIGINT, 20 | error_message TEXT NOT NULL 21 | ); 22 | CREATE UNIQUE INDEX transactions_id ON transactions(id); 23 | CREATE UNIQUE INDEX transactions_nonce ON transactions(tx_from, tx_nonce); 24 | CREATE INDEX transactions_hash ON transactions(tx_hash); 25 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000002_create_receipts_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX receipts_id; 3 | DROP TABLE receipts; 4 | COMMIT; 5 | -------------------------------------------------------------------------------- /db/migrations/postgres/000002_create_receipts_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE receipts ( 3 | seq SERIAL PRIMARY KEY, 4 | id TEXT NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | block_number VARCHAR(65), 8 | tx_index VARCHAR(65), 9 | block_hash TEXT NOT NULL, 10 | success BOOLEAN NOT NULL, 11 | protocol_id TEXT NOT NULL, 12 | extra_info TEXT, 13 | contract_loc TEXT 14 | ); 15 | CREATE UNIQUE INDEX receipts_id ON receipts(id); 16 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000003_create_confirmations_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX confirmations_id; 3 | DROP INDEX confirmations_txid; 4 | DROP TABLE confirmations; 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /db/migrations/postgres/000003_create_confirmations_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE confirmations ( 3 | seq SERIAL PRIMARY KEY, 4 | id UUID NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | tx_id TEXT NOT NULL, 8 | block_number BIGINT NOT NULL, 9 | block_hash TEXT NOT NULL, 10 | parent_hash TEXT NOT NULL 11 | ); 12 | CREATE UNIQUE INDEX confirmations_id ON confirmations(id); 13 | CREATE INDEX confirmations_txid ON confirmations(tx_id); 14 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000004_create_txhistory_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX IF EXISTS txhistory_id; 3 | DROP INDEX IF EXISTS txhistory_txid; 4 | DROP TABLE txhistory; 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /db/migrations/postgres/000004_create_txhistory_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE txhistory ( 3 | seq SERIAL PRIMARY KEY, 4 | id UUID NOT NULL, 5 | time BIGINT NOT NULL, 6 | last_occurrence BIGINT NOT NULL, 7 | tx_id TEXT NOT NULL, 8 | status TEXT NOT NULL, 9 | action TEXT NOT NULL, 10 | count INT NOT NULL, 11 | error TEXT, 12 | error_time BIGINT, 13 | info TEXT 14 | ); 15 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000005_create_checkpoints_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX checkpoints_id; 3 | DROP TABLE checkpoints; 4 | COMMIT; 5 | -------------------------------------------------------------------------------- /db/migrations/postgres/000005_create_checkpoints_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE checkpoints ( 3 | seq SERIAL PRIMARY KEY, 4 | id UUID NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | listeners JSON 8 | ); 9 | CREATE UNIQUE INDEX checkpoints_id ON checkpoints(id); 10 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000006_create_eventstreams_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX eventstreams_id; 3 | DROP INDEX eventstreams_name; 4 | DROP TABLE eventstreams; 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /db/migrations/postgres/000006_create_eventstreams_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE eventstreams ( 3 | seq SERIAL PRIMARY KEY, 4 | id UUID NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | name TEXT, 8 | suspended BOOLEAN, 9 | stream_type TEXT, 10 | error_handling TEXT, 11 | batch_size BIGINT, 12 | batch_timeout TEXT NOT NULL, 13 | retry_timeout TEXT NOT NULL, 14 | blocked_retry_timeout TEXT NOT NULL, 15 | webhook_config TEXT, 16 | websocket_config TEXT 17 | ); 18 | CREATE UNIQUE INDEX eventstreams_id ON eventstreams(id); 19 | CREATE UNIQUE INDEX eventstreams_name ON eventstreams(name); 20 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000007_create_listeners_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX listeners_id; 3 | DROP INDEX listeners_name; 4 | DROP INDEX listeners_stream; 5 | DROP TABLE listeners; 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /db/migrations/postgres/000007_create_listeners_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE TABLE listeners ( 3 | seq SERIAL PRIMARY KEY, 4 | id UUID NOT NULL, 5 | created BIGINT NOT NULL, 6 | updated BIGINT NOT NULL, 7 | name TEXT, 8 | stream_id UUID NOT NULL, 9 | filters TEXT, 10 | options TEXT, 11 | signature TEXT, 12 | from_block TEXT 13 | ); 14 | CREATE UNIQUE INDEX listeners_id ON listeners(id); 15 | CREATE UNIQUE INDEX listeners_name ON listeners(name); -- global uniqueness on names 16 | CREATE INDEX listeners_stream ON listeners(stream_id); 17 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000008_create_txhistory_idx.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX IF EXISTS txhistory_id; 3 | DROP INDEX IF EXISTS txhistory_txid; 4 | COMMIT; 5 | -------------------------------------------------------------------------------- /db/migrations/postgres/000008_create_txhistory_idx.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | -- Allow nil data on transactions, for example for a simple transfer operation 3 | ALTER TABLE transactions ALTER COLUMN tx_data DROP NOT NULL; 4 | 5 | -- Correct TXHistory indexes if created by an invalid 000004 migration (no longer in codebase). 6 | DROP INDEX IF EXISTS txhistory_id; 7 | DROP INDEX IF EXISTS txhistory_txid; 8 | 9 | -- Create corrected TXHistory indexes 10 | CREATE UNIQUE INDEX txhistory_id ON txhistory(id); 11 | CREATE INDEX txhistory_txid ON txhistory(tx_id); 12 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000009_add_transactions_status_index.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | DROP INDEX IF EXISTS transactions_status; 3 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000009_add_transactions_status_index.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | CREATE INDEX transactions_status ON transactions(status); 3 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000010_add_listeners_type.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE listeners DROP COLUMN "type"; 4 | 5 | COMMIT; -------------------------------------------------------------------------------- /db/migrations/postgres/000010_add_listeners_type.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE listeners ADD COLUMN "type" VARCHAR(64); 4 | UPDATE listeners SET "type" = 'events'; 5 | ALTER TABLE listeners ALTER COLUMN "type" SET NOT NULL; 6 | 7 | COMMIT; -------------------------------------------------------------------------------- /images/fftm_event_streams_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger/firefly-transaction-manager/7a882ddaeaf2e7b9b2203a053402576e436debd9/images/fftm_event_streams_architecture.jpg -------------------------------------------------------------------------------- /images/firefly_connector_framework_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger/firefly-transaction-manager/7a882ddaeaf2e7b9b2203a053402576e436debd9/images/firefly_connector_framework_architecture.jpg -------------------------------------------------------------------------------- /internal/apiclient/fftm_client.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apiclient 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-common/pkg/config" 24 | "github.com/hyperledger/firefly-common/pkg/ffresty" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | type FFTMClient interface { 29 | GetEventStreams(ctx context.Context) ([]apitypes.EventStream, error) 30 | GetListeners(ctx context.Context, eventStreamID string) ([]apitypes.Listener, error) 31 | DeleteEventStream(ctx context.Context, eventStreamID string) error 32 | DeleteEventStreamsByName(ctx context.Context, nameRegex string) error 33 | DeleteListener(ctx context.Context, eventStreamID, listenerID string) error 34 | DeleteListenersByName(ctx context.Context, eventStreamID, nameRegex string) error 35 | } 36 | 37 | type fftmClient struct { 38 | client *resty.Client 39 | } 40 | 41 | func InitConfig(conf config.Section) { 42 | ffresty.InitConfig(conf) 43 | } 44 | 45 | func NewFFTMClient(ctx context.Context, staticConfig config.Section) (FFTMClient, error) { 46 | client, err := ffresty.New(ctx, staticConfig) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &fftmClient{ 51 | client: client, 52 | }, nil 53 | } 54 | -------------------------------------------------------------------------------- /internal/apiclient/fftm_client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apiclient 18 | 19 | import ( 20 | "context" 21 | "net/http" 22 | "net/http/httptest" 23 | "testing" 24 | 25 | "github.com/hyperledger/firefly-common/pkg/config" 26 | "github.com/hyperledger/firefly-common/pkg/fftls" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func newTestClientServer(t *testing.T, handler func(w http.ResponseWriter, r *http.Request)) (FFTMClient, *httptest.Server) { 31 | server := httptest.NewServer(http.HandlerFunc(handler)) 32 | config := config.RootSection("fftm_client") 33 | InitConfig(config) 34 | config.Set("url", server.URL) 35 | client, err := NewFFTMClient(context.Background(), config) 36 | assert.NoError(t, err) 37 | return client, server 38 | } 39 | 40 | func TestBadTLSCreds(t *testing.T) { 41 | config := config.RootSection("fftm_client") 42 | InitConfig(config) 43 | tlsConf := config.SubSection("tls") 44 | tlsConf.Set(fftls.HTTPConfTLSEnabled, true) 45 | tlsConf.Set(fftls.HTTPConfTLSCAFile, "!!!badness") 46 | _, err := NewFFTMClient(context.Background(), config) 47 | assert.Regexp(t, "FF00153", err) 48 | } 49 | -------------------------------------------------------------------------------- /internal/blocklistener/blocklistener_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package blocklistener 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | type testBlockConsumer struct { 28 | c chan *ffcapi.BlockHashEvent 29 | } 30 | 31 | func (tbc *testBlockConsumer) NewBlockHashes() chan<- *ffcapi.BlockHashEvent { 32 | return tbc.c 33 | } 34 | 35 | func TestBlockListenerDoesNotBlock(t *testing.T) { 36 | 37 | unBuffered := make(chan *ffcapi.BlockHashEvent, 1) 38 | ctx, cancelCtx := context.WithCancel(context.Background()) 39 | 40 | buffered, blockListenerDone := BufferChannel(ctx, &testBlockConsumer{c: unBuffered}) 41 | 42 | for i := 0; i < 100; i++ { 43 | buffered <- &ffcapi.BlockHashEvent{} 44 | } 45 | 46 | // Get the one that was stuck in the pipe 47 | bhe := <-unBuffered 48 | assert.False(t, bhe.GapPotential) 49 | 50 | // We should get the unblocking one too, with GapPotential set 51 | bhe = <-unBuffered 52 | assert.True(t, bhe.GapPotential) 53 | 54 | // Block it again 55 | for i := 0; i < 100; i++ { 56 | buffered <- &ffcapi.BlockHashEvent{} 57 | } 58 | 59 | // And check we can exit while blocked 60 | cancelCtx() 61 | <-blockListenerDone 62 | 63 | } 64 | 65 | func TestExitOnContextCancel(t *testing.T) { 66 | 67 | unBuffered := make(chan *ffcapi.BlockHashEvent) 68 | ctx, cancelCtx := context.WithCancel(context.Background()) 69 | cancelCtx() 70 | 71 | _, blockListenerDone := BufferChannel(ctx, &testBlockConsumer{c: unBuffered}) 72 | <-blockListenerDone 73 | 74 | } 75 | -------------------------------------------------------------------------------- /internal/metrics/event_metrics_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package metrics 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | ) 23 | 24 | func TestTransactionHandlerEventMetricsEmitters(t *testing.T) { 25 | ctx := context.Background() 26 | mm, cancel := newTestMetricsManager(t) 27 | defer cancel() 28 | mm.metricsEnabled = true 29 | 30 | mm.RecordBlockHashProcessMetrics(ctx, 1) 31 | mm.RecordBlockHashBatchSizeMetric(ctx, 1) 32 | mm.RecordBlockHashQueueingMetrics(ctx, 1) 33 | mm.RecordConfirmationMetrics(ctx, 1) 34 | mm.RecordNotificationProcessMetrics(ctx, "test", 1) 35 | mm.RecordNotificationQueueingMetrics(ctx, "test", 1) 36 | mm.RecordReceiptCheckMetrics(ctx, "test", 1) 37 | mm.RecordReceiptMetrics(ctx, 1) 38 | } 39 | -------------------------------------------------------------------------------- /internal/persistence/dbmigration/leveldb2postgres.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package dbmigration 18 | 19 | import ( 20 | "context" 21 | "time" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/i18n" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence/leveldb" 25 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence/postgres" 26 | "github.com/hyperledger/firefly-transaction-manager/internal/tmconfig" 27 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 28 | ) 29 | 30 | func MigrateLevelDBToPostgres(ctx context.Context) (err error) { 31 | m := &dbMigration{} 32 | 33 | tmconfig.PostgresSection.Set(postgres.ConfigTXWriterBatchTimeout, 0) // single go-routine, no point in batching 34 | tmconfig.PostgresSection.Set(postgres.ConfigTXWriterCount, 1) 35 | nonceStateTimeout := 0 * time.Second 36 | if m.source, err = leveldb.NewLevelDBPersistence(ctx, nonceStateTimeout); err != nil { 37 | return i18n.NewError(ctx, tmmsgs.MsgPersistenceInitFail, "leveldb", err) 38 | } 39 | defer m.source.Close(ctx) 40 | if m.target, err = postgres.NewPostgresPersistence(ctx, tmconfig.PostgresSection, nonceStateTimeout, postgres.ForMigration); err != nil { 41 | return i18n.NewError(ctx, tmmsgs.MsgPersistenceInitFail, "postgres", err) 42 | } 43 | defer m.target.Close(ctx) 44 | 45 | return m.run(ctx) 46 | } 47 | -------------------------------------------------------------------------------- /internal/persistence/persistence_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package persistence 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/fftypes" 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestJSONOrStringNull(t *testing.T) { 27 | assert.Nil(t, JSONOrString(nil)) 28 | } 29 | 30 | func TestJSONOrStringGoodJSON(t *testing.T) { 31 | assert.Equal(t, `{ "good": "json"}`, (string)(*JSONOrString(fftypes.JSONAnyPtr(`{ "good": "json"}`)))) 32 | } 33 | 34 | func TestJSONOrStringBadJSON(t *testing.T) { 35 | assert.Equal(t, "\"\\\"bad\\\": \\\"json\\\"}\"", (string)(*JSONOrString(fftypes.JSONAnyPtr(`"bad": "json"}`)))) 36 | } 37 | -------------------------------------------------------------------------------- /internal/persistence/postgres/checkpoints_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package postgres 18 | 19 | import ( 20 | "encoding/json" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/fftypes" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestCheckpointsPSQ(t *testing.T) { 29 | 30 | ctx, p, _, done := initTestPSQL(t) 31 | defer done() 32 | 33 | cp1 := &apitypes.EventStreamCheckpoint{ 34 | StreamID: fftypes.NewUUID(), 35 | Listeners: apitypes.CheckpointListeners{ 36 | *fftypes.NewUUID(): json.RawMessage(`{"some":"data"}`), 37 | }, 38 | } 39 | err := p.WriteCheckpoint(ctx, cp1) 40 | assert.NoError(t, err) 41 | 42 | cp2, err := p.GetCheckpoint(ctx, cp1.StreamID) 43 | assert.NoError(t, err) 44 | assert.NotNil(t, cp2.Time) 45 | assert.NotNil(t, cp2.FirstCheckpoint) 46 | cp1.Time = cp2.Time 47 | cp1.FirstCheckpoint = cp2.FirstCheckpoint 48 | assert.Equal(t, cp1, cp2) 49 | 50 | err = p.DeleteCheckpoint(ctx, cp1.StreamID) 51 | assert.NoError(t, err) 52 | 53 | cp3, err := p.GetCheckpoint(ctx, cp1.StreamID) 54 | assert.Nil(t, cp3) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /internal/tmconfig/tmconfig_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package tmconfig 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/config" 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | const configDir = "../../test/data/config" 27 | 28 | func TestInitConfigOK(t *testing.T) { 29 | Reset() 30 | 31 | assert.Equal(t, 50, config.GetInt(EventStreamsDefaultsBatchSize)) 32 | } 33 | -------------------------------------------------------------------------------- /mocks/txhandlermocks/managed_tx_event_handler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.43.1. DO NOT EDIT. 2 | 3 | package txhandlermocks 4 | 5 | import ( 6 | context "context" 7 | 8 | apitypes "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 9 | 10 | mock "github.com/stretchr/testify/mock" 11 | ) 12 | 13 | // ManagedTxEventHandler is an autogenerated mock type for the ManagedTxEventHandler type 14 | type ManagedTxEventHandler struct { 15 | mock.Mock 16 | } 17 | 18 | // HandleEvent provides a mock function with given fields: ctx, e 19 | func (_m *ManagedTxEventHandler) HandleEvent(ctx context.Context, e apitypes.ManagedTransactionEvent) error { 20 | ret := _m.Called(ctx, e) 21 | 22 | if len(ret) == 0 { 23 | panic("no return value specified for HandleEvent") 24 | } 25 | 26 | var r0 error 27 | if rf, ok := ret.Get(0).(func(context.Context, apitypes.ManagedTransactionEvent) error); ok { 28 | r0 = rf(ctx, e) 29 | } else { 30 | r0 = ret.Error(0) 31 | } 32 | 33 | return r0 34 | } 35 | 36 | // NewManagedTxEventHandler creates a new instance of ManagedTxEventHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 37 | // The first argument is typically a *testing.T value. 38 | func NewManagedTxEventHandler(t interface { 39 | mock.TestingT 40 | Cleanup(func()) 41 | }) *ManagedTxEventHandler { 42 | mock := &ManagedTxEventHandler{} 43 | mock.Mock.Test(t) 44 | 45 | t.Cleanup(func() { mock.AssertExpectations(t) }) 46 | 47 | return mock 48 | } 49 | -------------------------------------------------------------------------------- /mocks/wsmocks/web_socket_channels.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.43.1. DO NOT EDIT. 2 | 3 | package wsmocks 4 | 5 | import ( 6 | ws "github.com/hyperledger/firefly-transaction-manager/internal/ws" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // WebSocketChannels is an autogenerated mock type for the WebSocketChannels type 11 | type WebSocketChannels struct { 12 | mock.Mock 13 | } 14 | 15 | // GetChannels provides a mock function with given fields: topic 16 | func (_m *WebSocketChannels) GetChannels(topic string) (chan<- interface{}, chan<- interface{}, <-chan *ws.WebSocketCommandMessageOrError) { 17 | ret := _m.Called(topic) 18 | 19 | if len(ret) == 0 { 20 | panic("no return value specified for GetChannels") 21 | } 22 | 23 | var r0 chan<- interface{} 24 | var r1 chan<- interface{} 25 | var r2 <-chan *ws.WebSocketCommandMessageOrError 26 | if rf, ok := ret.Get(0).(func(string) (chan<- interface{}, chan<- interface{}, <-chan *ws.WebSocketCommandMessageOrError)); ok { 27 | return rf(topic) 28 | } 29 | if rf, ok := ret.Get(0).(func(string) chan<- interface{}); ok { 30 | r0 = rf(topic) 31 | } else { 32 | if ret.Get(0) != nil { 33 | r0 = ret.Get(0).(chan<- interface{}) 34 | } 35 | } 36 | 37 | if rf, ok := ret.Get(1).(func(string) chan<- interface{}); ok { 38 | r1 = rf(topic) 39 | } else { 40 | if ret.Get(1) != nil { 41 | r1 = ret.Get(1).(chan<- interface{}) 42 | } 43 | } 44 | 45 | if rf, ok := ret.Get(2).(func(string) <-chan *ws.WebSocketCommandMessageOrError); ok { 46 | r2 = rf(topic) 47 | } else { 48 | if ret.Get(2) != nil { 49 | r2 = ret.Get(2).(<-chan *ws.WebSocketCommandMessageOrError) 50 | } 51 | } 52 | 53 | return r0, r1, r2 54 | } 55 | 56 | // SendReply provides a mock function with given fields: message 57 | func (_m *WebSocketChannels) SendReply(message interface{}) { 58 | _m.Called(message) 59 | } 60 | 61 | // NewWebSocketChannels creates a new instance of WebSocketChannels. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 62 | // The first argument is typically a *testing.T value. 63 | func NewWebSocketChannels(t interface { 64 | mock.TestingT 65 | Cleanup(func()) 66 | }) *WebSocketChannels { 67 | mock := &WebSocketChannels{} 68 | mock.Mock.Test(t) 69 | 70 | t.Cleanup(func() { mock.AssertExpectations(t) }) 71 | 72 | return mock 73 | } 74 | -------------------------------------------------------------------------------- /mocks/wsmocks/web_socket_server.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.43.1. DO NOT EDIT. 2 | 3 | package wsmocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | ws "github.com/hyperledger/firefly-transaction-manager/internal/ws" 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // WebSocketServer is an autogenerated mock type for the WebSocketServer type 13 | type WebSocketServer struct { 14 | mock.Mock 15 | } 16 | 17 | // Close provides a mock function with given fields: 18 | func (_m *WebSocketServer) Close() { 19 | _m.Called() 20 | } 21 | 22 | // GetChannels provides a mock function with given fields: topic 23 | func (_m *WebSocketServer) GetChannels(topic string) (chan<- interface{}, chan<- interface{}, <-chan *ws.WebSocketCommandMessageOrError) { 24 | ret := _m.Called(topic) 25 | 26 | if len(ret) == 0 { 27 | panic("no return value specified for GetChannels") 28 | } 29 | 30 | var r0 chan<- interface{} 31 | var r1 chan<- interface{} 32 | var r2 <-chan *ws.WebSocketCommandMessageOrError 33 | if rf, ok := ret.Get(0).(func(string) (chan<- interface{}, chan<- interface{}, <-chan *ws.WebSocketCommandMessageOrError)); ok { 34 | return rf(topic) 35 | } 36 | if rf, ok := ret.Get(0).(func(string) chan<- interface{}); ok { 37 | r0 = rf(topic) 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).(chan<- interface{}) 41 | } 42 | } 43 | 44 | if rf, ok := ret.Get(1).(func(string) chan<- interface{}); ok { 45 | r1 = rf(topic) 46 | } else { 47 | if ret.Get(1) != nil { 48 | r1 = ret.Get(1).(chan<- interface{}) 49 | } 50 | } 51 | 52 | if rf, ok := ret.Get(2).(func(string) <-chan *ws.WebSocketCommandMessageOrError); ok { 53 | r2 = rf(topic) 54 | } else { 55 | if ret.Get(2) != nil { 56 | r2 = ret.Get(2).(<-chan *ws.WebSocketCommandMessageOrError) 57 | } 58 | } 59 | 60 | return r0, r1, r2 61 | } 62 | 63 | // Handler provides a mock function with given fields: w, r 64 | func (_m *WebSocketServer) Handler(w http.ResponseWriter, r *http.Request) { 65 | _m.Called(w, r) 66 | } 67 | 68 | // SendReply provides a mock function with given fields: message 69 | func (_m *WebSocketServer) SendReply(message interface{}) { 70 | _m.Called(message) 71 | } 72 | 73 | // NewWebSocketServer creates a new instance of WebSocketServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 74 | // The first argument is typically a *testing.T value. 75 | func NewWebSocketServer(t interface { 76 | mock.TestingT 77 | Cleanup(func()) 78 | }) *WebSocketServer { 79 | mock := &WebSocketServer{} 80 | mock.Mock.Test(t) 81 | 82 | t.Cleanup(func() { mock.AssertExpectations(t) }) 83 | 84 | return mock 85 | } 86 | -------------------------------------------------------------------------------- /pkg/apitypes/base_request.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import "encoding/json" 20 | 21 | // BaseRequest is the common headers to all requests, and captures the full input payload for later decoding to a specific type 22 | type BaseRequest struct { 23 | headerDecoder 24 | fullPayload []byte 25 | } 26 | 27 | type headerDecoder struct { 28 | Headers RequestHeaders `json:"headers"` 29 | } 30 | 31 | func (br *BaseRequest) UnmarshalJSON(data []byte) error { 32 | br.fullPayload = data 33 | return json.Unmarshal(data, &br.headerDecoder) 34 | } 35 | 36 | func (br *BaseRequest) UnmarshalTo(o interface{}) error { 37 | return json.Unmarshal(br.fullPayload, &o) 38 | } 39 | 40 | type RequestHeaders struct { 41 | ID string `ffstruct:"fftmrequest" json:"id"` 42 | Type RequestType `json:"type"` 43 | } 44 | 45 | type RequestType string 46 | 47 | const ( 48 | RequestTypeSendTransaction RequestType = "SendTransaction" 49 | RequestTypeQuery RequestType = "Query" 50 | RequestTypeDeploy RequestType = "DeployContract" 51 | RequestTypeTransactionReceipt RequestType = "TransactionReceipt" 52 | ) 53 | -------------------------------------------------------------------------------- /pkg/apitypes/base_request_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "encoding/json" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/fftypes" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestBaseRequestDecoding(t *testing.T) { 29 | 30 | sampleRequest := &TransactionRequest{ 31 | Headers: RequestHeaders{ 32 | Type: RequestTypeSendTransaction, 33 | ID: fftypes.NewUUID().String(), 34 | }, 35 | TransactionInput: ffcapi.TransactionInput{ 36 | TransactionHeaders: ffcapi.TransactionHeaders{ 37 | From: "0x12345", 38 | }, 39 | }, 40 | } 41 | 42 | j, err := json.Marshal(&sampleRequest) 43 | assert.NoError(t, err) 44 | 45 | var br BaseRequest 46 | err = json.Unmarshal(j, &br) 47 | assert.NoError(t, err) 48 | 49 | assert.Equal(t, RequestTypeSendTransaction, br.Headers.Type) 50 | assert.Equal(t, sampleRequest.Headers.ID, br.Headers.ID) 51 | 52 | var receivedRequest TransactionRequest 53 | err = br.UnmarshalTo(&receivedRequest) 54 | assert.NoError(t, err) 55 | 56 | assert.Equal(t, "0x12345", receivedRequest.TransactionInput.From) 57 | 58 | } 59 | -------------------------------------------------------------------------------- /pkg/apitypes/query_request.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 21 | ) 22 | 23 | // QueryRequest is the request payload to send to perform a synchronous query against the blockchain state 24 | type QueryRequest struct { 25 | Headers RequestHeaders `json:"headers"` 26 | ffcapi.TransactionInput 27 | BlockNumber *string `json:"blockNumber,omitempty"` 28 | } 29 | 30 | // QueryResponse is the response payload for a query 31 | type QueryResponse ffcapi.QueryInvokeResponse 32 | -------------------------------------------------------------------------------- /pkg/apitypes/tx_request.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 21 | ) 22 | 23 | // TransactionRequest is the payload sent to initiate a new transaction 24 | type TransactionRequest struct { 25 | Headers RequestHeaders `json:"headers"` 26 | ffcapi.TransactionInput 27 | } 28 | 29 | // ContractDeployRequest is the payload sent to initiate a new transaction 30 | type ContractDeployRequest struct { 31 | Headers RequestHeaders `json:"headers"` 32 | ffcapi.ContractDeployPrepareRequest 33 | } 34 | -------------------------------------------------------------------------------- /pkg/apitypes/txreceipt_request.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 21 | ) 22 | 23 | // TransactionReceiptRequest is the request payload to query for a receipt 24 | type TransactionReceiptRequest struct { 25 | Headers RequestHeaders `json:"headers"` 26 | ffcapi.TransactionReceiptRequest 27 | } 28 | 29 | // TransactionReceiptResponse is the response payload for a query 30 | type TransactionReceiptResponse struct { 31 | ffcapi.TransactionReceiptResponseBase 32 | Events []*EventWithContext `json:"events,omitempty"` // this is the serialization format for events (historical complexity) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/apitypes/ulid.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "crypto/rand" 21 | "time" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/fftypes" 24 | "github.com/oklog/ulid/v2" 25 | ) 26 | 27 | var ulidReader = &ulid.LockedMonotonicReader{ 28 | MonotonicReader: &ulid.MonotonicEntropy{ 29 | Reader: rand.Reader, 30 | }, 31 | } 32 | 33 | // NewULID returns a Universally Unique Lexicographically Sortable Identifier (ULID). 34 | // For consistency we impersonate the formatting of a UUID, so they can be used 35 | // interchangeably. 36 | // This can be used in database tables to ensure monotonic increasing identifiers. 37 | func NewULID() *fftypes.UUID { 38 | u := ulid.MustNew(ulid.Timestamp(time.Now()), ulidReader) 39 | return (*fftypes.UUID)(&u) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/apitypes/ulid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package apitypes 18 | 19 | import ( 20 | "strings" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestULID(t *testing.T) { 27 | u1 := NewULID() 28 | u2 := NewULID() 29 | assert.Negative(t, strings.Compare(u1.String(), u2.String())) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/ffcapi/address_balance.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import "github.com/hyperledger/firefly-common/pkg/fftypes" 20 | 21 | type AddressBalanceRequest struct { 22 | Address string `json:"address"` 23 | BlockTag string `json:"blockTag"` 24 | } 25 | 26 | type AddressBalanceResponse struct { 27 | Balance *fftypes.FFBigInt `json:"balance"` 28 | } 29 | -------------------------------------------------------------------------------- /pkg/ffcapi/block_info_by_hash.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | type BlockInfoByHashRequest struct { 20 | BlockHash string `json:"blockHash"` 21 | } 22 | 23 | type BlockInfoByHashResponse struct { 24 | BlockInfo 25 | } 26 | -------------------------------------------------------------------------------- /pkg/ffcapi/block_info_by_number.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type BlockInfoByNumberRequest struct { 24 | BlockNumber *fftypes.FFBigInt `json:"blockNumber"` 25 | AllowCache bool `json:"allowCache"` 26 | ExpectedParentHash string `json:"expectedParentHash"` // If set then a mismatched parent hash should be considered a cache miss (if the connector does caching) 27 | } 28 | 29 | type BlockInfoByNumberResponse struct { 30 | BlockInfo 31 | } 32 | -------------------------------------------------------------------------------- /pkg/ffcapi/contract_deploy_prepare.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type ContractDeployPrepareRequest struct { 24 | TransactionHeaders 25 | Definition *fftypes.JSONAny `json:"definition"` // such as an ABI for EVM 26 | Contract *fftypes.JSONAny `json:"contract"` // such as the Bytecode for EVM 27 | Params []*fftypes.JSONAny `json:"params"` // such as the inputs to the constructor for EVM 28 | Errors []*fftypes.JSONAny `json:"errors"` // such as the errors spec for EVM 29 | } 30 | -------------------------------------------------------------------------------- /pkg/ffcapi/event_listener_add.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | const ( 24 | FromBlockEarliest = "earliest" 25 | FromBlockLatest = "latest" 26 | ) 27 | 28 | type EventListenerOptions struct { 29 | FromBlock string // The instruction for the first block to index from (when there is no previous checkpoint). Special "earliest" and "latest" strings should be supported as well as blockchain specific block ID (like a decimal number etc.) 30 | Filters []fftypes.JSONAny // The blockchain specific list of filters. The top-level array is an OR list. The semantics within each entry is defined by the blockchain 31 | Options *fftypes.JSONAny // Blockchain specific set of options, such as the first block to detect events from (can be null) 32 | } 33 | 34 | type EventListenerVerifyOptionsRequest struct { 35 | EventListenerOptions 36 | } 37 | 38 | type EventListenerVerifyOptionsResponse struct { 39 | ResolvedSignature string 40 | ResolvedOptions fftypes.JSONAny 41 | } 42 | 43 | type EventListenerAddRequest struct { 44 | EventListenerOptions 45 | ListenerID *fftypes.UUID // Unique UUID for the event listener, that should be included in each event 46 | StreamID *fftypes.UUID // The event stream (previously started) to which events should be delivered 47 | Name string // Descriptive name of the listener, provided by the user, or defaulted to the signature. Not guaranteed to be unique. Should be included in the event info 48 | Checkpoint EventListenerCheckpoint // The last persisted checkpoint for this event stream 49 | } 50 | 51 | type EventListenerAddResponse struct { 52 | } 53 | -------------------------------------------------------------------------------- /pkg/ffcapi/event_listener_hwm.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type EventListenerHWMRequest struct { 24 | StreamID *fftypes.UUID `json:"streamId"` 25 | ListenerID *fftypes.UUID `json:"listenerId"` 26 | } 27 | 28 | type EventListenerHWMResponse struct { 29 | Checkpoint EventListenerCheckpoint `json:"checkpoint"` 30 | Catchup bool `json:"catchup,omitempty"` // informational only - informs an operator that the stream is catching up 31 | } 32 | -------------------------------------------------------------------------------- /pkg/ffcapi/event_listener_remove.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type EventListenerRemoveRequest struct { 24 | StreamID *fftypes.UUID `json:"streamId"` 25 | ListenerID *fftypes.UUID `json:"listenerId"` 26 | } 27 | 28 | type EventListenerRemoveResponse struct { 29 | } 30 | -------------------------------------------------------------------------------- /pkg/ffcapi/event_stream_start.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/fftypes" 23 | ) 24 | 25 | type EventStreamStartRequest struct { 26 | ID *fftypes.UUID // UUID of the stream, which we be referenced in any future add/remove listener requests 27 | StreamContext context.Context // Context that will be cancelled when the event stream needs to stop - no further events will be consumed after this, so all pushes to the stream should select on the done channel too 28 | EventStream chan<- *ListenerEvent // The event stream to push events to as they are detected, and checkpoints regularly even if there are no events - remember to select on Done as well when pushing events 29 | BlockListener chan<- *BlockHashEvent // The connector should push new blocks to every stream, marking if it's possible blocks were missed (due to reconnect). The stream guarantees to always consume from this channel, until the stream context closes. 30 | InitialListeners []*EventListenerAddRequest // Initial list of event listeners to start with the stream - allows these to be started concurrently 31 | } 32 | 33 | type EventStreamStartResponse struct { 34 | } 35 | -------------------------------------------------------------------------------- /pkg/ffcapi/event_stream_stopped.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type EventStreamStoppedRequest struct { 24 | ID *fftypes.UUID // UUID of the stream, which we be referenced in any future add/remove listener requests 25 | } 26 | 27 | type EventStreamStoppedResponse struct { 28 | } 29 | -------------------------------------------------------------------------------- /pkg/ffcapi/gas_estimate.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import "github.com/hyperledger/firefly-common/pkg/fftypes" 20 | 21 | type GasEstimateRequest struct { 22 | TransactionInput 23 | } 24 | 25 | type GasEstimateResponse struct { 26 | GasEstimate *fftypes.FFBigInt `json:"gasEstimate"` 27 | } 28 | -------------------------------------------------------------------------------- /pkg/ffcapi/gas_price_estimate.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import "github.com/hyperledger/firefly-common/pkg/fftypes" 20 | 21 | type GasPriceEstimateRequest struct { 22 | } 23 | 24 | type GasPriceEstimateResponse struct { 25 | GasPrice *fftypes.JSONAny `json:"gasPrice"` 26 | } 27 | -------------------------------------------------------------------------------- /pkg/ffcapi/is_live.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | type LiveResponse struct { 20 | Up bool `json:"up"` 21 | } 22 | -------------------------------------------------------------------------------- /pkg/ffcapi/is_ready.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import "github.com/hyperledger/firefly-common/pkg/fftypes" 20 | 21 | type ReadyResponse struct { 22 | Ready bool `json:"ready"` 23 | DownstreamDetails *fftypes.JSONAny `json:"downstreamDetails"` // The data output from the method call - can be array or object structure 24 | } 25 | -------------------------------------------------------------------------------- /pkg/ffcapi/method_call.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | // QueryInvokeRequest requests execution of a smart contract method in order to either: 24 | // 1) Query state 25 | // 2) Attempt to extract the revert reason from an on-chain failure to execute a transaction 26 | // 27 | // See the list of standard error reasons that should be returned for situations that can be 28 | // detected by the back-end connector. 29 | type QueryInvokeRequest struct { 30 | TransactionInput 31 | BlockNumber *string `json:"blockNumber,omitempty"` 32 | } 33 | 34 | type QueryInvokeResponse struct { 35 | Outputs *fftypes.JSONAny `json:"outputs"` // The data output from the method call - can be array or object structure 36 | } 37 | -------------------------------------------------------------------------------- /pkg/ffcapi/new_block_listener.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/fftypes" 23 | ) 24 | 25 | type NewBlockListenerRequest struct { 26 | ID *fftypes.UUID // unique identifier for this listener 27 | ListenerContext context.Context // Context that will be cancelled when the listener needs to stop - no further events will be consumed after this, so all pushes to the listener should select on the done channel too 28 | BlockListener chan<- *BlockHashEvent // The connector should push new blocks to every listener, marking if it's possible blocks were missed (due to reconnect). The listener guarantees to always consume from this channel, until the listener context closes. 29 | } 30 | 31 | type NewBlockListenerResponse struct { 32 | } 33 | -------------------------------------------------------------------------------- /pkg/ffcapi/next_nonce_for_signer.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | // NextNonceForSignerRequest used to do a query for the next nonce to use for a 24 | // given signing identity. This is only used when there are no pending 25 | // operations outstanding for this signer known to the transaction manager. 26 | type NextNonceForSignerRequest struct { 27 | Signer string `json:"signer"` 28 | } 29 | 30 | type NextNonceForSignerResponse struct { 31 | Nonce *fftypes.FFBigInt `json:"nonce"` 32 | } 33 | -------------------------------------------------------------------------------- /pkg/ffcapi/submission_error.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | type SubmissionError struct { 20 | Error string `json:"error"` 21 | // When submissionRejected: true, the failure is considered final and the operation should transition directly to failed. 22 | // This should be returned in all cases where the FFCAPI connector or underlying blockchain node has evaluated the transaction 23 | // during the prepare phase, and determined it will fail if it were submitted. 24 | // The idempotencyKey is "spent" in these scenarios in the FF Core layer, but the transaction is never recorded into the FFTM 25 | // database, so the nonce is not spent, and the transaction is never submitted. 26 | SubmissionRejected bool `json:"submissionRejected,omitempty"` 27 | } 28 | 29 | func MapSubmissionRejected(reason ErrorReason) bool { 30 | switch reason { 31 | case ErrorReasonInvalidInputs, 32 | ErrorReasonTransactionReverted, 33 | ErrorReasonInsufficientFunds: 34 | // These reason codes are considered as rejections of the transaction - see ffcapi.SubmissionError 35 | return true 36 | default: 37 | // Everything else is eligible for idempotent retry of submission 38 | return false 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/ffcapi/submission_error_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestMapSubmissionError(t *testing.T) { 26 | assert.True(t, MapSubmissionRejected(ErrorReasonTransactionReverted)) 27 | assert.True(t, MapSubmissionRejected(ErrorReasonInvalidInputs)) 28 | assert.True(t, MapSubmissionRejected(ErrorReasonInsufficientFunds)) 29 | assert.False(t, MapSubmissionRejected(ErrorReasonTransactionUnderpriced)) 30 | assert.False(t, MapSubmissionRejected("")) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/ffcapi/transaction_prepare.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | // TransactionPrepareRequest is used to prepare a set of JSON formatted developer friendly 24 | // inputs, into a raw transaction ready for submission to the blockchain. 25 | // 26 | // The connector is responsible for encoding the transaction ready for submission, 27 | // and returning the hash for the transaction as well as a string serialization of 28 | // the pre-signed raw transaction in a format of its own choosing (hex etc.). 29 | // The hash is expected to be a function of: 30 | // - the method signature 31 | // - the signing identity 32 | // - the nonce 33 | // - the particular blockchain the transaction is submitted to 34 | // - the input parameters 35 | // 36 | // If "gas" is not supplied, the connector is expected to perform gas estimation 37 | // prior to generating the payload. 38 | // 39 | // See the list of standard error reasons that should be returned for situations that can be 40 | // detected by the back-end connector. 41 | type TransactionPrepareRequest struct { 42 | TransactionInput 43 | } 44 | 45 | type TransactionPrepareResponse struct { 46 | Gas *fftypes.FFBigInt `json:"gas"` 47 | TransactionData string `json:"transactionData"` 48 | } 49 | -------------------------------------------------------------------------------- /pkg/ffcapi/transaction_receipt.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | type TransactionReceiptRequest struct { 24 | TransactionHash string `json:"transactionHash"` 25 | IncludeLogs bool `json:"includeLogs"` 26 | EventFilters []fftypes.JSONAny `json:"eventFilters"` 27 | Methods []fftypes.JSONAny `json:"methods"` 28 | ExtractSigner bool `json:"extractSigner"` 29 | } 30 | 31 | type TransactionReceiptResponseBase struct { 32 | BlockNumber *fftypes.FFBigInt `json:"blockNumber"` 33 | TransactionIndex *fftypes.FFBigInt `json:"transactionIndex"` 34 | BlockHash string `json:"blockHash"` 35 | Success bool `json:"success"` 36 | ProtocolID string `json:"protocolId"` 37 | ExtraInfo *fftypes.JSONAny `json:"extraInfo,omitempty"` 38 | ContractLocation *fftypes.JSONAny `json:"contractLocation,omitempty"` 39 | Logs []fftypes.JSONAny `json:"logs,omitempty"` // all raw un-decoded logs should be included if includeLogs=true 40 | } 41 | 42 | type TransactionReceiptResponse struct { 43 | TransactionReceiptResponseBase 44 | Events []*Event `json:"events,omitempty"` // only for events that matched the filter, and were decoded 45 | } 46 | -------------------------------------------------------------------------------- /pkg/ffcapi/transaction_send.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package ffcapi 18 | 19 | import ( 20 | "github.com/hyperledger/firefly-common/pkg/fftypes" 21 | ) 22 | 23 | // TransactionSendRequest is used to send a transaction to the blockchain. 24 | // The connector is responsible for adding it to the transaction pool of the blockchain, 25 | // noting the transaction hash has already been calculated in the prepare step previously. 26 | type TransactionSendRequest struct { 27 | GasPrice *fftypes.JSONAny `json:"gasPrice,omitempty"` // can be a simple string/number, or a complex object - contract is between policy engine and blockchain connector 28 | TransactionHeaders 29 | TransactionData string `json:"transactionData"` 30 | PreSigned bool `json:"preSigned,omitempty"` 31 | } 32 | 33 | type TransactionSendResponse struct { 34 | TransactionHash string `json:"transactionHash"` 35 | } 36 | -------------------------------------------------------------------------------- /pkg/fftm/address_management.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/log" 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 25 | ) 26 | 27 | func (m *manager) getLiveBalance(ctx context.Context, address string, blockTag string) (resp *apitypes.LiveAddressBalance, err error) { 28 | resp = &apitypes.LiveAddressBalance{} 29 | balance, reason, err := m.connector.AddressBalance(ctx, &ffcapi.AddressBalanceRequest{Address: address, BlockTag: blockTag}) 30 | if err == nil { 31 | resp.AddressBalanceResponse = *balance 32 | } else { 33 | log.L(ctx).Warnf("Failed to fetch live address balance: %s (reason: %s)", err, reason) 34 | return nil, err 35 | } 36 | return resp, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/fftm/address_management_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "testing" 23 | 24 | "github.com/hyperledger/firefly-common/pkg/fftypes" 25 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/mock" 29 | ) 30 | 31 | func TestBalanceOK(t *testing.T) { 32 | _, m, cancel := newTestManager(t) 33 | defer cancel() 34 | m.Start() 35 | 36 | mca := m.connector.(*ffcapimocks.API) 37 | mca.On("AddressBalance", mock.Anything, mock.Anything).Return(&ffcapi.AddressBalanceResponse{Balance: fftypes.NewFFBigInt(999)}, ffcapi.ErrorReason(""), nil) 38 | 39 | res, err := m.getLiveBalance(context.Background(), "0x4a8c8f1717570f9774652075e249ded38124d708", "latest") 40 | 41 | assert.Nil(t, err) 42 | assert.NotNil(t, res) 43 | assert.Equal(t, int64(999), res.AddressBalanceResponse.Balance.Int64()) 44 | 45 | res, err = m.getLiveBalance(context.Background(), "0x4a8c8f1717570f9774652075e249ded38124d708", "") 46 | 47 | assert.Nil(t, err) 48 | assert.NotNil(t, res) 49 | assert.Equal(t, int64(999), res.AddressBalanceResponse.Balance.Int64()) 50 | 51 | mca.AssertExpectations(t) 52 | } 53 | 54 | func TestBalanceFail(t *testing.T) { 55 | 56 | _, m, cancel := newTestManager(t) 57 | defer cancel() 58 | m.Start() 59 | 60 | mca := m.connector.(*ffcapimocks.API) 61 | mca.On("AddressBalance", mock.Anything, mock.Anything).Return(nil, ffcapi.ErrorReason(""), fmt.Errorf("pop")) 62 | 63 | res, err := m.getLiveBalance(context.Background(), "0x4a8c8f1717570f9774652075e249ded38124d708", "") 64 | 65 | assert.Nil(t, res) 66 | assert.Regexp(t, "pop", err) 67 | 68 | mca.AssertExpectations(t) 69 | } 70 | -------------------------------------------------------------------------------- /pkg/fftm/config_docs_generate_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | //go:build docs 18 | // +build docs 19 | 20 | package fftm 21 | 22 | import ( 23 | "context" 24 | "os" 25 | "path/filepath" 26 | "testing" 27 | 28 | "github.com/hyperledger/firefly-common/pkg/config" 29 | "github.com/stretchr/testify/assert" 30 | ) 31 | 32 | const configDocHeader = "# Configuration reference" 33 | 34 | func TestGenerateConfigDocs(t *testing.T) { 35 | // Initialize config of all plugins 36 | InitConfig() 37 | f, err := os.Create(filepath.Join("..", "..", "config.md")) 38 | assert.NoError(t, err) 39 | generatedConfig, err := config.GenerateConfigMarkdown(context.Background(), configDocHeader, config.GetKnownKeys()) 40 | assert.NoError(t, err) 41 | _, err = f.Write(generatedConfig) 42 | assert.NoError(t, err) 43 | err = f.Close() 44 | assert.NoError(t, err) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/config_docs_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | //go:build !docs 18 | // +build !docs 19 | 20 | package fftm 21 | 22 | import ( 23 | "context" 24 | "crypto/sha1" 25 | "os" 26 | "path/filepath" 27 | "testing" 28 | 29 | "github.com/hyperledger/firefly-common/pkg/config" 30 | "github.com/stretchr/testify/assert" 31 | ) 32 | 33 | const configDocHeader = "# Configuration reference" 34 | 35 | func TestConfigDocsUpToDate(t *testing.T) { 36 | // Initialize config of all plugins 37 | InitConfig() 38 | generatedConfig, err := config.GenerateConfigMarkdown(context.Background(), configDocHeader, config.GetKnownKeys()) 39 | assert.NoError(t, err) 40 | configOnDisk, err := os.ReadFile(filepath.Join("..", "..", "config.md")) 41 | assert.NoError(t, err) 42 | 43 | generatedConfigHash := sha1.New() 44 | generatedConfigHash.Write(generatedConfig) 45 | configOnDiskHash := sha1.New() 46 | configOnDiskHash.Write(configOnDisk) 47 | assert.Equal(t, configOnDiskHash.Sum(nil), generatedConfigHash.Sum(nil), "The config reference docs generated by the code did not match the config.md file in git. Did you forget to run `make reference`?") 48 | } 49 | -------------------------------------------------------------------------------- /pkg/fftm/gas_management.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/log" 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 25 | ) 26 | 27 | func (m *manager) getLiveGasPrice(ctx context.Context) (resp *apitypes.LiveGasPrice, err error) { 28 | resp = &apitypes.LiveGasPrice{} 29 | gasPrice, reason, err := m.connector.GasPriceEstimate(ctx, &ffcapi.GasPriceEstimateRequest{}) 30 | if err == nil { 31 | resp.GasPriceEstimateResponse = *gasPrice 32 | } else { 33 | log.L(ctx).Warnf("Failed to fetch live gas price: %s (reason: %s)", err, reason) 34 | return nil, err 35 | } 36 | return resp, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_eventstream.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | ) 25 | 26 | var deleteEventStream = func(m *manager) *ffapi.Route { 27 | return &ffapi.Route{ 28 | Name: "deleteEventStream", 29 | Path: "/eventstreams/{streamId}", 30 | Method: http.MethodDelete, 31 | PathParams: []*ffapi.PathParam{ 32 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 33 | }, 34 | QueryParams: nil, 35 | Description: tmmsgs.APIEndpointDeleteEventStream, 36 | JSONInputValue: nil, 37 | JSONOutputValue: nil, 38 | JSONOutputCodes: []int{http.StatusNoContent}, 39 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 40 | err = m.deleteStream(r.Req.Context(), r.PP["streamId"]) 41 | return nil, err 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_eventstream_listener.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var deleteEventStreamListener = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "deleteEventStreamListener", 30 | Path: "/eventstreams/{streamId}/listeners/{listenerId}", 31 | Method: http.MethodDelete, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointDeleteEventStreamListener, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusNoContent}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return nil, m.deleteListener(r.Req.Context(), r.PP["streamId"], r.PP["listenerId"]) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_eventstream_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestDeleteEventStream(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | // Create stream 43 | var es apitypes.EventStream 44 | res, err := resty.New().R(). 45 | SetBody(&apitypes.EventStream{ 46 | Name: strPtr("my event stream"), 47 | }). 48 | SetResult(&es). 49 | Post(url + "/eventstreams") 50 | assert.NoError(t, err) 51 | assert.Equal(t, 200, res.StatusCode()) 52 | 53 | // Then delete it 54 | res, err = resty.New().R(). 55 | SetResult(&es). 56 | Delete(url + "/eventstreams/" + es.ID.String()) 57 | assert.NoError(t, err) 58 | assert.Equal(t, 204, res.StatusCode()) 59 | 60 | assert.Nil(t, m.eventStreams[(*es.ID)]) 61 | 62 | } 63 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_subscription.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var deleteSubscription = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "deleteSubscription", 30 | Path: "/subscriptions/{listenerId}", 31 | Deprecated: true, // in favor of "/eventstreams/{streamId}/listeners/{listenerId}" 32 | Method: http.MethodDelete, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointDeleteSubscription, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusNoContent}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return nil, m.deleteListener(r.Req.Context(), "" /* no streamId on this path */, r.PP["listenerId"]) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_transaction.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var deleteTransaction = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "deleteTransaction", 30 | Path: "/transactions/{transactionId}", 31 | Method: http.MethodDelete, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointDeleteTransaction, 37 | JSONInputValue: nil, 38 | JSONOutputValue: func() interface{} { return &apitypes.ManagedTX{} }, 39 | JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | r.SuccessStatus, output, err = m.requestTransactionDeletion(r.Req.Context(), r.PP["transactionId"]) 42 | return output, err 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_delete_transaction_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-transaction-manager/mocks/txhandlermocks" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestDeleteTransaction(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | tx := newTestTxn(t, m, "0x0aaaaa", 10001, apitypes.TxStatusSucceeded) 35 | txID := tx.ID 36 | 37 | err := m.Start() 38 | assert.NoError(t, err) 39 | 40 | var txOut *apitypes.ManagedTX 41 | res, err := resty.New().R(). 42 | SetResult(&txOut). 43 | Delete(fmt.Sprintf("%s/transactions/%s", url, txID)) 44 | assert.NoError(t, err) 45 | assert.Equal(t, 202, res.StatusCode()) 46 | assert.Equal(t, txID, txOut.ID) 47 | } 48 | 49 | func TestDeleteTransactionFailed(t *testing.T) { 50 | url, m, done := newTestManager(t) 51 | defer done() 52 | 53 | err := m.Start() 54 | assert.NoError(t, err) 55 | mth := txhandlermocks.TransactionHandler{} 56 | mth.On("HandleCancelTransaction", mock.Anything, "1234").Return(nil, fmt.Errorf("error")).Once() 57 | m.txHandler = &mth 58 | 59 | var txOut *apitypes.ManagedTX 60 | res, err := resty.New().R(). 61 | SetResult(&txOut). 62 | Delete(fmt.Sprintf("%s/transactions/%s", url, "1234")) 63 | assert.NoError(t, err) 64 | assert.Equal(t, 500, res.StatusCode()) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_address_balance.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var getAddressBalance = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "getBalance", 30 | Path: "/gastoken/balances/{address}", 31 | Method: http.MethodGet, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "address", Description: tmmsgs.APIParamSignerAddress}, 34 | }, 35 | QueryParams: []*ffapi.QueryParam{ 36 | {Name: "blocktag", Description: tmmsgs.APIParamBlocktag}, 37 | }, 38 | Description: tmmsgs.APIEndpointGetAddressBalance, 39 | JSONInputValue: nil, 40 | JSONOutputValue: func() interface{} { return &apitypes.LiveAddressBalance{} }, 41 | JSONOutputCodes: []int{http.StatusOK}, 42 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 43 | return m.getLiveBalance(r.Req.Context(), r.PP["address"], r.QP["blocktag"]) 44 | }, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_address_balance_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "testing" 23 | 24 | "github.com/go-resty/resty/v2" 25 | "github.com/hyperledger/firefly-common/pkg/fftypes" 26 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 27 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 28 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 29 | "github.com/stretchr/testify/assert" 30 | "github.com/stretchr/testify/mock" 31 | ) 32 | 33 | func TestGetAddressBalanceOK(t *testing.T) { 34 | url, m, done := newTestManager(t) 35 | defer done() 36 | 37 | mfc := m.connector.(*ffcapimocks.API) 38 | 39 | mfc.On("AddressBalance", mock.Anything, mock.Anything).Return(&ffcapi.AddressBalanceResponse{Balance: fftypes.NewFFBigInt(999)}, ffcapi.ErrorReason(""), nil) 40 | 41 | err := m.Start() 42 | assert.NoError(t, err) 43 | 44 | var liv apitypes.LiveAddressBalance 45 | res, err := resty.New().R(). 46 | SetResult(&liv). 47 | Get(url + "/gastoken/balances/0x4a8c8f1717570f9774652075e249ded38124d708") 48 | assert.NoError(t, err) 49 | assert.Equal(t, 200, res.StatusCode()) 50 | var responseObj fftypes.JSONObject 51 | err = json.Unmarshal(res.Body(), &responseObj) 52 | assert.NoError(t, err) 53 | assert.Equal(t, responseObj.GetString("balance"), "999") 54 | } 55 | 56 | func TestGetAddressBalanceBadAddress(t *testing.T) { 57 | url, m, done := newTestManager(t) 58 | defer done() 59 | 60 | mfc := m.connector.(*ffcapimocks.API) 61 | mfc.On("AddressBalance", mock.Anything, mock.Anything).Return(nil, ffcapi.ErrorReason(""), fmt.Errorf("pop")) 62 | 63 | err := m.Start() 64 | assert.NoError(t, err) 65 | 66 | var liv apitypes.LiveAddressBalance 67 | res, err := resty.New().R(). 68 | SetResult(&liv). 69 | Get(url + "/gastoken/balances/0x4a8c8f1717570f9774652075e249ded38124d708") 70 | assert.NoError(t, err) 71 | assert.Equal(t, 500, res.StatusCode()) 72 | } 73 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_eventstream.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var getEventStream = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "getEventStream", 30 | Path: "/eventstreams/{streamId}", 31 | Method: http.MethodGet, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointGetEventStream, 37 | JSONInputValue: nil, 38 | JSONOutputValue: func() interface{} { return &apitypes.EventStreamWithStatus{} }, 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | return m.getStream(r.Req.Context(), r.PP["streamId"]) 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_eventstream_listener.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var getEventStreamListener = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "getEventStreamListener", 30 | Path: "/eventstreams/{streamId}/listeners/{listenerId}", 31 | Method: http.MethodGet, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointGetEventStreamListener, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.getListener(r.Req.Context(), r.PP["streamId"], r.PP["listenerId"]) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_eventstream_listeners.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var getEventStreamListeners = func(m *manager) *ffapi.Route { 29 | route := &ffapi.Route{ 30 | Name: "getEventStreamListeners", 31 | Path: "/eventstreams/{streamId}/listeners", 32 | Method: http.MethodGet, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 35 | }, 36 | Description: tmmsgs.APIEndpointGetEventStreamListeners, 37 | JSONInputValue: nil, 38 | JSONOutputValue: func() interface{} { return []*apitypes.Listener{} }, 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | } 41 | if m.richQueryEnabled { 42 | route.FilterFactory = persistence.ListenerFilters 43 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 44 | return r.FilterResult(m.getStreamListenersRich(r.Req.Context(), r.PP["streamId"], r.Filter)) 45 | } 46 | } else { 47 | // Very limited query support 48 | route.QueryParams = []*ffapi.QueryParam{ 49 | {Name: "limit", Description: tmmsgs.APIParamLimit}, 50 | {Name: "after", Description: tmmsgs.APIParamAfter}, 51 | } 52 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 53 | return m.getStreamListenersByCreateTime(r.Req.Context(), r.QP["after"], r.QP["limit"], r.PP["streamId"]) 54 | } 55 | } 56 | return route 57 | } 58 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_eventstream_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestGetEventStream(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | // Create stream 43 | var es apitypes.EventStream 44 | res, err := resty.New().R(). 45 | SetBody(&apitypes.EventStream{ 46 | Name: strPtr("my event stream"), 47 | }). 48 | SetResult(&es). 49 | Post(url + "/eventstreams") 50 | assert.NoError(t, err) 51 | assert.Equal(t, 200, res.StatusCode()) 52 | 53 | // Then get it 54 | var ess apitypes.EventStreamWithStatus 55 | res, err = resty.New().R(). 56 | SetResult(&ess). 57 | Get(url + "/eventstreams/" + es.ID.String()) 58 | assert.NoError(t, err) 59 | assert.Equal(t, 200, res.StatusCode()) 60 | 61 | assert.Equal(t, es.ID, ess.ID) 62 | assert.Equal(t, apitypes.EventStreamStatusStarted, ess.Status) 63 | 64 | } 65 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_eventstreams.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var getEventStreams = func(m *manager) *ffapi.Route { 29 | route := &ffapi.Route{ 30 | Name: "getEventStreams", 31 | Path: "/eventstreams", 32 | Method: http.MethodGet, 33 | PathParams: nil, 34 | Description: tmmsgs.APIEndpointGetEventStreams, 35 | JSONInputValue: nil, 36 | JSONOutputValue: func() interface{} { return []*apitypes.EventStream{} }, 37 | JSONOutputCodes: []int{http.StatusOK}, 38 | } 39 | if m.richQueryEnabled { 40 | route.FilterFactory = persistence.EventStreamFilters 41 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return r.FilterResult(m.persistence.RichQuery().ListStreams(r.Req.Context(), r.Filter)) 43 | } 44 | } else { 45 | // Very limited query support 46 | route.QueryParams = []*ffapi.QueryParam{ 47 | {Name: "limit", Description: tmmsgs.APIParamLimit}, 48 | {Name: "after", Description: tmmsgs.APIParamAfter}, 49 | } 50 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 51 | return m.getStreams(r.Req.Context(), r.QP["after"], r.QP["limit"]) 52 | } 53 | } 54 | return route 55 | } 56 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_gas_price.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 23 | 24 | "github.com/hyperledger/firefly-common/pkg/ffapi" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var getGasPrice = func(m *manager) *ffapi.Route { 29 | return &ffapi.Route{ 30 | Name: "getGasPrice", 31 | Path: "/gasprice", 32 | Method: http.MethodGet, 33 | PathParams: nil, 34 | QueryParams: nil, 35 | Description: tmmsgs.APIEndpointGetGasPrice, 36 | JSONInputValue: nil, 37 | JSONOutputValue: func() interface{} { return &apitypes.LiveGasPrice{} }, 38 | JSONOutputCodes: []int{http.StatusOK}, 39 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 40 | return m.getLiveGasPrice(r.Req.Context()) 41 | }, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_gas_price_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "testing" 23 | 24 | "github.com/go-resty/resty/v2" 25 | "github.com/hyperledger/firefly-common/pkg/fftypes" 26 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 27 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 28 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 29 | "github.com/stretchr/testify/assert" 30 | "github.com/stretchr/testify/mock" 31 | ) 32 | 33 | func TestGetGasPriceOK(t *testing.T) { 34 | url, m, done := newTestManager(t) 35 | defer done() 36 | 37 | mfc := m.connector.(*ffcapimocks.API) 38 | 39 | mfc.On("GasPriceEstimate", mock.Anything, mock.Anything).Return(&ffcapi.GasPriceEstimateResponse{GasPrice: fftypes.JSONAnyPtr("123456")}, ffcapi.ErrorReason(""), nil) 40 | 41 | err := m.Start() 42 | assert.NoError(t, err) 43 | 44 | var liv apitypes.LiveGasPrice 45 | res, err := resty.New().R(). 46 | SetResult(&liv). 47 | Get(url + "/gasprice") 48 | assert.NoError(t, err) 49 | assert.Equal(t, 200, res.StatusCode()) 50 | var responseObj fftypes.JSONObject 51 | err = json.Unmarshal(res.Body(), &responseObj) 52 | assert.NoError(t, err) 53 | assert.Equal(t, responseObj.GetString("gasPrice"), "123456") 54 | } 55 | 56 | func TestGetGasPriceBad(t *testing.T) { 57 | url, m, done := newTestManager(t) 58 | defer done() 59 | 60 | mfc := m.connector.(*ffcapimocks.API) 61 | mfc.On("GasPriceEstimate", mock.Anything, mock.Anything).Return(nil, ffcapi.ErrorReason(""), fmt.Errorf("pop")) 62 | 63 | err := m.Start() 64 | assert.NoError(t, err) 65 | 66 | var liv apitypes.LiveGasPrice 67 | res, err := resty.New().R(). 68 | SetResult(&liv). 69 | Get(url + "/gasprice") 70 | assert.NoError(t, err) 71 | assert.Equal(t, 500, res.StatusCode()) 72 | } 73 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_status_live_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "github.com/go-resty/resty/v2" 21 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 22 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 24 | "github.com/stretchr/testify/assert" 25 | "github.com/stretchr/testify/mock" 26 | "testing" 27 | ) 28 | 29 | func TestGetLiveStatus(t *testing.T) { 30 | url, m, done := newTestManager(t) 31 | defer done() 32 | 33 | mfc := m.connector.(*ffcapimocks.API) 34 | mfc.On("IsLive", mock.Anything).Return(&ffcapi.LiveResponse{Up: true}, ffcapi.ErrorReason(""), nil) 35 | 36 | err := m.Start() 37 | assert.NoError(t, err) 38 | 39 | var liv apitypes.LiveStatus 40 | res, err := resty.New().R(). 41 | SetResult(&liv). 42 | Get(url + "/status/live") 43 | assert.NoError(t, err) 44 | assert.Equal(t, 200, res.StatusCode()) 45 | } 46 | 47 | func TestGetStatus(t *testing.T) { 48 | url, m, done := newTestManager(t) 49 | defer done() 50 | 51 | mfc := m.connector.(*ffcapimocks.API) 52 | mfc.On("IsLive", mock.Anything, mock.Anything).Return(&ffcapi.LiveResponse{Up: true}, ffcapi.ErrorReason(""), nil) 53 | 54 | err := m.Start() 55 | assert.NoError(t, err) 56 | 57 | var liv apitypes.LiveStatus 58 | res, err := resty.New().R(). 59 | SetResult(&liv). 60 | Get(url + "/status") 61 | assert.NoError(t, err) 62 | assert.Equal(t, 200, res.StatusCode()) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_status_ready.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 23 | 24 | "github.com/hyperledger/firefly-common/pkg/ffapi" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var deprecatedGetReadyStatus = func(m *manager) *ffapi.Route { 29 | return &ffapi.Route{ 30 | Name: "getReadyStatus", 31 | Path: "/status/ready", 32 | Method: http.MethodGet, 33 | PathParams: nil, 34 | QueryParams: nil, 35 | Description: tmmsgs.APIEndpointGetStatusReady, 36 | JSONInputValue: nil, 37 | JSONOutputValue: func() interface{} { return &apitypes.ReadyStatus{} }, 38 | JSONOutputCodes: []int{http.StatusOK}, 39 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 40 | return m.getReadyStatus(r.Req.Context()) 41 | }, 42 | } 43 | } 44 | 45 | var getReadiness = func(m *manager) *ffapi.Route { 46 | return &ffapi.Route{ 47 | Name: "getReadiness", 48 | Path: "/readyz", 49 | Method: http.MethodGet, 50 | PathParams: nil, 51 | QueryParams: nil, 52 | Description: tmmsgs.APIEndpointGetReadiness, 53 | JSONInputValue: nil, 54 | JSONOutputValue: func() interface{} { return &apitypes.ReadyStatus{} }, 55 | JSONOutputCodes: []int{http.StatusOK}, 56 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 57 | return m.getReadyStatus(r.Req.Context()) 58 | }, 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_status_ready_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "github.com/go-resty/resty/v2" 21 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 22 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 24 | "github.com/stretchr/testify/assert" 25 | "github.com/stretchr/testify/mock" 26 | "testing" 27 | ) 28 | 29 | func TestGetReadyStatus(t *testing.T) { 30 | url, m, done := newTestManager(t) 31 | defer done() 32 | 33 | mfc := m.connector.(*ffcapimocks.API) 34 | mfc.On("IsReady", mock.Anything).Return(&ffcapi.ReadyResponse{Ready: true}, ffcapi.ErrorReason(""), nil) 35 | 36 | err := m.Start() 37 | assert.NoError(t, err) 38 | 39 | var liv apitypes.LiveStatus 40 | res, err := resty.New().R(). 41 | SetResult(&liv). 42 | Get(url + "/status/ready") 43 | assert.NoError(t, err) 44 | assert.Equal(t, 200, res.StatusCode()) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_subscription.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var getSubscription = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "getSubscription", 30 | Path: "/subscriptions/{listenerId}", 31 | Deprecated: true, // in favor of "/eventstreams/{streamId}/listeners/{listenerId}" 32 | Method: http.MethodGet, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointGetSubscription, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.getListener(r.Req.Context(), "" /* no streamId on this path */, r.PP["listenerId"]) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_subscriptions.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var getSubscriptions = func(m *manager) *ffapi.Route { 29 | 30 | route := &ffapi.Route{ 31 | Name: "getSubscriptions", 32 | Path: "/subscriptions", 33 | Deprecated: true, // in favor of "/eventstreams/{id}/listeners" 34 | Method: http.MethodGet, 35 | PathParams: nil, 36 | Description: tmmsgs.APIEndpointGetSubscriptions, 37 | JSONInputValue: nil, 38 | JSONOutputValue: func() interface{} { return []*apitypes.Listener{} }, 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | } 41 | if m.richQueryEnabled { 42 | route.FilterFactory = persistence.ListenerFilters 43 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 44 | return r.FilterResult(m.persistence.RichQuery().ListListeners(r.Req.Context(), r.Filter)) 45 | } 46 | } else { 47 | // Very limited query support 48 | route.QueryParams = []*ffapi.QueryParam{ 49 | {Name: "limit", Description: tmmsgs.APIParamLimit}, 50 | {Name: "after", Description: tmmsgs.APIParamAfter}, 51 | } 52 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 53 | return m.getListeners(r.Req.Context(), r.QP["after"], r.QP["limit"]) 54 | } 55 | } 56 | return route 57 | } 58 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | "strings" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/ffapi" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | ) 27 | 28 | var getTransaction = func(m *manager) *ffapi.Route { 29 | return &ffapi.Route{ 30 | Name: "getTransaction", 31 | Path: "/transactions/{transactionId}", 32 | Method: http.MethodGet, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 35 | }, 36 | QueryParams: []*ffapi.QueryParam{ 37 | {Name: "history", Description: tmmsgs.APIParamHistory, IsBool: true}, 38 | }, 39 | Description: tmmsgs.APIEndpointGetTransaction, 40 | JSONInputValue: nil, 41 | JSONOutputValue: func() interface{} { return &apitypes.TXWithStatus{} }, 42 | JSONOutputCodes: []int{http.StatusOK}, 43 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 44 | return m.getTransactionByIDWithStatus(r.Req.Context(), r.PP["transactionId"], strings.EqualFold(r.QP["history"], "true")) 45 | }, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_confirmations.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-common/pkg/i18n" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 25 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 27 | ) 28 | 29 | var getTransactionConfirmations = func(m *manager) *ffapi.Route { 30 | route := &ffapi.Route{ 31 | Name: "getTransactionConfirmations", 32 | Path: "/transactions/{transactionId}/confirmations", 33 | Method: http.MethodGet, 34 | PathParams: []*ffapi.PathParam{ 35 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 36 | }, 37 | Description: tmmsgs.APIEndpointGetTransactionConfirmations, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return []*apitypes.ConfirmationRecord{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | } 42 | if m.richQueryEnabled { 43 | route.FilterFactory = persistence.ConfirmationFilters 44 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 45 | return r.FilterResult(m.persistence.RichQuery().ListTransactionConfirmations(r.Req.Context(), r.PP["transactionId"], r.Filter)) 46 | } 47 | } else { 48 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 49 | return nil, i18n.NewError(r.Req.Context(), tmmsgs.MsgOpNotSupportedWithoutRichQuery) 50 | } 51 | } 52 | return route 53 | } 54 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_confirmations_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-common/pkg/dbsql" 25 | "github.com/hyperledger/firefly-common/pkg/fftypes" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/mock" 29 | ) 30 | 31 | func TestGetTransactionConfirmationsOK(t *testing.T) { 32 | 33 | url, _, mrc, done := newTestManagerMockRichDB(t) 34 | defer done() 35 | 36 | id1 := fftypes.NewUUID() 37 | mrc.On("ListTransactionConfirmations", mock.Anything, "tx1", mock.Anything).Return( 38 | []*apitypes.ConfirmationRecord{{TransactionID: "tx1", ResourceBase: dbsql.ResourceBase{ID: id1}}}, nil, nil, 39 | ) 40 | 41 | var out []*apitypes.ConfirmationRecord 42 | res, err := resty.New().R(). 43 | SetResult(&out). 44 | Get(fmt.Sprintf("%s/transactions/%s/confirmations", url, "tx1")) 45 | assert.NoError(t, err) 46 | assert.Equal(t, 200, res.StatusCode()) 47 | assert.Equal(t, id1, out[0].ID) 48 | } 49 | 50 | func TestGetTransactionConfirmationsNoRichQuery(t *testing.T) { 51 | 52 | url, _, done := newTestManagerMockNoRichDB(t) 53 | defer done() 54 | 55 | var txOut apitypes.ManagedTX 56 | var errorOut fftypes.RESTError 57 | res, err := resty.New().R(). 58 | SetResult(&txOut). 59 | SetError(&errorOut). 60 | Get(fmt.Sprintf("%s/transactions/%s/confirmations", url, "tx1")) 61 | assert.NoError(t, err) 62 | assert.Equal(t, 501, res.StatusCode()) 63 | assert.Regexp(t, "FF21085", errorOut.Error) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_history.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-common/pkg/i18n" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 25 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 27 | ) 28 | 29 | var getTransactionHistory = func(m *manager) *ffapi.Route { 30 | route := &ffapi.Route{ 31 | Name: "getTransactionHistory", 32 | Path: "/transactions/{transactionId}/history", 33 | Method: http.MethodGet, 34 | PathParams: []*ffapi.PathParam{ 35 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 36 | }, 37 | Description: tmmsgs.APIEndpointGetTransactionHistory, 38 | JSONInputValue: nil, 39 | JSONOutputValue: func() interface{} { return []*apitypes.TXHistoryRecord{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | } 42 | if m.richQueryEnabled { 43 | route.FilterFactory = persistence.TXHistoryFilters 44 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 45 | return r.FilterResult(m.persistence.RichQuery().ListTransactionHistory(r.Req.Context(), r.PP["transactionId"], r.Filter)) 46 | } 47 | } else { 48 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 49 | return nil, i18n.NewError(r.Req.Context(), tmmsgs.MsgOpNotSupportedWithoutRichQuery) 50 | } 51 | } 52 | return route 53 | } 54 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_history_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-common/pkg/fftypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestGetTransactionHistoryOK(t *testing.T) { 31 | 32 | url, _, mrc, done := newTestManagerMockRichDB(t) 33 | defer done() 34 | 35 | id1 := fftypes.NewUUID() 36 | mrc.On("ListTransactionHistory", mock.Anything, "tx1", mock.Anything).Return( 37 | []*apitypes.TXHistoryRecord{{TransactionID: "tx1", ID: id1}}, nil, nil, 38 | ) 39 | 40 | var out []*apitypes.TXHistoryRecord 41 | res, err := resty.New().R(). 42 | SetResult(&out). 43 | Get(fmt.Sprintf("%s/transactions/%s/history", url, "tx1")) 44 | assert.NoError(t, err) 45 | assert.Equal(t, 200, res.StatusCode()) 46 | assert.Equal(t, id1, out[0].ID) 47 | } 48 | 49 | func TestGetTransactionHistoryNoRichQuery(t *testing.T) { 50 | 51 | url, _, done := newTestManagerMockNoRichDB(t) 52 | defer done() 53 | 54 | var txOut apitypes.ManagedTX 55 | var errorOut fftypes.RESTError 56 | res, err := resty.New().R(). 57 | SetResult(&txOut). 58 | SetError(&errorOut). 59 | Get(fmt.Sprintf("%s/transactions/%s/history", url, "tx1")) 60 | assert.NoError(t, err) 61 | assert.Equal(t, 501, res.StatusCode()) 62 | assert.Regexp(t, "FF21085", errorOut.Error) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_receipt.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 25 | ) 26 | 27 | var getTransactionReceipt = func(m *manager) *ffapi.Route { 28 | route := &ffapi.Route{ 29 | Name: "getTransactionReceipt", 30 | Path: "/transactions/{transactionId}/receipt", 31 | Method: http.MethodGet, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 34 | }, 35 | Description: tmmsgs.APIEndpointGetTransactionReceipt, 36 | JSONInputValue: nil, 37 | JSONOutputValue: func() interface{} { return &ffcapi.TransactionReceiptResponse{} }, 38 | JSONOutputCodes: []int{http.StatusOK}, 39 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 40 | return m.persistence.GetTransactionReceipt(r.Req.Context(), r.PP["transactionId"]) 41 | }, 42 | } 43 | return route 44 | } 45 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transaction_receipt_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-common/pkg/fftypes" 25 | "github.com/hyperledger/firefly-transaction-manager/mocks/persistencemocks" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 27 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 28 | "github.com/stretchr/testify/assert" 29 | "github.com/stretchr/testify/mock" 30 | ) 31 | 32 | func TestGetTransactionReceiptOK(t *testing.T) { 33 | 34 | url, m, done := newTestManagerMockNoRichDB(t) 35 | defer done() 36 | 37 | mpm := m.persistence.(*persistencemocks.Persistence) 38 | mpm.On("GetTransactionReceipt", mock.Anything, "tx1").Return( 39 | &ffcapi.TransactionReceiptResponse{ 40 | TransactionReceiptResponseBase: ffcapi.TransactionReceiptResponseBase{ 41 | BlockHash: "0x123456", 42 | }, 43 | }, nil, 44 | ) 45 | 46 | var out apitypes.ReceiptRecord 47 | res, err := resty.New().R(). 48 | SetResult(&out). 49 | Get(fmt.Sprintf("%s/transactions/%s/receipt", url, "tx1")) 50 | assert.NoError(t, err) 51 | assert.Equal(t, 200, res.StatusCode()) 52 | assert.Equal(t, "0x123456", out.BlockHash) 53 | } 54 | 55 | func TestGetTransactionReceiptNotFound(t *testing.T) { 56 | 57 | url, m, done := newTestManagerMockNoRichDB(t) 58 | defer done() 59 | 60 | mpm := m.persistence.(*persistencemocks.Persistence) 61 | mpm.On("GetTransactionReceipt", mock.Anything, "tx1").Return(nil, nil) 62 | 63 | var errRes fftypes.RESTError 64 | res, err := resty.New().R(). 65 | SetError(&errRes). 66 | Get(fmt.Sprintf("%s/transactions/%s/receipt", url, "tx1")) 67 | assert.NoError(t, err) 68 | assert.Equal(t, 404, res.StatusCode()) 69 | assert.Regexp(t, "FF00164", errRes.Error) 70 | } 71 | -------------------------------------------------------------------------------- /pkg/fftm/route_get_transactions.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | "strings" 22 | 23 | "github.com/hyperledger/firefly-common/pkg/ffapi" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/persistence" 25 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 27 | ) 28 | 29 | var getTransactions = func(m *manager) *ffapi.Route { 30 | route := &ffapi.Route{ 31 | Name: "getTransactions", 32 | Path: "/transactions", 33 | Method: http.MethodGet, 34 | PathParams: nil, 35 | Description: tmmsgs.APIEndpointGetTransactions, 36 | JSONInputValue: nil, 37 | JSONOutputValue: func() interface{} { return []*apitypes.ManagedTX{} }, 38 | JSONOutputCodes: []int{http.StatusOK}, 39 | } 40 | if m.richQueryEnabled { 41 | route.FilterFactory = persistence.TransactionFilters 42 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 43 | return r.FilterResult(m.persistence.RichQuery().ListTransactions(r.Req.Context(), r.Filter)) 44 | } 45 | } else { 46 | // Very limited query support 47 | route.QueryParams = []*ffapi.QueryParam{ 48 | {Name: "limit", Description: tmmsgs.APIParamLimit}, 49 | {Name: "after", Description: tmmsgs.APIParamAfter}, 50 | {Name: "signer", Description: tmmsgs.APIParamTXSigner}, 51 | {Name: "pending", Description: tmmsgs.APIParamTXPending, IsBool: true}, 52 | {Name: "direction", Description: tmmsgs.APIParamSortDirection}, 53 | } 54 | route.JSONHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { 55 | return m.getTransactions(r.Req.Context(), r.QP["after"], r.QP["limit"], r.QP["signer"], strings.EqualFold(r.QP["pending"], "true"), r.QP["direction"]) 56 | } 57 | } 58 | return route 59 | } 60 | -------------------------------------------------------------------------------- /pkg/fftm/route_patch_eventstream.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var patchEventStream = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "patchEventStream", 30 | Path: "/eventstreams/{streamId}", 31 | Method: http.MethodPatch, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPatchEventStream, 37 | JSONInputValue: func() interface{} { return &apitypes.EventStream{} }, 38 | JSONOutputValue: func() interface{} { return &apitypes.EventStream{} }, 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | return m.updateStream(r.Req.Context(), r.PP["streamId"], r.Input.(*apitypes.EventStream)) 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/fftm/route_patch_eventstream_listener.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var patchEventStreamListener = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "patchEventStreamListener", 30 | Path: "/eventstreams/{streamId}/listeners/{listenerId}", 31 | Method: http.MethodPatch, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointPatchEventStreamListener, 38 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.updateExistingListener(r.Req.Context(), r.PP["streamId"], r.PP["listenerId"], r.Input.(*apitypes.Listener), false) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_patch_eventstream_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPatchEventStream(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | // Create stream 43 | var es apitypes.EventStream 44 | res, err := resty.New().R(). 45 | SetBody(&apitypes.EventStream{ 46 | Name: strPtr("my event stream"), 47 | }). 48 | SetResult(&es). 49 | Post(url + "/eventstreams") 50 | assert.NoError(t, err) 51 | assert.Equal(t, 200, res.StatusCode()) 52 | 53 | // Then update it 54 | res, err = resty.New().R(). 55 | SetBody(&apitypes.EventStream{ 56 | Name: strPtr("my renamed event stream"), 57 | }). 58 | SetResult(&es). 59 | Patch(url + "/eventstreams/" + es.ID.String()) 60 | assert.NoError(t, err) 61 | assert.Equal(t, 200, res.StatusCode()) 62 | assert.NotNil(t, es.ID) 63 | assert.NotNil(t, es.Created) 64 | assert.NotEqual(t, es.Created, es.Updated) 65 | assert.Equal(t, "my renamed event stream", *es.Name) 66 | 67 | } 68 | -------------------------------------------------------------------------------- /pkg/fftm/route_patch_subscription.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var patchSubscription = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "patchSubscription", 30 | Path: "/subscriptions/{listenerId}", 31 | Deprecated: true, // in favor of "/eventstreams/{streamId}/listeners/{listenerId}" 32 | Method: http.MethodPatch, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointPatchSubscription, 38 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.updateExistingListener(r.Req.Context(), "" /* no streamId on this path */, r.PP["listenerId"], r.Input.(*apitypes.Listener), false) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postEventStream = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postEventStream", 30 | Path: "/eventstreams", 31 | Method: http.MethodPost, 32 | PathParams: nil, 33 | QueryParams: nil, 34 | Description: tmmsgs.APIEndpointPostEventStream, 35 | JSONInputValue: func() interface{} { return &apitypes.EventStream{} }, 36 | JSONOutputValue: func() interface{} { return &apitypes.EventStream{} }, 37 | JSONOutputCodes: []int{http.StatusOK}, 38 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 39 | return m.createAndStoreNewStream(r.Req.Context(), r.Input.(*apitypes.EventStream)) 40 | }, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_listener_reset.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postEventStreamListenerReset = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postEventStreamListenerReset", 30 | Path: "/eventstreams/{streamId}/listeners/{listenerId}/reset", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointPostEventStreamListenerReset, 38 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.updateExistingListener(r.Req.Context(), r.PP["streamId"], r.PP["listenerId"], r.Input.(*apitypes.Listener), true) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_listeners.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postEventStreamListeners = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postEventStreamListeners", 30 | Path: "/eventstreams/{streamId}/listeners", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPostEventStreamListener, 37 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 38 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | return m.createAndStoreNewStreamListener(r.Req.Context(), r.PP["streamId"], r.Input.(*apitypes.Listener)) 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_listeners_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/mock" 29 | ) 30 | 31 | func TestPostEventStreamListeners(t *testing.T) { 32 | 33 | url, m, done := newTestManager(t) 34 | defer done() 35 | 36 | err := m.Start() 37 | assert.NoError(t, err) 38 | 39 | mfc := m.connector.(*ffcapimocks.API) 40 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 41 | mfc.On("EventListenerVerifyOptions", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerVerifyOptionsResponse{}, ffcapi.ErrorReason(""), nil) 42 | mfc.On("EventListenerAdd", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerAddResponse{}, ffcapi.ErrorReason(""), nil) 43 | mfc.On("EventListenerRemove", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerRemoveResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 44 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 45 | 46 | // Create a stream 47 | var es1 apitypes.EventStream 48 | res, err := resty.New().R().SetBody(&apitypes.EventStream{Name: strPtr("stream1")}).SetResult(&es1).Post(url + "/eventstreams") 49 | assert.NoError(t, err) 50 | assert.Equal(t, 200, res.StatusCode()) 51 | 52 | // Create a listener 53 | var l1 apitypes.Listener 54 | res, err = resty.New().R().SetBody(&apitypes.Listener{Name: strPtr("listener1"), StreamID: es1.ID}).SetResult(&l1).Post(fmt.Sprintf("%s/eventstreams/%s/listeners", url, es1.ID)) 55 | assert.NoError(t, err) 56 | assert.Equal(t, 200, res.StatusCode()) 57 | 58 | mfc.AssertExpectations(t) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_resume.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postEventStreamResume = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postEventStreamResume", 30 | Path: "/eventstreams/{streamId}/resume", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPostEventStreamResume, 37 | JSONInputValue: func() interface{} { return struct{}{} }, // empty input 38 | JSONOutputValue: func() interface{} { return struct{}{} }, // empty output 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | falsy := false 42 | _, err = m.updateStream(r.Req.Context(), r.PP["streamId"], &apitypes.EventStream{ 43 | Suspended: &falsy, 44 | }) 45 | return &struct{}{}, err 46 | }, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_resume_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostEventStreamResume(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | // Create stream 43 | var es apitypes.EventStream 44 | truthy := true 45 | res, err := resty.New().R(). 46 | SetBody(&apitypes.EventStream{ 47 | Name: strPtr("my event stream"), 48 | Suspended: &truthy, 49 | }). 50 | SetResult(&es). 51 | Post(url + "/eventstreams") 52 | assert.NoError(t, err) 53 | assert.Equal(t, 200, res.StatusCode()) 54 | 55 | // Then suspend it 56 | res, err = resty.New().R(). 57 | SetBody(&struct{}{}). 58 | SetResult(&es). 59 | Post(url + "/eventstreams/" + es.ID.String() + "/resume") 60 | assert.NoError(t, err) 61 | assert.Equal(t, 200, res.StatusCode()) 62 | 63 | assert.Equal(t, apitypes.EventStreamStatusStarted, m.eventStreams[(*es.ID)].Status()) 64 | 65 | } 66 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_suspend.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postEventStreamSuspend = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postEventStreamSuspend", 30 | Path: "/eventstreams/{streamId}/suspend", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "streamId", Description: tmmsgs.APIParamStreamID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPostEventStreamSuspend, 37 | JSONInputValue: func() interface{} { return struct{}{} }, // empty input 38 | JSONOutputValue: func() interface{} { return struct{}{} }, // empty output 39 | JSONOutputCodes: []int{http.StatusOK}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | truthy := true 42 | _, err = m.updateStream(r.Req.Context(), r.PP["streamId"], &apitypes.EventStream{ 43 | Suspended: &truthy, 44 | }) 45 | return &struct{}{}, err 46 | }, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_suspend_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostEventStreamSuspend(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | // Create stream 43 | var es apitypes.EventStream 44 | res, err := resty.New().R(). 45 | SetBody(&apitypes.EventStream{ 46 | Name: strPtr("my event stream"), 47 | }). 48 | SetResult(&es). 49 | Post(url + "/eventstreams") 50 | assert.NoError(t, err) 51 | assert.Equal(t, 200, res.StatusCode()) 52 | 53 | // Then suspend it 54 | res, err = resty.New().R(). 55 | SetBody(&struct{}{}). 56 | SetResult(&es). 57 | Post(url + "/eventstreams/" + es.ID.String() + "/suspend") 58 | assert.NoError(t, err) 59 | assert.Equal(t, 200, res.StatusCode()) 60 | 61 | assert.Equal(t, apitypes.EventStreamStatusStopped, m.eventStreams[(*es.ID)].Status()) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_eventstream_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostNewEventStream(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | mfc := m.connector.(*ffcapimocks.API) 36 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 37 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 38 | 39 | err := m.Start() 40 | assert.NoError(t, err) 41 | 42 | var es apitypes.EventStream 43 | res, err := resty.New().R(). 44 | SetBody(&apitypes.EventStream{ 45 | Name: strPtr("my event stream"), 46 | }). 47 | SetResult(&es). 48 | Post(url + "/eventstreams") 49 | assert.NoError(t, err) 50 | assert.Equal(t, 200, res.StatusCode()) 51 | assert.NotNil(t, es.ID) 52 | assert.NotNil(t, es.Created) 53 | assert.Equal(t, es.Created, es.Updated) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_subscription_reset.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postSubscriptionReset = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postSubscriptionReset", 30 | Path: "/subscriptions/{listenerId}/reset", 31 | Deprecated: true, // in favor of "/eventstreams/{streamId}/listeners/{listenerId}" 32 | Method: http.MethodPost, 33 | PathParams: []*ffapi.PathParam{ 34 | {Name: "listenerId", Description: tmmsgs.APIParamListenerID}, 35 | }, 36 | QueryParams: nil, 37 | Description: tmmsgs.APIEndpointPostSubscriptionReset, 38 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 39 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 40 | JSONOutputCodes: []int{http.StatusOK}, 41 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 42 | return m.updateExistingListener(r.Req.Context(), "" /* no streamId on this path */, r.PP["listenerId"], r.Input.(*apitypes.Listener), true) 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_subscriptions.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postSubscriptions = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postSubscriptions", 30 | Path: "/subscriptions", 31 | Deprecated: true, // in favor of "/eventstreams/{id}/listeners" 32 | Method: http.MethodPost, 33 | PathParams: nil, 34 | QueryParams: nil, 35 | Description: tmmsgs.APIEndpointPostSubscriptions, 36 | JSONInputValue: func() interface{} { return &apitypes.Listener{} }, 37 | JSONOutputValue: func() interface{} { return &apitypes.Listener{} }, 38 | JSONOutputCodes: []int{http.StatusOK}, 39 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 40 | return m.createAndStoreNewListener(r.Req.Context(), r.Input.(*apitypes.Listener)) 41 | }, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_subscriptions_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/go-resty/resty/v2" 23 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostSubscriptions(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | 35 | err := m.Start() 36 | assert.NoError(t, err) 37 | 38 | mfc := m.connector.(*ffcapimocks.API) 39 | mfc.On("EventStreamStart", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStartResponse{}, ffcapi.ErrorReason(""), nil) 40 | mfc.On("EventListenerVerifyOptions", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerVerifyOptionsResponse{}, ffcapi.ErrorReason(""), nil) 41 | mfc.On("EventListenerAdd", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerAddResponse{}, ffcapi.ErrorReason(""), nil) 42 | mfc.On("EventListenerRemove", mock.Anything, mock.Anything).Return(&ffcapi.EventListenerRemoveResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 43 | mfc.On("EventStreamStopped", mock.Anything, mock.Anything).Return(&ffcapi.EventStreamStoppedResponse{}, ffcapi.ErrorReason(""), nil).Maybe() 44 | 45 | // Create a stream 46 | var es1 apitypes.EventStream 47 | res, err := resty.New().R().SetBody(&apitypes.EventStream{Name: strPtr("stream1")}).SetResult(&es1).Post(url + "/eventstreams") 48 | assert.NoError(t, err) 49 | assert.Equal(t, 200, res.StatusCode()) 50 | 51 | // Create a listener 52 | var l1 apitypes.Listener 53 | res, err = resty.New().R().SetBody(&apitypes.Listener{Name: strPtr("listener1"), StreamID: es1.ID}).SetResult(&l1).Post(url + "/subscriptions") 54 | assert.NoError(t, err) 55 | assert.Equal(t, 200, res.StatusCode()) 56 | 57 | mfc.AssertExpectations(t) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_transaction_resume.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postTransactionResume = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postTransactionResume", 30 | Path: "/transactions/{transactionId}/resume", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPostTransactionResume, 37 | JSONInputValue: func() interface{} { return &struct{}{} }, 38 | JSONOutputValue: func() interface{} { return &apitypes.ManagedTX{} }, 39 | JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | r.SuccessStatus, output, err = m.requestTransactionResume(r.Req.Context(), r.PP["transactionId"]) 42 | return output, err 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_transaction_resume_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-transaction-manager/mocks/txhandlermocks" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostTransactionResume(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | tx := newTestTxn(t, m, "0x0aaaaa", 10001, apitypes.TxStatusSucceeded) 35 | txID := tx.ID 36 | 37 | err := m.Start() 38 | assert.NoError(t, err) 39 | 40 | var txOut *apitypes.ManagedTX 41 | res, err := resty.New().R(). 42 | SetResult(&txOut). 43 | SetBody(struct{}{}). 44 | Post(fmt.Sprintf("%s/transactions/%s/resume", url, txID)) 45 | assert.NoError(t, err) 46 | assert.Equal(t, 202, res.StatusCode()) 47 | assert.Equal(t, txID, txOut.ID) 48 | } 49 | 50 | func TestPostTransactionResumeFailed(t *testing.T) { 51 | url, m, done := newTestManager(t) 52 | defer done() 53 | 54 | err := m.Start() 55 | assert.NoError(t, err) 56 | mth := txhandlermocks.TransactionHandler{} 57 | mth.On("HandleResumeTransaction", mock.Anything, "1234").Return(nil, fmt.Errorf("error")).Once() 58 | m.txHandler = &mth 59 | 60 | var txOut *apitypes.ManagedTX 61 | res, err := resty.New().R(). 62 | SetResult(&txOut). 63 | SetBody(struct{}{}). 64 | Post(fmt.Sprintf("%s/transactions/%s/resume", url, "1234")) 65 | assert.NoError(t, err) 66 | assert.Equal(t, 500, res.StatusCode()) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_transaction_suspend.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/ffapi" 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 25 | ) 26 | 27 | var postTransactionSuspend = func(m *manager) *ffapi.Route { 28 | return &ffapi.Route{ 29 | Name: "postTransactionSuspend", 30 | Path: "/transactions/{transactionId}/suspend", 31 | Method: http.MethodPost, 32 | PathParams: []*ffapi.PathParam{ 33 | {Name: "transactionId", Description: tmmsgs.APIParamTransactionID}, 34 | }, 35 | QueryParams: nil, 36 | Description: tmmsgs.APIEndpointPostTransactionSuspend, 37 | JSONInputValue: func() interface{} { return &struct{}{} }, 38 | JSONOutputValue: func() interface{} { return &apitypes.ManagedTX{} }, 39 | JSONOutputCodes: []int{http.StatusOK, http.StatusAccepted}, 40 | JSONHandler: func(r *ffapi.APIRequest) (output interface{}, err error) { 41 | r.SuccessStatus, output, err = m.requestTransactionSuspend(r.Req.Context(), r.PP["transactionId"]) 42 | return output, err 43 | }, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/fftm/route_post_transaction_suspend_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/go-resty/resty/v2" 24 | "github.com/hyperledger/firefly-transaction-manager/mocks/txhandlermocks" 25 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/mock" 28 | ) 29 | 30 | func TestPostTransactionSuspend(t *testing.T) { 31 | 32 | url, m, done := newTestManager(t) 33 | defer done() 34 | tx := newTestTxn(t, m, "0x0aaaaa", 10001, apitypes.TxStatusSucceeded) 35 | txID := tx.ID 36 | 37 | err := m.Start() 38 | assert.NoError(t, err) 39 | 40 | var txOut *apitypes.ManagedTX 41 | res, err := resty.New().R(). 42 | SetResult(&txOut). 43 | SetBody(struct{}{}). 44 | Post(fmt.Sprintf("%s/transactions/%s/suspend", url, txID)) 45 | assert.NoError(t, err) 46 | assert.Equal(t, 202, res.StatusCode()) 47 | assert.Equal(t, txID, txOut.ID) 48 | } 49 | 50 | func TestPostTransactionSuspendFailed(t *testing.T) { 51 | url, m, done := newTestManager(t) 52 | defer done() 53 | 54 | err := m.Start() 55 | assert.NoError(t, err) 56 | mth := txhandlermocks.TransactionHandler{} 57 | mth.On("HandleSuspendTransaction", mock.Anything, "1234").Return(nil, fmt.Errorf("error")).Once() 58 | m.txHandler = &mth 59 | 60 | var txOut *apitypes.ManagedTX 61 | res, err := resty.New().R(). 62 | SetResult(&txOut). 63 | SetBody(struct{}{}). 64 | Post(fmt.Sprintf("%s/transactions/%s/suspend", url, "1234")) 65 | assert.NoError(t, err) 66 | assert.Equal(t, 500, res.StatusCode()) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/fftm/routes.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2025 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import "github.com/hyperledger/firefly-common/pkg/ffapi" 20 | 21 | func (m *manager) routes() []*ffapi.Route { 22 | return []*ffapi.Route{ 23 | deleteEventStream(m), 24 | deleteEventStreamListener(m), 25 | deleteSubscription(m), 26 | deleteTransaction(m), 27 | getEventStream(m), 28 | getEventStreamListener(m), 29 | getEventStreamListeners(m), 30 | getEventStreams(m), 31 | deprecatedGetStatus(m), 32 | getSubscription(m), 33 | getSubscriptions(m), 34 | deprecatedGetLiveStatus(m), // TODO: remove this route from the API routes, they are already in the monitoring routes 35 | deprecatedGetReadyStatus(m), // TODO: remove this route from the API routes, they are already in the monitoring routes 36 | getTransaction(m), 37 | getTransactionConfirmations(m), 38 | getTransactionHistory(m), 39 | getTransactionReceipt(m), 40 | getTransactions(m), 41 | patchEventStream(m), 42 | patchEventStreamListener(m), 43 | patchSubscription(m), 44 | postEventStream(m), 45 | postEventStreamListenerReset(m), 46 | postEventStreamListeners(m), 47 | postEventStreamResume(m), 48 | postEventStreamSuspend(m), 49 | postRootCommand(m), 50 | postSubscriptionReset(m), 51 | postSubscriptions(m), 52 | getAddressBalance(m), 53 | getGasPrice(m), 54 | postTransactionSuspend(m), 55 | postTransactionResume(m), 56 | } 57 | } 58 | 59 | func (m *manager) monitoringRoutes() []*ffapi.Route { 60 | return []*ffapi.Route{ 61 | getReadiness(m), 62 | getLiveness(m), 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/fftm/status_management.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/log" 23 | "github.com/hyperledger/firefly-transaction-manager/pkg/apitypes" 24 | ) 25 | 26 | func (m *manager) getLiveStatus(ctx context.Context) (resp *apitypes.LiveStatus, err error) { 27 | resp = &apitypes.LiveStatus{} 28 | status, _, err := m.connector.IsLive(ctx) 29 | if err == nil { 30 | resp.LiveResponse = *status 31 | } else { 32 | log.L(ctx).Warnf("Failed to fetch live status: %s", err) 33 | return nil, err 34 | } 35 | return resp, nil 36 | } 37 | 38 | func (m *manager) getReadyStatus(ctx context.Context) (resp *apitypes.ReadyStatus, err error) { 39 | resp = &apitypes.ReadyStatus{} 40 | status, _, err := m.connector.IsReady(ctx) 41 | if err == nil { 42 | resp.ReadyResponse = *status 43 | } else { 44 | log.L(ctx).Warnf("Failed to fetch ready status: %s", err) 45 | return nil, err 46 | } 47 | return resp, nil 48 | } 49 | -------------------------------------------------------------------------------- /pkg/fftm/status_management_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package fftm 18 | 19 | import ( 20 | "fmt" 21 | "github.com/hyperledger/firefly-transaction-manager/mocks/ffcapimocks" 22 | "github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi" 23 | "github.com/stretchr/testify/assert" 24 | "github.com/stretchr/testify/mock" 25 | "testing" 26 | ) 27 | 28 | func TestGetLiveStatusError(t *testing.T) { 29 | _, m, close := newTestManager(t) 30 | defer close() 31 | 32 | mfc := m.connector.(*ffcapimocks.API) 33 | mfc.On("IsLive", mock.Anything, mock.Anything).Return(nil, ffcapi.ErrorReason(""), fmt.Errorf("failed to get live status")) 34 | 35 | _, err := m.getLiveStatus(m.ctx) 36 | assert.Error(t, err) 37 | 38 | mfc.AssertExpectations(t) 39 | } 40 | 41 | func TestGetReadyStatusError(t *testing.T) { 42 | _, m, close := newTestManager(t) 43 | defer close() 44 | 45 | mfc := m.connector.(*ffcapimocks.API) 46 | mfc.On("IsReady", mock.Anything, mock.Anything).Return(nil, ffcapi.ErrorReason(""), fmt.Errorf("failed to get ready status")) 47 | 48 | _, err := m.getReadyStatus(m.ctx) 49 | assert.Error(t, err) 50 | 51 | mfc.AssertExpectations(t) 52 | } 53 | -------------------------------------------------------------------------------- /pkg/txhandler/registry/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package txhandlerfactory 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/hyperledger/firefly-common/pkg/config" 23 | "github.com/hyperledger/firefly-common/pkg/i18n" 24 | "github.com/hyperledger/firefly-transaction-manager/internal/tmconfig" 25 | "github.com/hyperledger/firefly-transaction-manager/internal/tmmsgs" 26 | "github.com/hyperledger/firefly-transaction-manager/pkg/txhandler" 27 | ) 28 | 29 | var txHandlers = make(map[string]Factory) 30 | 31 | func NewTransactionHandler(ctx context.Context, baseConfig config.Section, name string) (txhandler.TransactionHandler, error) { 32 | factory, ok := txHandlers[name] 33 | if !ok { 34 | return nil, i18n.NewError(ctx, tmmsgs.MsgTransactionHandlerNotRegistered, name) 35 | } 36 | return factory.NewTransactionHandler(ctx, baseConfig.SubSection(name)) 37 | } 38 | 39 | type Factory interface { 40 | Name() string 41 | InitConfig(conf config.Section) 42 | NewTransactionHandler(ctx context.Context, conf config.Section) (txhandler.TransactionHandler, error) 43 | } 44 | 45 | func RegisterHandler(factory Factory) string { 46 | name := factory.Name() 47 | txHandlers[name] = factory 48 | // init the new transaction handler configurations 49 | factory.InitConfig(tmconfig.TransactionHandlerBaseConfig.SubSection(name)) 50 | return name 51 | } 52 | -------------------------------------------------------------------------------- /pkg/txhandler/registry/registry_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Kaleido, Inc. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package txhandlerfactory 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | 23 | "github.com/hyperledger/firefly-transaction-manager/internal/tmconfig" 24 | "github.com/hyperledger/firefly-transaction-manager/pkg/txhandler/simple" 25 | "github.com/spf13/viper" 26 | "github.com/stretchr/testify/assert" 27 | ) 28 | 29 | func TestRegistryWithDeprecatedConfig(t *testing.T) { 30 | tmconfig.Reset() 31 | viper.SetDefault(string(tmconfig.DeprecatedPolicyEngineName), "simple") 32 | RegisterHandler(&simple.TransactionHandlerFactory{}) 33 | tmconfig.DeprecatedPolicyEngineBaseConfig.SubSection("simple").Set(simple.FixedGasPrice, "12345") 34 | p, err := NewTransactionHandler(context.Background(), tmconfig.DeprecatedPolicyEngineBaseConfig, "simple") 35 | assert.NotNil(t, p) 36 | assert.NoError(t, err) 37 | 38 | p, err = NewTransactionHandler(context.Background(), tmconfig.DeprecatedPolicyEngineBaseConfig, "bob") 39 | assert.Nil(t, p) 40 | assert.Regexp(t, "FF21070", err) 41 | 42 | } 43 | 44 | func TestRegistry(t *testing.T) { 45 | tmconfig.Reset() 46 | RegisterHandler(&simple.TransactionHandlerFactory{}) 47 | 48 | tmconfig.TransactionHandlerBaseConfig.SubSection("simple").Set(simple.FixedGasPrice, "12345") 49 | p, err := NewTransactionHandler(context.Background(), tmconfig.TransactionHandlerBaseConfig, "simple") 50 | assert.NotNil(t, p) 51 | assert.NoError(t, err) 52 | 53 | p, err = NewTransactionHandler(context.Background(), tmconfig.TransactionHandlerBaseConfig, "bob") 54 | assert.Nil(t, p) 55 | assert.Regexp(t, "FF21070", err) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /test/empty-config.fftm.yaml: -------------------------------------------------------------------------------- 1 | manager: 2 | no-name-set: "should have a name to start" 3 | api: 4 | port: 0 # allocate one -------------------------------------------------------------------------------- /test/firefly.fftm.yaml: -------------------------------------------------------------------------------- 1 | manager: 2 | name: test 3 | policyengine: 4 | simple: 5 | fixedGasPrice: 12345 6 | api: 7 | port: 0 # allocate one -------------------------------------------------------------------------------- /test/quick-fail.fftm.yaml: -------------------------------------------------------------------------------- 1 | manager: 2 | name: test 3 | operations: 4 | fullScan: 5 | startupMaxRetries: 1 6 | minimumDelay: 1ms 7 | policyengine: 8 | simple: 9 | fixedGasPrice: 12345 10 | ffcore: 11 | url: http://localhost:99999 12 | api: 13 | port: 0 # allocate one --------------------------------------------------------------------------------