├── .dockerignore ├── .github └── workflows │ ├── maintest.yml │ ├── quorum.release.yml │ ├── release.yml │ ├── rumcli.release.yml │ ├── swag.yml │ └── update.api.page.yml ├── .gitignore ├── .goreleaser.yaml ├── Dockerfile ├── Dockerfile-goreleaser ├── LICENSE ├── README.md ├── Tutorial.md ├── Tutorial_V2.md ├── arch_info_forppt.png ├── bind_pubkey_with_trx.md ├── cmd ├── backup.go ├── bootstrapnode.go ├── cli │ ├── README.md │ ├── api │ │ ├── api.go │ │ └── def.go │ ├── cache │ │ └── cache.go │ ├── config.default.toml │ ├── config │ │ └── config.go │ ├── main.go │ ├── model │ │ ├── blocks.go │ │ ├── commands.go │ │ ├── network.go │ │ ├── pubqueue.go │ │ └── quorum.go │ ├── ui │ │ ├── command.go │ │ ├── forms.go │ │ ├── modals.go │ │ ├── page_blocks.go │ │ ├── page_chain_config.go │ │ ├── page_group_admin.go │ │ ├── page_help.go │ │ ├── page_network.go │ │ ├── page_pubqueue.go │ │ ├── page_quorum.go │ │ ├── page_welcome.go │ │ └── ui.go │ └── utils │ │ └── utils.go ├── db.go ├── fullnode.go ├── jwt.go ├── lightnode.go ├── ping.go ├── producernode.go ├── relaynode.go ├── restore.go ├── root.go ├── rumfile.go ├── utils.go └── version.go ├── docs.go ├── go.mod ├── go.sum ├── howtotest.md ├── internal └── pkg │ ├── .keep │ ├── appdata │ ├── db.go │ ├── db_test.go │ ├── sync.go │ └── utils_native.go │ ├── chainsdk │ ├── core │ │ ├── chain.go │ │ ├── chaindata.go │ │ ├── group.go │ │ ├── groupmgr.go │ │ ├── rexsyncer.go │ │ └── syncerrunner.go │ └── def │ │ ├── chaindataciface.go │ │ ├── group.go │ │ ├── groupmgr.go │ │ └── trxfactory.go │ ├── cli │ └── flags.go │ ├── conn │ ├── connmgr.go │ ├── p2p │ │ ├── network.go │ │ ├── network_native.go │ │ ├── network_test.go │ │ ├── peerdata │ │ │ ├── BUILD.bazel │ │ │ ├── store.go │ │ │ └── store_test.go │ │ ├── ping.go │ │ ├── psping.go │ │ ├── relayfilter.go │ │ ├── relaynode.go │ │ ├── rumchaindata.go │ │ ├── rumexchange.go │ │ ├── rumpeerstore.go │ │ ├── rumpeerstore_test.go │ │ └── scorers │ │ │ ├── BUILD.bazel │ │ │ ├── bad_responses.go │ │ │ ├── bad_responses_test.go │ │ │ ├── block_providers.go │ │ │ ├── block_providers_test.go │ │ │ ├── peer_status.go │ │ │ ├── peer_status_test.go │ │ │ ├── rpc_errors.go │ │ │ ├── scorers_test.go │ │ │ ├── service.go │ │ │ └── service_test.go │ └── pubsubconn │ │ └── pubsubconn.go │ ├── errors │ ├── error.go │ └── http.go │ ├── logging │ ├── logger_native.go │ └── logging.go │ ├── metric │ ├── prometheus.go │ └── utils.go │ ├── middleware │ ├── jwt_skipper.go │ ├── localhost.go │ └── opa.go │ ├── nodectx │ └── nodectx.go │ ├── options │ ├── options.go │ ├── options_jwt_native.go │ ├── options_native.go │ └── options_relay.go │ ├── payment │ └── README │ ├── storage │ ├── chain │ │ ├── appconfigdb.go │ │ ├── blockdb.go │ │ ├── chainconfigdb.go │ │ ├── chaindb.go │ │ ├── consensusdb.go │ │ ├── groupdb.go │ │ ├── producerdb.go │ │ ├── trxdb.go │ │ └── userdb.go │ ├── dbmgr.go │ ├── def │ │ └── chainstorage.go │ ├── node │ │ └── node_db.go │ ├── prefix.go │ ├── storage.go │ └── storage_native.go │ └── utils │ ├── cert.go │ ├── compress.go │ ├── echo.go │ ├── file.go │ ├── file_copy_native.go │ ├── http.go │ ├── jwt.go │ ├── math_helper.go │ ├── selfupdate.go │ ├── str.go │ ├── utils.go │ ├── utils_test.go │ ├── version.go │ └── zip.go ├── main.go ├── main_test.backup ├── main_test.go ├── makefile ├── pkg ├── .keep ├── autorelay │ ├── api │ │ ├── blacklist.go │ │ ├── disconnect.go │ │ ├── forbid.go │ │ ├── getpermissions.go │ │ └── handler.go │ ├── audit │ │ └── traffic.go │ ├── handlers │ │ ├── blacklist.go │ │ ├── constant.go │ │ ├── disconnect.go │ │ ├── forbid.go │ │ └── getpermissions.go │ └── server.go ├── chainapi │ ├── api │ │ ├── addpeers.go │ │ ├── addpeers_test.go │ │ ├── announce.go │ │ ├── announce_sdk_test.go │ │ ├── appconfig_test.go │ │ ├── autorelay.go │ │ ├── cleargroupdata.go │ │ ├── cleargroupdata_test.go │ │ ├── config.go │ │ ├── creategroup.go │ │ ├── fixture_test.go │ │ ├── get_content_sdk_test.go │ │ ├── get_user_encrypt_pubkeys_test.go │ │ ├── getannouncedgroupproducer.go │ │ ├── getannouncedgroupuser.go │ │ ├── getappconfigitem.go │ │ ├── getappconfigkey.go │ │ ├── getblk.go │ │ ├── getblkbyid_test.go │ │ ├── getbootstrapnodeinfo.go │ │ ├── getbootstrapnodeinfo_test.go │ │ ├── getchaindata_sdk_test.go │ │ ├── getchaintrxallowlist.go │ │ ├── getchaintrxallowlist_test.go │ │ ├── getchaintrxauthmode.go │ │ ├── getchaintrxauthmode_test.go │ │ ├── getchaintrxdenylist.go │ │ ├── getchaintrxdenylist_test.go │ │ ├── getgroupctn_test.go │ │ ├── getgroupproducer.go │ │ ├── getgroups.go │ │ ├── getgroups_test.go │ │ ├── getgroupseed.go │ │ ├── getgroupseed_test.go │ │ ├── getnetwork.go │ │ ├── getnetwork_test.go │ │ ├── getnodeinfo.go │ │ ├── getnodeinfo_test.go │ │ ├── gettrx.go │ │ ├── gettrx_test.go │ │ ├── group_test.go │ │ ├── handle.go │ │ ├── joingroup_test.go │ │ ├── joingroup_v2.go │ │ ├── leavegroup.go │ │ ├── leavegroup_test.go │ │ ├── metrics.go │ │ ├── mgrappconfig.go │ │ ├── mgrchainconfig.go │ │ ├── mgrchainconfig_test.go │ │ ├── nsdk_announce.go │ │ ├── nsdk_appconfig.go │ │ ├── nsdk_auth.go │ │ ├── nsdk_groupctn.go │ │ ├── nsdk_groupinfo.go │ │ ├── nsdk_producer.go │ │ ├── nsdk_sendtrx.go │ │ ├── nsdk_userencryptpubkeys.go │ │ ├── opa_helper.go │ │ ├── opa_policy.go │ │ ├── posttogroup.go │ │ ├── posttogroup_test.go │ │ ├── producer.go │ │ ├── producer_test.go │ │ ├── seed.go │ │ ├── sendtrx_test.go │ │ ├── server.go │ │ ├── signtx.go │ │ ├── startsync.go │ │ ├── tools.go │ │ ├── user.go │ │ └── websocket.go │ ├── appapi │ │ ├── config.go │ │ ├── content.go │ │ ├── handle.go │ │ └── jwt.go │ └── handlers │ │ ├── addpeers.go │ │ ├── announce.go │ │ ├── autorelay.go │ │ ├── backup.go │ │ ├── backup_block.go │ │ ├── backup_check.go │ │ ├── backup_group_seed.go │ │ ├── cleargroupdata.go │ │ ├── config.go │ │ ├── creategroup.go │ │ ├── creategroup_native.go │ │ ├── getannouncedgroupproducer.go │ │ ├── getannouncedgroupuser.go │ │ ├── getappconfigitem.go │ │ ├── getappconfigkey.go │ │ ├── getchaintrxallowlist.go │ │ ├── getchaintrxdenyist.go │ │ ├── getchintrxauthlist.go │ │ ├── getgroupctn.go │ │ ├── getgroupproducer.go │ │ ├── getgroupseed.go │ │ ├── getnetwork.go │ │ ├── getnodeinfo.go │ │ ├── gettrx.go │ │ ├── groupseed.go │ │ ├── leavegroup.go │ │ ├── logger.go │ │ ├── mgrappconfig.go │ │ ├── mgrchainconfig.go │ │ ├── posttogroup.go │ │ ├── producer.go │ │ ├── restore.go │ │ ├── startsync.go │ │ ├── utils.go │ │ └── utils_test.go ├── consensus │ ├── bba.go │ ├── cofig.go │ ├── def │ │ ├── chainiface.go │ │ ├── consensus.go │ │ ├── producer.go │ │ └── user.go │ ├── molasses.go │ ├── molassesproducer.go │ ├── molassesuser.go │ ├── msgsender.go │ ├── rbc.go │ ├── trxacs.go │ ├── trxbft.go │ ├── trxbuffer.go │ └── trxrbc.go ├── constants │ └── network.go ├── crypto │ ├── aes.go │ ├── aes_test.go │ ├── age.go │ ├── age_test.go │ ├── data.go │ ├── dirkeystore.go │ ├── dirkeystore_test.go │ ├── keys.go │ ├── keys_test.go │ ├── keystore.go │ ├── keystore_native.go │ ├── keystore_native_test.go │ ├── keystore_test.go │ ├── passphrase.go │ ├── rand.go │ ├── tools.go │ ├── tools_test.go │ └── wordlist.go ├── data │ ├── block.go │ ├── trx.go │ ├── trx_test.go │ ├── trxfactory.go │ └── util.go ├── makefile ├── nodesdk │ ├── Readme.md │ ├── Tutorial_nodesdk.md │ ├── api │ │ ├── announce.go │ │ ├── bindaliaskeyname.go │ │ ├── config.go │ │ ├── getallalias.go │ │ ├── getallgroups.go │ │ ├── getannouncedusers.go │ │ ├── getapihosturl.go │ │ ├── getappconfigitem.go │ │ ├── getappconfigkey.go │ │ ├── getblock.go │ │ ├── getgroupbyid.go │ │ ├── getgroupctn.go │ │ ├── getgroupinfo.go │ │ ├── getgroupseed.go │ │ ├── getproducers.go │ │ ├── gettrx.go │ │ ├── handle.go │ │ ├── joingroup.go │ │ ├── leavegroup.go │ │ ├── mgrappconfig.go │ │ ├── newkey.go │ │ ├── posttogroup.go │ │ ├── rmalias.go │ │ ├── seed.go │ │ ├── server.go │ │ ├── updapihosturl.go │ │ └── utils.go │ ├── http │ │ └── httpclient.go │ └── nodesdkctx │ │ └── nodesdkctx.go └── pb │ ├── activity_stream.pb.go │ ├── activity_stream.proto │ ├── chain.pb.go │ ├── chain.proto │ ├── rumexchange.pb.go │ ├── rumexchange.proto │ └── utils.go ├── scripts ├── cmd_command ├── env.sh ├── manual_test_local.py ├── protoupdate.sh ├── runbootstrap.sh └── start_node.sh ├── systemd └── quorum.service.sample └── testnode ├── fork.go ├── fork_windows.go ├── setup.go └── utils.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | dist/ 3 | main 4 | quorum 5 | -------------------------------------------------------------------------------- /.github/workflows/maintest.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | - consensus_2_main 6 | - consensus_2_preview 7 | pull_request: 8 | branches: 9 | - main 10 | - consensus_2_main 11 | - consensus_2_preview 12 | 13 | name: MainTest 14 | jobs: 15 | test: 16 | strategy: 17 | matrix: 18 | go-version: [1.19.x, 1.20.x] 19 | os: [ubuntu-latest] 20 | runs-on: ${{ matrix.os }} 21 | steps: 22 | - name: Install Go 23 | uses: actions/setup-go@v2 24 | with: 25 | go-version: ${{ matrix.go-version }} 26 | - name: Checkout code 27 | uses: actions/checkout@v2 28 | - name: ApiTest 29 | run: make test-api 30 | - name: MainTest 31 | run: make test-main 32 | -------------------------------------------------------------------------------- /.github/workflows/quorum.release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [created] 4 | 5 | jobs: 6 | releases-matrix: 7 | name: Release Go Binary 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | # build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64 12 | goos: [linux, windows, darwin] 13 | goarch: ["386", amd64] 14 | exclude: 15 | - goarch: "386" 16 | goos: darwin 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set GIT_COMMIT env 20 | run: echo GIT_COMMIT=$(git rev-parse --short ${GITHUB_SHA}) >> ${GITHUB_ENV} 21 | - name: Set RELEASE_TAG env 22 | run: echo RELEASE_TAG=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV} 23 | - uses: chux0519/go-release-action@v2.5.0 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | # only needs to set following 2 secrets 27 | signify_sec_key: ${{ secrets.SIGNIFY_SEC_KEY }} 28 | signify_sec_key_pass: ${{ secrets.SIGNIFY_SEC_KEY_PASS }} 29 | signify: TRUE 30 | qingcloud: TRUE 31 | qingcloud_config: ${{ secrets.QINGCLOUD_CONFIG }} 32 | qingcloud_bucket: ${{ secrets.QINGCLOUD_BUCKET }} 33 | project_path: "./" 34 | source_files: "main.go" 35 | ldflags: "-X main.GitCommit=${{ env.GIT_COMMIT }} -X main.ReleaseVersion=${{ env.RELEASE_TAG }}" 36 | binary_name: "quorum" 37 | goos: ${{ matrix.goos }} 38 | goarch: ${{ matrix.goarch }} 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | goreleaser: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - name: Set up Go 20 | uses: actions/setup-go@v3 21 | with: 22 | go-version: ">=1.19.0" 23 | - name: Run GoReleaser 24 | uses: goreleaser/goreleaser-action@v4 25 | with: 26 | distribution: goreleaser 27 | version: latest 28 | args: release --clean 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/rumcli.release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [created] 4 | 5 | jobs: 6 | releases-matrix: 7 | name: Release Go Binary 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | # build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64 12 | goos: [linux, windows, darwin] 13 | goarch: ["386", amd64] 14 | exclude: 15 | - goarch: "386" 16 | goos: darwin 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set GIT_COMMIT env 20 | run: echo GIT_COMMIT=$(git rev-parse --short ${GITHUB_SHA}) >> ${GITHUB_ENV} 21 | - name: Set RELEASE_TAG env 22 | run: echo RELEASE_TAG=$(basename ${GITHUB_REF}) >> ${GITHUB_ENV} 23 | - uses: chux0519/go-release-action@v2.5.0 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | # only needs to set following 2 secrets 27 | signify_sec_key: ${{ secrets.SIGNIFY_SEC_KEY }} 28 | signify_sec_key_pass: ${{ secrets.SIGNIFY_SEC_KEY_PASS }} 29 | signify: TRUE 30 | qingcloud: TRUE 31 | qingcloud_config: ${{ secrets.QINGCLOUD_CONFIG }} 32 | qingcloud_bucket: ${{ secrets.QINGCLOUD_BUCKET }} 33 | project_path: "./cmd/cli" 34 | ldflags: "-X main.GitCommit=${{ env.GIT_COMMIT }} -X main.ReleaseVersion=${{ env.RELEASE_TAG }}" 35 | binary_name: "rumcli" 36 | goos: ${{ matrix.goos }} 37 | goarch: ${{ matrix.goarch }} 38 | -------------------------------------------------------------------------------- /.github/workflows/swag.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Swag Doc 3 | 4 | jobs: 5 | doc: 6 | strategy: 7 | matrix: 8 | go-version: [1.19.x, 1.20.x] 9 | os: [ubuntu-latest] 10 | runs-on: ${{ matrix.os }} 11 | steps: 12 | - name: Install Go 13 | uses: actions/setup-go@v2 14 | with: 15 | go-version: ${{ matrix.go-version }} 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | - name: Swag 19 | run: | 20 | make gen-doc 21 | -------------------------------------------------------------------------------- /.github/workflows/update.api.page.yml: -------------------------------------------------------------------------------- 1 | name: Update Quorum Api Github Page 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | update: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - name: Install Go 13 | uses: actions/setup-go@v2 14 | with: 15 | go-version: ">=1.19.0" 16 | 17 | - name: Checkout quorum repo 18 | uses: actions/checkout@v3 19 | 20 | - name: Swag Init 21 | run: | 22 | go install github.com/swaggo/swag/cmd/swag@v1.7.0 23 | make gen-doc 24 | 25 | - name: Check swagger.json generated 26 | id: check_files 27 | uses: andstor/file-existence-action@v1.1.0 28 | with: 29 | files: "docs/swagger.json" 30 | 31 | - name: Quit workflow when generating swagger.json failure 32 | if: steps.check_files.outputs.files_exists == 'false' 33 | run: | 34 | echo swag init failure 35 | exit 1 36 | 37 | - name: Upload swagger.json to artifact 38 | uses: actions/upload-artifact@v3 39 | with: 40 | name: quorum-artifact 41 | path: docs/swagger.json 42 | 43 | - name: Checkout quorum-api repo 44 | uses: actions/checkout@v3 45 | with: 46 | repository: rumsystem/quorum-api 47 | ssh-key: ${{ secrets.QUORUM_API_ACCESS_KEY }} 48 | 49 | - name: Download swagger.json from artifact 50 | uses: actions/download-artifact@v3 51 | with: 52 | name: quorum-artifact 53 | path: docs 54 | 55 | - name: Commit and Push 56 | run: | 57 | git config user.name github-actions 58 | git config user.email github-actions@github.com 59 | git add . 60 | git diff-index --quiet HEAD || git commit -m "generated from $(git rev-parse --short ${GITHUB_SHA}) of quorum repo" 61 | git push 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go ### 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # ide 16 | .idea/ 17 | 18 | /docs 19 | /config 20 | /data 21 | /testscripts 22 | dist/ 23 | certs/ 24 | main 25 | *.patch 26 | jsontracer*.json 27 | .DS_Store 28 | keystore 29 | *.ps1 30 | 31 | dist/ 32 | .env 33 | .envrc 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine AS build 2 | RUN addgroup -S quorum && adduser -S -G quorum quorum 3 | RUN apk add build-base 4 | RUN apk add git 5 | WORKDIR /src 6 | COPY . . 7 | RUN make linux 8 | 9 | FROM scratch 10 | WORKDIR / 11 | COPY --from=build /src/dist/quorum_linux_amd64_v1/quorum /quorum 12 | EXPOSE 8000 13 | EXPOSE 8001 14 | EXPOSE 8002 15 | USER quorum:quorum 16 | ENTRYPOINT ["/quorum"] 17 | -------------------------------------------------------------------------------- /Dockerfile-goreleaser: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | WORKDIR / 3 | COPY quorum /quorum 4 | EXPOSE 8000 5 | EXPOSE 8001 6 | EXPOSE 8002 7 | USER quorum:quorum 8 | ENTRYPOINT ["/quorum"] 9 | -------------------------------------------------------------------------------- /arch_info_forppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rumsystem/quorum/75f766f68132fdaaac7885de5b2b1fd507389ae6/arch_info_forppt.png -------------------------------------------------------------------------------- /bind_pubkey_with_trx.md: -------------------------------------------------------------------------------- 1 | 定义: 2 | 发布者:创作并发布内容 3 | 阅读者:付费并阅读发布者发布的内容 4 | 代理节点:被发布者挑选并信任,负责存储发布者发布的trx,并未阅读者提供加密过的内容 5 | 支付服务:被发布者挑选和信任,收取阅读者支付的费用并产生支付凭证 6 | 托管网关:发布者将自己的私钥存在托管网关,该网关可以代替发布者进行签名,可以实现根据支付网关凭证,给阅读者授权等功能 7 | 8 | 注意:支付网关,代理节点,托管网关是概念上的定义 9 | 10 | 流程: 11 | 1. 代理节点将自己的轻节点URI和pubkey通过 ANNOUNCE_CONTENT_PROXY trx发送到链上 12 | 2. 内容发布者可以通过 get_announced_content_proxy获得当前链上的代理节点列表 13 | 3. 内容发布者挑选一个或多个当前链上(group)受信任的代理节点 14 | 4. 发送者创作内容, 15 | 5. 内容发送者(或托管网关)将内容使用hybird加密,对选出的受信任代理节点的pubkey(和自己的pubkey)进行加密,生成密文,发送POST trx,将密文上链 16 | 6. 代理节点通过新的block,获得含有该密文的trx 17 | 7. 代理节点判断是否代理该trx(出于一些原因,代理节点可能并不想给发布者提供服务) 18 | 8. 如果代理节点同意代理该trx,则通过PROXY_APPROVED trx,将自己将代理这个trx并愿意提供内容的 trx发送到链上 19 | 8. 阅读者购买某个内容(trx)并付费 20 | 9. 支付服务帮助发布者收费并生成凭证 21 | 10. 发布者在收费成功之后,通过发送(或由托管网关发送) BINDING_TRX_WITH_PUBKEY trx,将 {阅读者提供的pubkey,某个trx_id}键值对发送到链上 22 | 11. 阅读者通过某个全节点提供的轻节点URI查询到 代理某个trx (by trx_id)的代理节点列表 23 | 12. 阅读者通过某个代理节点请求该trx的内容,提供自己的pubkey和签名 24 | 13. 代理节点查询该pubkey是否已经和该trx_id绑定 25 | 14. 如已成功绑定,则代理节点用自己的pubkey将该内容解密,并用阅读者提供的pubkey加密,并将trx content反还给阅读者 26 | 15. 阅读者用自己pubkey对应的私钥将该密文解密并阅读 27 | 28 | 29 | -------------------------------------------------------------------------------- /cmd/backup.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | // backupCmd represents the backup command 9 | var backupCmd = &cobra.Command{ 10 | Use: "backup", 11 | Short: "Backup rum data", 12 | Run: func(cmd *cobra.Command, args []string) { 13 | params := handlers.BackupParam{ 14 | Peername: peerName, 15 | Password: keystorePassword, 16 | ConfigDir: configDir, 17 | KeystoreDir: keystoreDir, 18 | KeystoreName: keystoreName, 19 | DataDir: dataDir, 20 | SeedDir: seedDir, 21 | BackupFile: backupFile, 22 | } 23 | 24 | handlers.Backup(params) 25 | }, 26 | } 27 | 28 | func init() { 29 | rootCmd.AddCommand(backupCmd) 30 | 31 | flags := backupCmd.Flags() 32 | flags.SortFlags = false 33 | 34 | flags.StringVar(&peerName, "peername", "peer", "peer name") 35 | flags.StringVar(&configDir, "configdir", "config", "config dir") 36 | flags.StringVar(&keystoreDir, "keystoredir", "keystore", "keystore dir") 37 | flags.StringVar(&keystoreName, "keystorename", "defaultkeystore", "keystore name") 38 | flags.StringVar(&keystorePassword, "keystorepass", "", "keystore password") 39 | 40 | flags.StringVar(&dataDir, "datadir", "data", "data dir") 41 | flags.StringVar(&seedDir, "seeddir", "seeds", "seed dir") 42 | flags.StringVar(&backupFile, "file", "", "backup filename") 43 | 44 | backupCmd.MarkFlagRequired("file") 45 | } 46 | -------------------------------------------------------------------------------- /cmd/cli/cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/adrg/xdg" 9 | "github.com/rumsystem/quorum/cmd/cli/config" 10 | "github.com/rumsystem/quorum/internal/pkg/storage" 11 | ) 12 | 13 | type QuorumDataCache struct { 14 | db *storage.Store 15 | } 16 | 17 | var QCache *QuorumDataCache 18 | 19 | func GetUserProfileKey(group string, pubkey string) string { 20 | return fmt.Sprintf("profile_%s_%s", group, pubkey) 21 | } 22 | 23 | func Init() { 24 | // $XDG_DATA_HOME/rumcli/data 25 | path, err := xdg.DataFile("rumcli/data") 26 | if err != nil { 27 | config.Logger.Fatalf(err.Error()) 28 | } 29 | if QCache == nil { 30 | ctx := context.Background() 31 | bucket := "cache" 32 | db, err := storage.NewStore(ctx, path, bucket) 33 | if err != nil { 34 | config.Logger.Errorf("Failed to open cache db: %s", err.Error()) 35 | } 36 | QCache = &QuorumDataCache{db} 37 | config.Logger.Infof("cache db opened") 38 | } 39 | } 40 | 41 | func (cache *QuorumDataCache) Set(key []byte, value []byte) { 42 | if cache != nil && cache.db != nil { 43 | if err := cache.db.Set(key, value); err != nil { 44 | config.Logger.Errorf("Failed to Set: %s\n", err.Error()) 45 | } else { 46 | config.Logger.Infof("cache %s setted", string(key)) 47 | } 48 | } 49 | } 50 | 51 | func (cache *QuorumDataCache) Get(key []byte) ([]byte, error) { 52 | if cache != nil && cache.db != nil { 53 | return cache.db.Get(key) 54 | } 55 | return nil, errors.New("Not found") 56 | } 57 | 58 | func (cache *QuorumDataCache) StartSync(interval int) { 59 | if cache != nil { 60 | } 61 | } 62 | 63 | func (cache *QuorumDataCache) StopSync() { 64 | if cache != nil { 65 | } 66 | } 67 | 68 | func Shutdown() { 69 | if QCache != nil && QCache.db != nil { 70 | QCache.db.Close() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /cmd/cli/config.default.toml: -------------------------------------------------------------------------------- 1 | [Quorum] 2 | Server = "http://127.0.0.1:8002" 3 | JWT = "" 4 | Muted = [] 5 | -------------------------------------------------------------------------------- /cmd/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | 8 | "github.com/rumsystem/quorum/cmd/cli/cache" 9 | "github.com/rumsystem/quorum/cmd/cli/config" 10 | "github.com/rumsystem/quorum/cmd/cli/ui" 11 | "github.com/rumsystem/quorum/internal/pkg/logging" 12 | "github.com/rumsystem/quorum/internal/pkg/utils" 13 | ) 14 | 15 | var ( 16 | ReleaseVersion string 17 | GitCommit string 18 | ) 19 | 20 | func main() { 21 | if ReleaseVersion == "" { 22 | ReleaseVersion = "0.0.0" 23 | } 24 | if GitCommit == "" { 25 | GitCommit = "devel" 26 | } 27 | version := flag.Bool("version", false, "Show the version") 28 | update := flag.Bool("update", false, "Update to the latest version") 29 | updateFrom := flag.String("from", "qingcloud", "Update from: github/qingcloud, default to qingcloud") 30 | configPath := flag.String("config", "", "Default to $XDG_CONFIG_HOME/rumcli/config.toml") 31 | 32 | flag.Parse() 33 | 34 | if *version { 35 | fmt.Printf("%s - %s\n", ReleaseVersion, GitCommit) 36 | return 37 | } 38 | 39 | if *update { 40 | mainLog := logging.Logger("main") 41 | lvl, _ := logging.LevelFromString("info") 42 | logging.SetAllLoggers(lvl) 43 | 44 | err := errors.New(fmt.Sprintf("invalid `-from`: %s", *updateFrom)) 45 | if *updateFrom == "qingcloud" { 46 | err = utils.CheckUpdateQingCloud(ReleaseVersion, "rumcli") 47 | } else if *updateFrom == "github" { 48 | err = utils.CheckUpdate(ReleaseVersion, "rumcli") 49 | } 50 | if err != nil { 51 | mainLog.Fatalf("Failed to do self-update: %s\n", err.Error()) 52 | } 53 | return 54 | } 55 | 56 | config.Init(*configPath) 57 | cache.Init() 58 | ui.Init() 59 | 60 | if err := ui.App.Run(); err != nil { 61 | panic(err) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /cmd/cli/ui/ui.go: -------------------------------------------------------------------------------- 1 | package ui 2 | 3 | import ( 4 | "runtime" 5 | 6 | "code.rocketnine.space/tslocum/cbind" 7 | "code.rocketnine.space/tslocum/cview" 8 | "github.com/gdamore/tcell/v2" 9 | "github.com/rumsystem/quorum/cmd/cli/cache" 10 | "github.com/rumsystem/quorum/cmd/cli/config" 11 | ) 12 | 13 | var App = cview.NewApplication() 14 | 15 | // root panels contains about page and main group page 16 | var rootPanels = cview.NewPanels() 17 | 18 | // root layout 19 | var layout = cview.NewFlex() 20 | 21 | // terminal size 22 | var termW, termH int 23 | 24 | func wrapGlobal(f func()) func(ev *tcell.EventKey) *tcell.EventKey { 25 | return func(ev *tcell.EventKey) *tcell.EventKey { 26 | if !cmdMode && !formMode { 27 | f() 28 | return nil 29 | } 30 | return ev 31 | } 32 | } 33 | 34 | func Init() { 35 | cmdInputInit() 36 | modalInit() 37 | formInit() 38 | 39 | helpPageInit() 40 | welcomePageInit() 41 | blocksPageInit() 42 | quorumPageInit() 43 | adminPageInit() 44 | chainConfigPageInit() 45 | networkPageInit() 46 | pubqueuePageInit() 47 | 48 | // display groups 49 | App.EnableMouse(false) 50 | App.SetAfterResizeFunc(func(width int, height int) { 51 | termW = width 52 | termH = height 53 | // TODO: rerender 54 | }) 55 | 56 | layout.SetDirection(cview.FlexRow) 57 | layout.AddItem(rootPanels, 0, 1, true) 58 | layout.AddItem(cmdInput, 1, 1, false) 59 | 60 | App.SetRoot(layout, true) 61 | 62 | gInputHandler := cbind.NewConfiguration() 63 | gInputHandler.SetRune(tcell.ModNone, 'q', wrapGlobal(shutdown)) 64 | if runtime.GOOS == "windows" { 65 | gInputHandler.Set("Shift+?", wrapGlobal(Help)) 66 | } else { 67 | gInputHandler.SetRune(tcell.ModNone, '?', wrapGlobal(Help)) 68 | } 69 | gInputHandler.SetRune(tcell.ModNone, ' ', wrapGlobal(cmdActivate)) 70 | 71 | App.SetInputCapture(gInputHandler.Capture) 72 | 73 | if config.RumConfig.Quorum.Server != "" { 74 | Quorum(config.RumConfig.Quorum.Server) 75 | } else { 76 | Welcome() 77 | } 78 | } 79 | 80 | func shutdown() { 81 | // Graceful shutdown 82 | cache.Shutdown() 83 | config.Save() 84 | App.Stop() 85 | } 86 | -------------------------------------------------------------------------------- /cmd/cli/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/rumsystem/quorum/cmd/cli/api" 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | ) 9 | 10 | // this function will check trx in pubqueue 11 | // once success, it will ack 12 | // also, it will ack trx which failed > 10 times 13 | func CheckTrx(groupId string, trxId string, status string) ([]string, error) { 14 | select { 15 | case <-time.After(30 * time.Second): 16 | qInfo, err := api.GetPubQueue(groupId, trxId, status) 17 | if err != nil { 18 | return nil, err 19 | } 20 | if len(qInfo.Data) == 0 { 21 | return nil, nil 22 | } 23 | successed := []string{} 24 | rejected := []string{} 25 | for _, item := range qInfo.Data { 26 | if item.State == chain.PublishQueueItemStateSuccess { 27 | successed = append(successed, item.Trx.TrxId) 28 | } 29 | if item.RetryCount > chain.MAX_RETRY_COUNT && item.State == chain.PublishQueueItemStateFail { 30 | rejected = append(rejected, item.Trx.TrxId) 31 | } 32 | } 33 | 34 | acked := append(successed, rejected...) 35 | if len(acked) > 0 { 36 | _, err = api.PubQueueAck(acked) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return acked, nil 41 | } 42 | return nil, nil 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cmd/ping.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/libp2p/go-libp2p" 8 | peerstore "github.com/libp2p/go-libp2p/core/peer" 9 | "github.com/rumsystem/quorum/internal/pkg/cli" 10 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var pingCmd = &cobra.Command{ 15 | Use: "ping", 16 | Short: "Ping peer", 17 | Run: func(cmd *cobra.Command, args []string) { 18 | ping(peerList) 19 | }, 20 | } 21 | 22 | func init() { 23 | rootCmd.AddCommand(pingCmd) 24 | 25 | flags := pingCmd.Flags() 26 | flags.SortFlags = false 27 | flags.VarP(&peerList, "peer", "p", "peer address") 28 | pingCmd.MarkFlagRequired("peer") 29 | } 30 | 31 | func ping(peerList cli.AddrList) { 32 | tcpAddr := "/ip4/127.0.0.1/tcp/0" 33 | wsAddr := "/ip4/127.0.0.1/tcp/0/ws" 34 | ctx := context.Background() 35 | node, err := libp2p.New( 36 | libp2p.ListenAddrStrings(tcpAddr, wsAddr), 37 | libp2p.Ping(false), 38 | ) 39 | if err != nil { 40 | logger.Fatal(err) 41 | } 42 | 43 | // configure our ping protocol 44 | pingService := &p2p.PingService{Host: node} 45 | node.SetStreamHandler(p2p.PingID, pingService.PingHandler) 46 | 47 | for _, addr := range peerList { 48 | peer, err := peerstore.AddrInfoFromP2pAddr(addr) 49 | if err != nil { 50 | logger.Fatal(err) 51 | } 52 | 53 | if err := node.Connect(ctx, *peer); err != nil { 54 | logger.Fatal(err) 55 | } 56 | ch := pingService.Ping(ctx, peer.ID) 57 | fmt.Println() 58 | fmt.Println("pinging remote peer at", addr) 59 | for i := 0; i < 4; i++ { 60 | res := <-ch 61 | fmt.Println("PING", addr, "in", res.RTT) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/utils" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | // versionCmd represents the version command 11 | var versionCmd = &cobra.Command{ 12 | Use: "version", 13 | Short: "Show version", 14 | Run: func(cmd *cobra.Command, args []string) { 15 | version := fmt.Sprintf("%s - %s", utils.ReleaseVersion, utils.GitCommit) 16 | fmt.Println(version) 17 | }, 18 | } 19 | 20 | func init() { 21 | rootCmd.AddCommand(versionCmd) 22 | } 23 | -------------------------------------------------------------------------------- /docs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/labstack/echo/v4" 5 | _ "github.com/rumsystem/quorum/docs" // docs is generated by Swag CLI, you have to import it. 6 | echoSwagger "github.com/swaggo/echo-swagger" 7 | ) 8 | 9 | func main() { 10 | e := echo.New() 11 | e.HideBanner = true 12 | e.GET("/*", echoSwagger.WrapHandler) 13 | 14 | e.Logger.Fatal(e.Start(":1323")) 15 | } 16 | -------------------------------------------------------------------------------- /internal/pkg/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rumsystem/quorum/75f766f68132fdaaac7885de5b2b1fd507389ae6/internal/pkg/.keep -------------------------------------------------------------------------------- /internal/pkg/appdata/utils_native.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package appdata 5 | 6 | import ( 7 | "context" 8 | 9 | "github.com/rumsystem/quorum/internal/pkg/storage" 10 | ) 11 | 12 | func CreateAppDb(path string) (*AppDb, error) { 13 | ctx := context.Background() 14 | db, err := storage.NewStore(ctx, path, "appdb") 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | app := NewAppDb() 20 | app.Db = db 21 | app.DataPath = path 22 | return app, nil 23 | } 24 | -------------------------------------------------------------------------------- /internal/pkg/chainsdk/core/syncerrunner.go: -------------------------------------------------------------------------------- 1 | package chain 2 | 3 | /* 4 | func (sr *SyncerRunner) GetSyncCnsusTask(args ...interface{}) (*SyncTask, error) { 5 | syncerrunner_log.Debugf("<%s> GetConsensusSyncTask called", sr.groupId) 6 | taskmate := PSyncTask{SessionId: uuid.NewString()} 7 | return &SyncTask{TaskId: taskmate.SessionId, Type: PSync, RetryCount: 0, Meta: taskmate}, nil 8 | } 9 | 10 | 11 | func (sr *SyncerRunner) GetSyncLocalTask(args ...interface{}) (*SyncTask, error) { 12 | return nil, nil 13 | } 14 | */ 15 | 16 | /* 17 | else if task.Type == PSync { 18 | psynctask, ok := task.Meta.(PSyncTask) 19 | if !ok { 20 | gsyncer_log.Errorf("<%s> Unsupported task %s", sr.groupId, task.TaskId) 21 | return fmt.Errorf("<%s> Unsupported task %s", sr.groupId, task.TaskId) 22 | } 23 | 24 | syncerrunner_log.Debugf("<%s> TaskSender with PSync Task, SessionId <%s>", sr.groupId, psynctask.SessionId) 25 | 26 | //create psyncReqMsg 27 | psyncReqMsg := &quorumpb.PSyncReq{ 28 | GroupId: sr.groupId, 29 | SessionId: psynctask.SessionId, 30 | SenderPubkey: sr.chainCtx.groupItem.UserSignPubkey, 31 | MyEpoch: sr.chainCtx.GetCurrEpoch(), 32 | } 33 | 34 | //sign it 35 | bbytes, err := proto.Marshal(psyncReqMsg) 36 | if err != nil { 37 | return err 38 | } 39 | 40 | msgHash := localcrypto.Hash(bbytes) 41 | 42 | var signature []byte 43 | ks := localcrypto.GetKeystore() 44 | signature, err = ks.EthSignByKeyName(sr.groupId, msgHash, sr.nodename) 45 | 46 | if err != nil { 47 | return err 48 | } 49 | 50 | if len(signature) == 0 { 51 | return fmt.Errorf("create signature failed") 52 | } 53 | 54 | psyncReqMsg.SenderSign = signature 55 | 56 | payload, _ := proto.Marshal(psyncReqMsg) 57 | psyncMsg := &quorumpb.PSyncMsg{ 58 | MsgType: quorumpb.PSyncMsgType_PSYNC_REQ, 59 | Payload: payload, 60 | } 61 | 62 | connMgr, err := conn.GetConn().GetConnMgr(sr.groupId) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | err = connMgr.BroadcastPSyncMsg(psyncMsg) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | return nil 73 | } 74 | 75 | return fmt.Errorf("<%s> Unsupported task type %s", sr.groupId, task.TaskId) 76 | */ 77 | -------------------------------------------------------------------------------- /internal/pkg/chainsdk/def/chaindataciface.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p/core/network" 5 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 6 | ) 7 | 8 | type ChainDataSyncIface interface { 9 | HandlePsConnMessage(pkg *quorumpb.Package) error 10 | HandleTrxPsConn(trx *quorumpb.Trx) error 11 | HandleBlockPsConn(block *quorumpb.Block) error 12 | HandleTrxRex(trx *quorumpb.Trx, fromstream network.Stream) error 13 | HandleBlockRex(block *quorumpb.Block, fromstream network.Stream) error 14 | HandleHBPsConn(hb *quorumpb.HBMsgv1) error 15 | HandleHBRex(hb *quorumpb.HBMsgv1) error 16 | GetCurrBlockId() uint64 17 | } 18 | -------------------------------------------------------------------------------- /internal/pkg/chainsdk/def/group.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 5 | ) 6 | 7 | type GroupIface interface { 8 | SendRawTrx(trx *quorumpb.Trx) (string, error) 9 | GetTrx(trxId string) (*quorumpb.Trx, error) 10 | GetTrxFromCache(trxId string) (*quorumpb.Trx, error) 11 | GetRexSyncerStatus() string 12 | StartSync(restart bool) error 13 | StopSync() error 14 | } 15 | 16 | type RexSyncResult struct { 17 | Provider string 18 | FromBlock uint64 19 | BlockProvided int32 20 | SyncResult string 21 | LastSyncTaskTimestamp int64 22 | NextSyncTaskTimeStamp int64 23 | } 24 | -------------------------------------------------------------------------------- /internal/pkg/chainsdk/def/groupmgr.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | type GroupMgrIface interface { 4 | GetGroup(groupId string) (GroupIface, error) 5 | } 6 | -------------------------------------------------------------------------------- /internal/pkg/chainsdk/def/trxfactory.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 5 | ) 6 | 7 | type TrxFactoryIface interface { 8 | GetAnnounceTrx(keyalias string, item *quorumpb.AnnounceItem) (*quorumpb.Trx, error) 9 | GetChainConfigTrx(keyalias string, item *quorumpb.ChainConfigItem) (*quorumpb.Trx, error) 10 | GetRegProducerBundleTrx(keyalias string, item *quorumpb.BFTProducerBundleItem) (*quorumpb.Trx, error) 11 | GetUpdAppConfigTrx(keyalias string, item *quorumpb.AppConfigItem) (*quorumpb.Trx, error) 12 | GetRegUserTrx(keyalias string, item *quorumpb.UserItem) (*quorumpb.Trx, error) 13 | GetPostAnyTrx(keyalias string, content []byte, encryptto ...[]string) (*quorumpb.Trx, error) 14 | GetReqBlocksTrx(keyalias string, groupId string, fromBlock uint64, blkReq int32) (*quorumpb.Trx, error) 15 | GetReqBlocksRespTrx(keyalias string, groupId string, requester string, fromBlock uint64, blkReq int32, blocks []*quorumpb.Block, result quorumpb.ReqBlkResult) (*quorumpb.Trx, error) 16 | } 17 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/network_test.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package p2p 5 | 6 | import ( 7 | "context" 8 | "testing" 9 | "time" 10 | 11 | "github.com/rumsystem/quorum/testnode" 12 | ) 13 | 14 | func TestNodeConnecting(t *testing.T) { 15 | ctx, cancel := context.WithCancel(context.Background()) 16 | defer cancel() 17 | 18 | mockRendezvousString := "testrendezvousuniqstring" 19 | bootstrap, peer1, peer2, _, _, _, err := testnode.Run2nodes(ctx, mockRendezvousString) 20 | if err != nil { 21 | t.Errorf("create test peers err:%s", err) 22 | } 23 | 24 | networklog.Debugf("bootstrap id: %s", bootstrap.Host.ID()) 25 | networklog.Debugf("peer1 id: %s", peer1.Host.ID()) 26 | networklog.Debugf("peer2 id: %s", peer2.Host.ID()) 27 | 28 | networklog.Debug("Waitting 10s for finding peers testing...") 29 | time.Sleep(10 * time.Second) 30 | peer1info, err := peer1.FindPeers(ctx, mockRendezvousString) 31 | if err != nil { 32 | t.Errorf("Find peer1 peers err:%s", err) 33 | } 34 | peer2info, err := peer2.FindPeers(ctx, mockRendezvousString) 35 | if err != nil { 36 | t.Errorf("Find peer2 peers err:%s", err) 37 | } 38 | if len(peer2info) == len(peer1info) && len(peer1info) == 2 { 39 | for _, p2 := range peer2info { 40 | peerexist := false 41 | networklog.Debugf("check addr %s", p2) 42 | for _, p1 := range peer1info { 43 | if p1.String() == p2.String() { 44 | peerexist = true 45 | networklog.Debugf("addr %s exist", p2) 46 | } 47 | } 48 | if peerexist != true { 49 | t.Errorf("peer2 address not exist in the peer1 %s", p2.String()) 50 | } 51 | } 52 | } else { 53 | t.Errorf("Findpeers peer1 != peer2 %s %s", peer1info, peer2info) 54 | } 55 | 56 | cancel() 57 | 58 | timer2 := time.NewTimer(time.Second * 30) 59 | go func() { 60 | <-timer2.C 61 | cancel() 62 | }() 63 | 64 | select { 65 | case <-ctx.Done(): 66 | ("cancel all nodes after 60s") 67 | return 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/peerdata/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@prysm//tools/go:def.bzl", "go_library", "go_test") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["store.go"], 6 | importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/peers/peerdata", 7 | visibility = ["//beacon-chain:__subpackages__"], 8 | deps = [ 9 | "//proto/prysm/v1alpha1:go_default_library", 10 | "//proto/prysm/v1alpha1/metadata:go_default_library", 11 | "@com_github_ethereum_go_ethereum//p2p/enr:go_default_library", 12 | "@com_github_libp2p_go_libp2p//core/network:go_default_library", 13 | "@com_github_libp2p_go_libp2p//core/peer:go_default_library", 14 | "@com_github_multiformats_go_multiaddr//:go_default_library", 15 | ], 16 | ) 17 | 18 | go_test( 19 | name = "go_default_test", 20 | srcs = ["store_test.go"], 21 | deps = [ 22 | ":go_default_library", 23 | "//testing/assert:go_default_library", 24 | "//testing/require:go_default_library", 25 | "@com_github_libp2p_go_libp2p//core/peer:go_default_library", 26 | ], 27 | ) 28 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/relayfilter.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p/core/peer" 5 | "github.com/rumsystem/quorum/internal/pkg/storage" 6 | "github.com/rumsystem/quorum/pkg/autorelay/handlers" 7 | 8 | ma "github.com/multiformats/go-multiaddr" 9 | ) 10 | 11 | type QuorumRelayFilter struct { 12 | db storage.QuorumStorage 13 | } 14 | 15 | func NewQuorumRelayFilter(db storage.QuorumStorage) *QuorumRelayFilter { 16 | rf := QuorumRelayFilter{db} 17 | return &rf 18 | } 19 | 20 | func (rf *QuorumRelayFilter) AllowReserve(p peer.ID, a ma.Multiaddr) bool { 21 | // we always allow reservation 22 | return true 23 | } 24 | 25 | func (rf *QuorumRelayFilter) AllowConnect(src peer.ID, srcAddr ma.Multiaddr, dest peer.ID) bool { 26 | // check wheter remote peer can connect to local peer 27 | // once traffic of a dest peer exceeds its limit, we dont allow connect to the peer anymore 28 | // ps: src peer is the remote peer, so dest peer is the server peer 29 | permission, err := handlers.GetPermissions(rf.db, dest.String()) 30 | if err != nil { 31 | networklog.Errorf("getDestConnectPermission failed: %s:", err.Error()) 32 | return false 33 | } 34 | 35 | if !permission.AllowConnect { 36 | // maybe server peer is out of money/traffic 37 | return false 38 | } 39 | 40 | // check whether the remote peer is in the blacklist of server peer 41 | // should check both side, cause connection could be bio connection 42 | inBlacklist, err := handlers.CheckBlacklist(rf.db, dest.String(), src.String()) 43 | if err != nil { 44 | // db error, we abort connect by now 45 | return false 46 | } 47 | inBlacklistRev, err := handlers.CheckBlacklist(rf.db, src.String(), dest.String()) 48 | if err != nil { 49 | // db error, we abort connect by now 50 | return false 51 | } 52 | 53 | return !inBlacklist && !inBlacklistRev 54 | } 55 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/rumchaindata.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/libp2p/go-libp2p/core/network" 7 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 8 | "google.golang.org/protobuf/proto" 9 | ) 10 | 11 | type RexChainData struct { 12 | rex *RexService 13 | } 14 | 15 | func NewRexChainData(rex *RexService) *RexChainData { 16 | return &RexChainData{rex: rex} 17 | } 18 | 19 | func (r *RexChainData) Handler(rummsg *quorumpb.RumDataMsg, s network.Stream) error { 20 | frompeerid := s.Conn().RemotePeer() 21 | pkg := rummsg.DataPackage 22 | 23 | if pkg.Type == quorumpb.PackageType_TRX { 24 | rumexchangelog.Debugf("receive a trx, from %s", frompeerid) 25 | trx := &quorumpb.Trx{} 26 | err := proto.Unmarshal(pkg.Data, trx) 27 | if err == nil { 28 | targetchain, ok := r.rex.chainmgr[trx.GroupId] 29 | if ok == true { 30 | return targetchain.HandleTrxRex(trx, s) 31 | } else { 32 | rumexchangelog.Warningf("receive a group unknown package, groupid: %s from: %s", trx.GroupId, frompeerid) 33 | } 34 | } else { 35 | rumexchangelog.Warningf(err.Error()) 36 | } 37 | } else { 38 | rumexchangelog.Warningf("receive a non-trx package, %s", pkg.Type) 39 | } 40 | 41 | return fmt.Errorf("unsupported trx type: %s", pkg.Type) 42 | } 43 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/scorers/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@prysm//tools/go:def.bzl", "go_library", "go_test") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = [ 6 | "bad_responses.go", 7 | "block_providers.go", 8 | "gossip_scorer.go", 9 | "peer_status.go", 10 | "service.go", 11 | ], 12 | importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/peers/scorers", 13 | visibility = ["//beacon-chain:__subpackages__"], 14 | deps = [ 15 | "//beacon-chain/p2p/peers/peerdata:go_default_library", 16 | "//beacon-chain/p2p/types:go_default_library", 17 | "//cmd/beacon-chain/flags:go_default_library", 18 | "//config/features:go_default_library", 19 | "//consensus-types/primitives:go_default_library", 20 | "//crypto/rand:go_default_library", 21 | "//proto/prysm/v1alpha1:go_default_library", 22 | "//time:go_default_library", 23 | "@com_github_libp2p_go_libp2p//core/peer:go_default_library", 24 | ], 25 | ) 26 | 27 | go_test( 28 | name = "go_default_test", 29 | srcs = [ 30 | "bad_responses_test.go", 31 | "block_providers_test.go", 32 | "gossip_scorer_test.go", 33 | "peer_status_test.go", 34 | "scorers_test.go", 35 | "service_test.go", 36 | ], 37 | deps = [ 38 | ":go_default_library", 39 | "//beacon-chain/p2p/peers:go_default_library", 40 | "//beacon-chain/p2p/peers/peerdata:go_default_library", 41 | "//beacon-chain/p2p/types:go_default_library", 42 | "//cmd/beacon-chain/flags:go_default_library", 43 | "//config/features:go_default_library", 44 | "//consensus-types/primitives:go_default_library", 45 | "//crypto/rand:go_default_library", 46 | "//proto/prysm/v1alpha1:go_default_library", 47 | "//testing/assert:go_default_library", 48 | "//testing/require:go_default_library", 49 | "//time:go_default_library", 50 | "@com_github_libp2p_go_libp2p//core/network:go_default_library", 51 | "@com_github_libp2p_go_libp2p//core/peer:go_default_library", 52 | "@com_github_sirupsen_logrus//:go_default_library", 53 | ], 54 | ) 55 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/scorers/rpc_errors.go: -------------------------------------------------------------------------------- 1 | package scorers 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrWrongForkDigestVersion = errors.New("wrong fork digest version") 7 | ErrInvalidEpoch = errors.New("invalid epoch") 8 | ErrInvalidFinalizedRoot = errors.New("invalid finalized root") 9 | ErrInvalidSequenceNum = errors.New("invalid sequence number provided") 10 | ErrGeneric = errors.New("internal service error") 11 | ErrInvalidParent = errors.New("mismatched parent root") 12 | ErrRateLimited = errors.New("rate limited") 13 | ErrIODeadline = errors.New("i/o deadline exceeded") 14 | ErrInvalidRequest = errors.New("invalid range, step or count") 15 | ) 16 | -------------------------------------------------------------------------------- /internal/pkg/conn/p2p/scorers/scorers_test.go: -------------------------------------------------------------------------------- 1 | package scorers_test 2 | 3 | import ( 4 | "io" 5 | "math" 6 | "testing" 7 | 8 | "github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags" 9 | "github.com/prysmaticlabs/prysm/v3/config/features" 10 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p/scorers" 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | func TestMain(m *testing.M) { 15 | logrus.SetLevel(logrus.DebugLevel) 16 | logrus.SetOutput(io.Discard) 17 | 18 | resetCfg := features.InitWithReset(&features.Flags{ 19 | EnablePeerScorer: true, 20 | }) 21 | defer resetCfg() 22 | 23 | resetFlags := flags.Get() 24 | flags.Init(&flags.GlobalFlags{ 25 | BlockBatchLimit: 64, 26 | BlockBatchLimitBurstFactor: 10, 27 | }) 28 | defer func() { 29 | flags.Init(resetFlags) 30 | }() 31 | m.Run() 32 | } 33 | 34 | // roundScore returns score rounded in accordance with the score manager's rounding factor. 35 | func roundScore(score float64) float64 { 36 | return math.Round(score*scorers.ScoreRoundingFactor) / scorers.ScoreRoundingFactor 37 | } 38 | -------------------------------------------------------------------------------- /internal/pkg/errors/http.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | func NewBadRequestError(message ...interface{}) *echo.HTTPError { 10 | return echo.NewHTTPError(http.StatusBadRequest, message...) 11 | } 12 | 13 | func NewUnauthorizedError(message ...interface{}) *echo.HTTPError { 14 | return echo.NewHTTPError(http.StatusUnauthorized, message...) 15 | } 16 | 17 | func NewForbiddenError(message ...interface{}) *echo.HTTPError { 18 | return echo.NewHTTPError(http.StatusForbidden, message...) 19 | } 20 | 21 | func NewNotFoundError(message ...interface{}) *echo.HTTPError { 22 | return echo.NewHTTPError(http.StatusNotFound, message...) 23 | } 24 | 25 | func NewInternalServerError(message ...interface{}) *echo.HTTPError { 26 | return echo.NewHTTPError(http.StatusInternalServerError, message...) 27 | } 28 | -------------------------------------------------------------------------------- /internal/pkg/logging/logger_native.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package logging 5 | 6 | import ( 7 | log "github.com/ipfs/go-log/v2" 8 | "go.uber.org/zap/zapcore" 9 | ) 10 | 11 | func Logger(system string) QuorumLogger { 12 | return log.Logger(system) 13 | } 14 | 15 | func SetLogLevel(name, level string) error { 16 | return log.SetLogLevel(name, level) 17 | } 18 | 19 | func SetAllLoggers(lvl int) { 20 | log.SetAllLoggers(log.LogLevel(lvl)) 21 | } 22 | 23 | func LevelFromString(level string) (int, error) { 24 | l, e := log.LevelFromString(level) 25 | return int(l), e 26 | } 27 | 28 | func SetPrimaryCore(core zapcore.Core) { 29 | log.SetPrimaryCore(core) 30 | } 31 | -------------------------------------------------------------------------------- /internal/pkg/logging/logging.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import log "github.com/ipfs/go-log/v2" 4 | 5 | type QuorumLogger interface { 6 | log.StandardLogger 7 | Warning(args ...interface{}) 8 | Warningf(format string, args ...interface{}) 9 | } 10 | -------------------------------------------------------------------------------- /internal/pkg/metric/utils.go: -------------------------------------------------------------------------------- 1 | package metric 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/logging" 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | var logger = logging.Logger("metric") 11 | 12 | func GetBinarySize(v interface{}) uint { 13 | size := binary.Size(v) 14 | if size < 0 { 15 | size = 0 16 | logger.Errorf("get binary.Size(%+v) failed", v) 17 | } 18 | 19 | return uint(size) 20 | } 21 | 22 | func GetProtoSize(v proto.Message) uint { 23 | size := proto.Size(v) 24 | 25 | if size < 0 { 26 | size = 0 27 | logger.Errorf("get proto.Size(%+v) failed", v) 28 | } 29 | 30 | return uint(size) 31 | } 32 | -------------------------------------------------------------------------------- /internal/pkg/middleware/jwt_skipper.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | func JWTSkipper(c echo.Context) bool { 10 | if LocalhostSkipper(c) { 11 | return true 12 | } 13 | 14 | path := c.Request().URL.Path 15 | skipPathPrefix := []string{ 16 | "/api/v1/ws/trx", 17 | } 18 | for _, v := range skipPathPrefix { 19 | if strings.HasPrefix(path, v) { 20 | return true 21 | } 22 | } 23 | 24 | return false 25 | } 26 | -------------------------------------------------------------------------------- /internal/pkg/middleware/localhost.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | func LocalhostSkipper(c echo.Context) bool { 10 | host := c.Request().Host 11 | skipHosts := []string{"localhost", "127.0.0.1"} 12 | for _, h := range skipHosts { 13 | if strings.HasPrefix(host, h+":") || host == h { 14 | return true 15 | } 16 | } 17 | 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /internal/pkg/options/options.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/logging" 7 | ) 8 | 9 | var optionslog = logging.Logger("options") 10 | 11 | type NodeOptions struct { 12 | Password string 13 | EnableRelay bool 14 | EnableNat bool 15 | EnableRumExchange bool 16 | EnableDevNetwork bool 17 | EnableSnapshot bool 18 | EnablePubQue bool 19 | MaxPeers int 20 | ConnsHi int 21 | NetworkName string 22 | JWT *JWT 23 | SignKeyMap map[string]string 24 | mu sync.RWMutex 25 | } 26 | 27 | type ( 28 | JWT struct { 29 | Key string `json:"key" mapstructure:"key"` 30 | Chain *JWTListItem `json:"chain" mapstructure:"chain"` 31 | Node map[string]*JWTListItem `json:"node" mapstructure:"node"` 32 | } 33 | 34 | JWTListItem struct { 35 | Normal []*TokenItem `json:"normal" mapstructure:"normal"` 36 | Revoke []*TokenItem `json:"revoke" mapstructure:"revoke"` 37 | } 38 | 39 | TokenItem struct { 40 | Remark string `json:"remark" mapstructure:"remark"` 41 | Token string `json:"token" mapstructure:"token"` 42 | } 43 | ) 44 | -------------------------------------------------------------------------------- /internal/pkg/payment/README: -------------------------------------------------------------------------------- 1 | //Connect with payment service 2 | //handle payment service api call/resp -------------------------------------------------------------------------------- /internal/pkg/storage/def/chainstorage.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 5 | ) 6 | 7 | type TrxStorageType uint 8 | 9 | const ( 10 | Chain TrxStorageType = iota 11 | Cache 12 | ) 13 | 14 | type TrxStorageIface interface { 15 | GetTrx(groupId string, trxId string, storagetype TrxStorageType, prefix ...string) (t *quorumpb.Trx, err error) 16 | } 17 | 18 | type APIHandlerIface interface { 19 | IsUserAnnounced(groupId, userSignPubkey string, prefix ...string) (bool, error) 20 | IsProducerAnnounced(groupId, producerSignPubkey string, prefix ...string) (bool, error) 21 | GetSendTrxAuthListByGroupId(groupId string, listType quorumpb.AuthListType, prefix ...string) ([]*quorumpb.ChainConfigItem, []*quorumpb.ChainSendTrxRuleListItem, error) 22 | GetTrxAuthModeByGroupId(groupId string, trxType quorumpb.TrxType, prefix ...string) (quorumpb.TrxAuthMode, error) 23 | GetAnnounceProducersByGroup(groupId string, prefix ...string) ([]*quorumpb.AnnounceItem, error) 24 | GetAnnounceUsersByGroup(groupId string, prefix ...string) ([]*quorumpb.AnnounceItem, error) 25 | GetProducers(groupId string, prefix ...string) ([]*quorumpb.ProducerItem, error) 26 | } 27 | -------------------------------------------------------------------------------- /internal/pkg/storage/node/node_db.go: -------------------------------------------------------------------------------- 1 | package node_storage 2 | 3 | //node storage func goes here 4 | -------------------------------------------------------------------------------- /internal/pkg/storage/storage.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | type QuorumStorage interface { 4 | Init(path string) error 5 | Close() error 6 | Set(key []byte, val []byte) error 7 | Delete(key []byte) error 8 | Get(key []byte) ([]byte, error) 9 | PrefixDelete(prefix []byte) (int, error) 10 | PrefixCondDelete(prefix []byte, fn func(k []byte, v []byte, err error) (bool, error)) (int, error) 11 | PrefixForeachKey(prefix []byte, valid []byte, reverse bool, fn func([]byte, error) error) (int, error) 12 | PrefixForeach(prefix []byte, fn func([]byte, []byte, error) error) error 13 | Foreach(fn func([]byte, []byte, error) error) error 14 | IsExist([]byte) (bool, error) 15 | 16 | // For appdb, atomic batch write 17 | BatchWrite(keys [][]byte, values [][]byte) error 18 | GetSequence([]byte, uint64) (Sequence, error) 19 | } 20 | 21 | type Sequence interface { 22 | Next() (uint64, error) 23 | Release() error 24 | } 25 | -------------------------------------------------------------------------------- /internal/pkg/utils/cert.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net" 5 | "regexp" 6 | ) 7 | 8 | func IsPublicIP(v string) bool { 9 | ip := net.ParseIP(v) 10 | if ip == nil { 11 | return false 12 | } 13 | 14 | if !ip.IsPrivate() && !ip.IsLoopback() && !ip.IsUnspecified() { 15 | return true 16 | } 17 | return false 18 | } 19 | 20 | func IsDomainName(domain string) bool { 21 | RegExp := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$`) 22 | 23 | return RegExp.MatchString(domain) 24 | } 25 | -------------------------------------------------------------------------------- /internal/pkg/utils/compress.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/klauspost/compress/zstd" 7 | ) 8 | 9 | // Compress compress with zstd 10 | func Compress(in io.Reader, out io.Writer) error { 11 | enc, err := zstd.NewWriter(out) 12 | if err != nil { 13 | return err 14 | } 15 | 16 | _, err = io.Copy(enc, in) 17 | if err != nil { 18 | enc.Close() 19 | return err 20 | } 21 | 22 | return enc.Close() 23 | } 24 | 25 | // Decompress decompress with zstd 26 | func Decompress(in io.Reader, out io.Writer) error { 27 | d, err := zstd.NewReader(in) 28 | if err != nil { 29 | return err 30 | } 31 | defer d.Close() 32 | 33 | _, err = io.Copy(out, d) 34 | 35 | return err 36 | } 37 | -------------------------------------------------------------------------------- /internal/pkg/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | func CheckAndCreateDir(path string) error { 10 | path, err := filepath.Abs(path) 11 | if err != nil { 12 | return fmt.Errorf("filepath.Abs(%s) failed: %s", path, err) 13 | } 14 | 15 | // if path is exists, return 16 | if FileExist(path) { 17 | return fmt.Errorf("file %s is exists", path) 18 | } 19 | 20 | // if path is dir, but not empty, return 21 | if DirExist(path) { 22 | empty, err := IsDirEmpty(path) 23 | if err != nil { 24 | return err 25 | } 26 | if !empty { 27 | return fmt.Errorf("dir %s is not empty", path) 28 | } 29 | } else { 30 | // create path 31 | if err := os.MkdirAll(path, 0700); err != nil { 32 | return fmt.Errorf("os.MkdirAll(%s, 0700) failed: %s", path, err) 33 | } 34 | } 35 | 36 | return nil 37 | } 38 | 39 | // RemoveAll wrap os.RemoveAll and output log 40 | func RemoveAll(path string) error { 41 | err := os.RemoveAll(path) 42 | if err != nil { 43 | logger.Errorf("remove %s failed: %s", path, err) 44 | } 45 | 46 | return err 47 | } 48 | -------------------------------------------------------------------------------- /internal/pkg/utils/file_copy_native.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package utils 5 | 6 | import ( 7 | cp "github.com/otiai10/copy" 8 | ) 9 | 10 | // Copy copies src to dest, doesn't matter if src is a directory or a file. 11 | func Copy(src string, dst string, opt ...cp.Options) error { 12 | return cp.Copy(src, dst, opt...) 13 | } 14 | -------------------------------------------------------------------------------- /internal/pkg/utils/jwt.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/golang-jwt/jwt/v4" 8 | ) 9 | 10 | // NewJWTToken creates a new jwt token 11 | func NewJWTToken(name string, role string, allowGroup string, jwtKey string, exp time.Time) (string, error) { 12 | 13 | token := jwt.New(jwt.SigningMethodHS256) 14 | claims := token.Claims.(jwt.MapClaims) 15 | claims["name"] = name 16 | claims["role"] = role 17 | claims["allowGroup"] = allowGroup 18 | claims["exp"] = exp.Unix() 19 | 20 | return token.SignedString([]byte(jwtKey)) 21 | } 22 | 23 | // ParseJWTToken parse jwt token string to *jwt.Token 24 | func ParseJWTToken(tokenStr string, jwtKey string) (*jwt.Token, error) { 25 | claims := jwt.MapClaims{} 26 | token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) { 27 | return []byte(jwtKey), nil 28 | }) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | return token, nil 34 | } 35 | 36 | // IsJWTTokenExpires checks if the token is expired 37 | func IsJWTTokenExpired(tokenStr string, jwtKey string) bool { 38 | _, err := ParseJWTToken(tokenStr, jwtKey) 39 | if err != nil { 40 | e := err.(*jwt.ValidationError) 41 | if e.Errors == jwt.ValidationErrorExpired { 42 | return true 43 | } 44 | } 45 | 46 | return false 47 | } 48 | 49 | // IsJWTTokenValid checks if the token is valid, invalid include expired or invalid 50 | func IsJWTTokenValid(tokenStr string, jwtKey string) (bool, error) { 51 | _, err := ParseJWTToken(tokenStr, jwtKey) 52 | if err != nil { 53 | e := err.(*jwt.ValidationError) 54 | if e.Errors == jwt.ValidationErrorExpired { 55 | return false, fmt.Errorf("token expires: %s", err) 56 | } 57 | 58 | return false, fmt.Errorf("token is invalid: %s", err) 59 | } 60 | 61 | return true, nil 62 | } 63 | -------------------------------------------------------------------------------- /internal/pkg/utils/str.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | "unicode" 6 | ) 7 | 8 | func LongestCommonPrefix(strs []string) string { 9 | if len(strs) == 0 { 10 | return "" 11 | } 12 | 13 | prefix := strs[0] 14 | for i := 1; i < len(strs); i++ { 15 | for !strings.HasPrefix(strs[i], prefix) { 16 | prefix = prefix[0 : len(prefix)-1] 17 | if len(prefix) == 0 { 18 | return "" 19 | } 20 | } 21 | } 22 | 23 | return prefix 24 | } 25 | 26 | func LowerFirstLetter(s string) string { 27 | for i, v := range s { 28 | return string(unicode.ToLower(v)) + s[i+1:] 29 | } 30 | 31 | return s 32 | } 33 | -------------------------------------------------------------------------------- /internal/pkg/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | 6 | maddr "github.com/multiformats/go-multiaddr" 7 | ) 8 | 9 | func TestStringsToAddrs(t *testing.T) { 10 | m, _ := maddr.NewMultiaddr("/ip4/127.0.0.1/tcp/7002") 11 | excepted := []maddr.Multiaddr{m} 12 | m1, err := StringsToAddrs([]string{"/ip4/127.0.0.1/tcp/7002"}) 13 | if err != nil { 14 | t.Errorf("Test failed:%s", err) 15 | } 16 | if len(m1) != len(excepted) { 17 | t.Error("Test failed") 18 | } 19 | for i, mitem := range m1 { 20 | if !mitem.Equal(excepted[i]) { 21 | t.Errorf("Test failed: %s not %s", mitem, excepted[i]) 22 | } 23 | } 24 | } 25 | 26 | func TestGetRandomStr(t *testing.T) { 27 | for i := 0; i < 20; i++ { 28 | s := GetRandomStr(i) 29 | if len(s) != i { 30 | t.Errorf("Test failed, len(%s) != %d", s, i) 31 | } 32 | } 33 | 34 | a := GetRandomStr(10) 35 | b := GetRandomStr(10) 36 | if a == b { 37 | t.Errorf("random two string are equal: %s, %s", a, b) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /internal/pkg/utils/version.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | var ReleaseVersion string 4 | var GitCommit string 5 | 6 | func SetGitCommit(hash string) { 7 | GitCommit = hash 8 | } 9 | 10 | func SetVersion(version string) { 11 | ReleaseVersion = version 12 | } 13 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "google.golang.org/protobuf/types/known/timestamppb" //import for swaggo 5 | 6 | "github.com/rumsystem/quorum/cmd" 7 | "github.com/rumsystem/quorum/internal/pkg/utils" 8 | ) 9 | 10 | var ( 11 | ReleaseVersion string 12 | GitCommit string 13 | ) 14 | 15 | // @title Quorum Api 16 | // @version 1.0 17 | // @description Quorum Api Docs 18 | // @BasePath / 19 | func main() { 20 | if ReleaseVersion == "" { 21 | ReleaseVersion = "v1.0.0" 22 | } 23 | if GitCommit == "" { 24 | GitCommit = "devel" 25 | } 26 | utils.SetGitCommit(GitCommit) 27 | utils.SetVersion(ReleaseVersion) 28 | 29 | cmd.Execute() 30 | } 31 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | PROTOC_GEN_GO = $(GOPATH)/bin/protoc-gen-go 2 | PROTOC = $(shell which protoc) 3 | 4 | install-goreleaser: 5 | go install github.com/goreleaser/goreleaser@v1.18.2 6 | 7 | linux: install-goreleaser 8 | GOOS=linux GOARCH=amd64 goreleaser build --snapshot --clean --single-target 9 | 10 | windows: install-goreleaser 11 | GOOS=windows GOARCH=amd64 goreleaser build --snapshot --clean --single-target 12 | 13 | freebsd: install-goreleaser 14 | GOOS=freebsd GOARCH=amd64 goreleaser build --snapshot --clean --single-target 15 | 16 | darwin: install-goreleaser 17 | GOOS=darwin GOARCH=amd64 goreleaser build --snapshot --clean --single-target 18 | 19 | buildall: install-goreleaser 20 | goreleaser build --snapshot --clean 21 | 22 | release: install-goreleaser 23 | goreleaser release --clean 24 | 25 | install-swag: 26 | go install github.com/swaggo/swag/cmd/swag@v1.8.4 27 | 28 | gen-doc: install-swag 29 | $(shell which swag) init -g main.go --parseDependency --parseInternal --parseDepth 3 --parseGoList=true 30 | 31 | serve-doc: gen-doc 32 | go run ./docs.go 33 | 34 | test-main: 35 | go test -timeout 99999s main_test.go -v 36 | 37 | test-main-rex: 38 | #go test -timeout 99999s main_rex_test.go -v -nodes=3 -posts=2 -timerange=5 -groups=3 -synctime=20 -rextest=true 39 | go test -timeout 99999s main_test.go -v -fullnodes=3 -posts=2 -timerange=5 -groups=3 -synctime=20 -rextest=true 40 | 41 | test-api: 42 | go test -v pkg/chainapi/api/* 43 | 44 | test: test-api test-main test-main-rex 45 | 46 | all: doc test buildall release 47 | -------------------------------------------------------------------------------- /pkg/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rumsystem/quorum/75f766f68132fdaaac7885de5b2b1fd507389ae6/pkg/.keep -------------------------------------------------------------------------------- /pkg/autorelay/api/blacklist.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | handlers "github.com/rumsystem/quorum/pkg/autorelay/handlers" 9 | ) 10 | 11 | func (h *RelayServerHandler) GetBlacklist(c echo.Context) (err error) { 12 | peer := c.QueryParam("peer") 13 | if peer == "" { 14 | return rumerrors.NewBadRequestError("peer can't be nil.") 15 | } 16 | 17 | result, err := handlers.GetBlacklist(h.db, peer) 18 | if err != nil { 19 | return rumerrors.NewInternalServerError(err) 20 | } 21 | 22 | return c.JSON(http.StatusOK, result) 23 | } 24 | 25 | func (h *RelayServerHandler) AddBlacklist(c echo.Context) (err error) { 26 | param := handlers.AddBlacklistParam{} 27 | if err := c.Bind(¶m); err != nil { 28 | rumerrors.NewBadRequestError(err.Error()) 29 | } 30 | 31 | result, err := handlers.AddBlacklist(h.db, param) 32 | if err != nil { 33 | return rumerrors.NewInternalServerError(err) 34 | } 35 | 36 | relay := h.node.GetRelay() 37 | if relay != nil { 38 | //TODO upgrade the DisconnectByPeerID 39 | //type *relay.Relay has no field or method DisconnectByPeerID 40 | 41 | //from, err := peer.Decode(param.FromPeer) 42 | //if err != nil { 43 | // return rumerrors.NewBadRequestError(err.Error()) 44 | //} 45 | //to, err := peer.Decode(param.ToPeer) 46 | //if err != nil { 47 | // return rumerrors.NewBadRequestError(err.Error()) 48 | //} 49 | //relay.DisconnectByPeerID(from, to) 50 | } 51 | 52 | return c.JSON(http.StatusOK, result) 53 | } 54 | 55 | func (h *RelayServerHandler) DeleteBlacklist(c echo.Context) (err error) { 56 | param := handlers.DelBlacklistParam{} 57 | if err := c.Bind(¶m); err != nil { 58 | rumerrors.NewBadRequestError(err.Error()) 59 | } 60 | 61 | result, err := handlers.DeleteBlacklist(h.db, param) 62 | if err != nil { 63 | return rumerrors.NewInternalServerError(err) 64 | } 65 | 66 | return c.JSON(http.StatusOK, result) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/autorelay/api/disconnect.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | handlers "github.com/rumsystem/quorum/pkg/autorelay/handlers" 9 | ) 10 | 11 | func (h *RelayServerHandler) Disconnect(c echo.Context) (err error) { 12 | param := handlers.DelBlacklistParam{} 13 | if err := c.Bind(¶m); err != nil { 14 | return rumerrors.NewBadRequestError(err.Error()) 15 | } 16 | 17 | result := handlers.DisconnectResult{Ok: true} 18 | 19 | relay := h.node.GetRelay() 20 | if relay != nil { 21 | //TODO upgrade the DisconnectByPeerID 22 | //type *relay.Relay has no field or method DisconnectByPeerID 23 | 24 | //from, err := peer.Decode(param.FromPeer) 25 | //if err != nil { 26 | // return rumerrors.NewBadRequestError(err.Error()) 27 | //} 28 | //to, err := peer.Decode(param.ToPeer) 29 | //if err != nil { 30 | // return rumerrors.NewBadRequestError(err.Error()) 31 | //} 32 | //relay.DisconnectByPeerID(from, to) 33 | } 34 | 35 | return c.JSON(http.StatusOK, result) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/autorelay/api/forbid.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | handlers "github.com/rumsystem/quorum/pkg/autorelay/handlers" 9 | ) 10 | 11 | func (h *RelayServerHandler) ForbidPeer(c echo.Context) (err error) { 12 | param := handlers.ForbidParam{} 13 | if err := c.Bind(¶m); err != nil { 14 | rumerrors.NewBadRequestError(err.Error()) 15 | } 16 | 17 | result, err := handlers.ForbidPeer(h.db, param) 18 | if err != nil { 19 | return rumerrors.NewInternalServerError(err) 20 | } 21 | 22 | return c.JSON(http.StatusOK, result) 23 | } 24 | -------------------------------------------------------------------------------- /pkg/autorelay/api/getpermissions.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | handlers "github.com/rumsystem/quorum/pkg/autorelay/handlers" 9 | ) 10 | 11 | func (h *RelayServerHandler) GetPermissions(c echo.Context) (err error) { 12 | peer := c.QueryParam("peer") 13 | if peer == "" { 14 | return rumerrors.NewBadRequestError("peer can't be nil.") 15 | } 16 | 17 | result, err := handlers.GetPermissions(h.db, peer) 18 | if err != nil { 19 | return rumerrors.NewInternalServerError(err) 20 | } 21 | 22 | return c.JSON(http.StatusOK, result) 23 | } 24 | -------------------------------------------------------------------------------- /pkg/autorelay/api/handler.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p" 5 | "github.com/rumsystem/quorum/internal/pkg/storage" 6 | ) 7 | 8 | type RelayServerHandler struct { 9 | db storage.QuorumStorage 10 | node *p2p.RelayNode 11 | } 12 | 13 | func NewRelayServerHandler(db storage.QuorumStorage, node *p2p.RelayNode) RelayServerHandler { 14 | return RelayServerHandler{db, node} 15 | } 16 | -------------------------------------------------------------------------------- /pkg/autorelay/audit/traffic.go: -------------------------------------------------------------------------------- 1 | package audit 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p/core/peer" 5 | "github.com/rumsystem/quorum/internal/pkg/logging" 6 | "github.com/rumsystem/quorum/internal/pkg/storage" 7 | ) 8 | 9 | /* to record traffic consumption of a peer */ 10 | 11 | var auditLogger = logging.Logger("main") 12 | 13 | type QuorumTrafficAudit struct { 14 | db storage.QuorumStorage 15 | } 16 | 17 | func NewQuorumTrafficAudit(db storage.QuorumStorage) *QuorumTrafficAudit { 18 | a := QuorumTrafficAudit{db} 19 | return &a 20 | } 21 | 22 | func (a *QuorumTrafficAudit) OnRelay(src peer.ID, dest peer.ID, count int64) { 23 | auditLogger.Infof("%s -> %s: %d bytes", src.String(), dest.String(), count) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/autorelay/handlers/blacklist.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/storage" 7 | ) 8 | 9 | type GetBlacklistResult struct { 10 | Peers []string `json:"peers"` 11 | } 12 | 13 | type AddBlacklistParam struct { 14 | FromPeer string `json:"from_peer"` 15 | ToPeer string `json:"to_peer"` 16 | } 17 | 18 | type DelBlacklistParam AddBlacklistParam 19 | 20 | type AddBlacklistResult struct { 21 | Ok bool `json:"ok"` 22 | } 23 | 24 | type DelBlacklistResult AddBlacklistResult 25 | 26 | /* GetBlacklist to get blacklist for a server peer */ 27 | func GetBlacklist(db storage.QuorumStorage, serverPeer string) (*GetBlacklistResult, error) { 28 | res := &GetBlacklistResult{[]string{}} 29 | 30 | prefix := []byte(GetBlackListPrefixKey(serverPeer)) 31 | if _, err := db.PrefixForeachKey(prefix, prefix, false, func(k []byte, err error) error { 32 | if err != nil { 33 | return err 34 | } 35 | key := string(k) 36 | banPeer := GetBlacklistPeerFromKeyByPrefix(key, string(prefix)) 37 | res.Peers = append(res.Peers, banPeer) 38 | return nil 39 | }); err != nil { 40 | return nil, err 41 | } 42 | 43 | return res, nil 44 | } 45 | 46 | /* AddBlacklist to put a peer in blacklist */ 47 | func AddBlacklist(db storage.QuorumStorage, param AddBlacklistParam) (*AddBlacklistResult, error) { 48 | res := &AddBlacklistResult{true} 49 | 50 | k := []byte(GetBlackListKey(param.FromPeer, param.ToPeer)) 51 | if err := db.Set(k, []byte(strconv.FormatBool(true))); err != nil { 52 | return nil, err 53 | } 54 | 55 | return res, nil 56 | } 57 | 58 | /* DeleteBlacklist to remove a peer from blacklist */ 59 | func DeleteBlacklist(db storage.QuorumStorage, param DelBlacklistParam) (*DelBlacklistResult, error) { 60 | res := &DelBlacklistResult{true} 61 | 62 | k := []byte(GetBlackListKey(param.FromPeer, param.ToPeer)) 63 | if err := db.Delete(k); err != nil { 64 | return nil, err 65 | } 66 | 67 | return res, nil 68 | } 69 | 70 | func CheckBlacklist(db storage.QuorumStorage, from string, to string) (bool, error) { 71 | k := []byte(GetBlackListKey(from, to)) 72 | 73 | return db.IsExist(k) 74 | } 75 | -------------------------------------------------------------------------------- /pkg/autorelay/handlers/constant.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | PREFIX_ALLOW_RESERVE = "AllowReserve" 10 | PREFIX_ALLOW_CONNECT = "AllowConnect" 11 | PREFIX_BLACKLIST = "Blacklist" 12 | ) 13 | 14 | func GetAllowConnectKey(peer string) string { 15 | return fmt.Sprintf("%s_%s", PREFIX_ALLOW_CONNECT, peer) 16 | } 17 | 18 | func GetAllowReserveKey(peer string) string { 19 | return fmt.Sprintf("%s_%s", PREFIX_ALLOW_RESERVE, peer) 20 | } 21 | 22 | func GetBlackListPrefixKey(serverPeer string) string { 23 | return fmt.Sprintf("%s_%s", PREFIX_BLACKLIST, serverPeer) 24 | } 25 | 26 | func GetBlackListKey(serverPeer string, banPeer string) string { 27 | // like `Blacklist_$from_$to` 28 | return fmt.Sprintf("%s_%s", GetBlackListPrefixKey(serverPeer), banPeer) 29 | } 30 | 31 | func GetBlacklistPeerFromKeyByPrefix(key string, prefix string) string { 32 | return strings.ReplaceAll(key, fmt.Sprintf("%s_", prefix), "") 33 | } 34 | -------------------------------------------------------------------------------- /pkg/autorelay/handlers/disconnect.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | type DisconnectParam struct { 4 | FromPeer string `json:"from_peer"` 5 | ToPeer string `json:"to_peer"` 6 | } 7 | type DisconnectResult struct { 8 | Ok bool `json:"ok"` 9 | } 10 | -------------------------------------------------------------------------------- /pkg/autorelay/handlers/forbid.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/storage" 7 | ) 8 | 9 | type ForbidParam struct { 10 | Peer string `json:"peer"` 11 | } 12 | 13 | type ForbidResult struct { 14 | Ok bool `json:"ok"` 15 | } 16 | 17 | /* ForbidPeer forbid a server peer */ 18 | func ForbidPeer(db storage.QuorumStorage, param ForbidParam) (*ForbidResult, error) { 19 | res := &ForbidResult{true} 20 | 21 | k := []byte(GetAllowConnectKey(param.Peer)) 22 | if err := db.Set(k, []byte(strconv.FormatBool(false))); err != nil { 23 | return nil, err 24 | } 25 | 26 | return res, nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/autorelay/handlers/getpermissions.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/storage" 7 | ) 8 | 9 | type GetPermissionsResult struct { 10 | AllowReserve bool 11 | AllowConnect bool 12 | } 13 | 14 | func GetPermissions(db storage.QuorumStorage, peer string) (*GetPermissionsResult, error) { 15 | res := &GetPermissionsResult{true, true} 16 | 17 | // only get `AllowConnect` permission here, we always allow reserve for now 18 | k := []byte(GetAllowConnectKey(peer)) 19 | 20 | isExist, err := db.IsExist(k) 21 | if err != nil { 22 | return nil, err 23 | } 24 | if !isExist { 25 | // allow by default 26 | return res, nil 27 | } 28 | 29 | v, err := db.Get(k) 30 | if err != nil { 31 | return nil, err 32 | } 33 | ok, _ := strconv.ParseBool(string(v)) 34 | res.AllowConnect = ok 35 | 36 | return res, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/autorelay/server.go: -------------------------------------------------------------------------------- 1 | package autorelay 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "syscall" 8 | 9 | "github.com/labstack/echo/v4" 10 | "github.com/rumsystem/quorum/internal/pkg/appdata" 11 | "github.com/rumsystem/quorum/internal/pkg/cli" 12 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 13 | "github.com/rumsystem/quorum/internal/pkg/utils" 14 | "github.com/rumsystem/quorum/pkg/autorelay/api" 15 | ) 16 | 17 | type Handler struct { 18 | Ctx context.Context 19 | Appdb *appdata.AppDb 20 | Trxdb def.TrxStorageIface 21 | Apiroot string 22 | GitCommit string 23 | ConfigDir string 24 | PeerName string 25 | NodeName string 26 | } 27 | 28 | //StartRelayServer : Start local web server 29 | func StartRelayServer(config cli.RelayNodeFlag, quitCh chan os.Signal, h *api.RelayServerHandler) { 30 | e := utils.NewEcho(config.IsDebug) 31 | r := e.Group("/relay") 32 | 33 | r.GET("/quit", func(c echo.Context) (err error) { 34 | fmt.Println("/api/quit has been called, send Signal SIGTERM...") 35 | quitCh <- syscall.SIGTERM 36 | return nil 37 | }) 38 | 39 | r.POST("/v1/forbid", h.ForbidPeer) 40 | r.POST("/v1/blacklist", h.AddBlacklist) 41 | r.DELETE("/v1/blacklist", h.DeleteBlacklist) 42 | r.POST("/v1/disconnect", h.Disconnect) 43 | 44 | r.GET("/v1/permissions", h.GetPermissions) 45 | r.GET("/v1/blacklist", h.GetBlacklist) 46 | 47 | e.Logger.Fatal(e.Start(fmt.Sprintf("%s:%d", config.APIHost, config.APIPort))) 48 | } 49 | -------------------------------------------------------------------------------- /pkg/chainapi/api/addpeers.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Node 12 | // @Summary AddPeers 13 | // @Description Connect to peers 14 | // @Accept json 15 | // @Produce json 16 | // @Param data body handlers.AddPeerParam true "AddPeerParam" 17 | // @Success 200 {object} handlers.AddPeerResult 18 | // @Router /api/v1/network/peers [post] 19 | func (h *Handler) AddPeers(c echo.Context) (err error) { 20 | params := new(handlers.AddPeerParam) 21 | if err := c.Bind(params); err != nil { 22 | rumerrors.NewBadRequestError(err.Error()) 23 | } 24 | 25 | result, err := handlers.AddPeers(*params) 26 | if err != nil { 27 | return rumerrors.NewBadRequestError(err) 28 | } 29 | 30 | return c.JSON(http.StatusOK, result) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/chainapi/api/addpeers_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/go-playground/validator/v10" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | "github.com/rumsystem/quorum/testnode" 11 | ) 12 | 13 | func addPeers(api string, payload handlers.AddPeerParam) (*handlers.AddPeerResult, error) { 14 | payloadByte, err := json.Marshal(payload) 15 | if err != nil { 16 | return nil, err 17 | } 18 | payloadStr := string(payloadByte) 19 | 20 | urlSuffix := "/api/v1/network/peers" 21 | _, resp, err := testnode.RequestAPI(api, urlSuffix, "POST", payloadStr) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | var result handlers.AddPeerResult 27 | if err := json.Unmarshal(resp, &result); err != nil { 28 | return nil, err 29 | } 30 | 31 | if result.ErrCount > 0 { 32 | return nil, fmt.Errorf("%s", result.Errs) 33 | } 34 | 35 | validate := validator.New() 36 | if err := validate.Struct(result); err != nil { 37 | return nil, err 38 | } 39 | 40 | return &result, nil 41 | } 42 | 43 | func TestAddPeers(t *testing.T) { 44 | t.Parallel() 45 | 46 | payload := handlers.AddPeerParam{"/ip4/192.99.101.35/tcp/10666/p2p/16Uiu2HAm8FNWrm1Zqe29Xe4EoHTzKG5UnVD2gCDB7D4b3SM5AvGi"} 47 | 48 | if _, err := addPeers(peerapi, payload); err != nil { 49 | t.Errorf("addPeers failed: %s, payload: %+v", err, payload) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkg/chainapi/api/announce.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags User 13 | // @Summary AnnounceUserPubkey 14 | // @Description Announce User's encryption Pubkey to the group 15 | // @Accept json 16 | // @Produce json 17 | // @Param data body handlers.AnnounceParam true "AnnounceParam" 18 | // @Success 200 {object} handlers.AnnounceResult 19 | // @Router /api/v1/group/announce [post] 20 | func (h *Handler) Announce(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | params := new(handlers.AnnounceParam) 23 | if err := cc.BindAndValidate(params); err != nil { 24 | return err 25 | } 26 | 27 | res, err := handlers.AnnounceHandler(params) 28 | if err != nil { 29 | return rumerrors.NewBadRequestError(err) 30 | } 31 | 32 | return c.JSON(http.StatusOK, res) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/api/autorelay.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 8 | ) 9 | 10 | type AddRelayServersResp struct { 11 | Ok bool `json:"ok" example:"true"` 12 | } 13 | 14 | // @Tags Node 15 | // @Summary AddRelayServers 16 | // @Accept json 17 | // @Produce json 18 | // @Param data body []string true "Peers List" 19 | // @Success 200 {object} AddRelayServersResp 20 | // @Router /api/v1/network/relay [post] 21 | func (h *Handler) AddRelayServers(c echo.Context) (err error) { 22 | var input handlers.AddRelayParam 23 | output := make(map[string]interface{}) 24 | 25 | if err = c.Bind(&input); err != nil { 26 | output[ERROR_INFO] = err.Error() 27 | return c.JSON(http.StatusBadRequest, output) 28 | } 29 | 30 | ok, err := handlers.AddRelayServers(input) 31 | if err != nil { 32 | output[ERROR_INFO] = err.Error() 33 | return c.JSON(http.StatusBadRequest, output) 34 | } 35 | resp := AddRelayServersResp{Ok: ok} 36 | return c.JSON(http.StatusOK, resp) 37 | } 38 | -------------------------------------------------------------------------------- /pkg/chainapi/api/cleargroupdata.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/rumsystem/quorum/internal/pkg/utils" 8 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Groups 12 | // @Summary ClearGroupData 13 | // @Description Clear group data 14 | // @Produce json 15 | // @Accept json 16 | // @Param data body handlers.ClearGroupDataParam true "ClearGroupParam" 17 | // @Success 200 {object} handlers.ClearGroupDataResult 18 | // @Router /api/v1/group/clear [post] 19 | func (h *Handler) ClearGroupData(c echo.Context) (err error) { 20 | cc := c.(*utils.CustomContext) 21 | params := new(handlers.ClearGroupDataParam) 22 | if err := cc.BindAndValidate(params); err != nil { 23 | return err 24 | } 25 | 26 | res, err := handlers.ClearGroupData(params) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | return c.JSON(http.StatusOK, res) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/chainapi/api/cleargroupdata_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/go-playground/validator/v10" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | "github.com/rumsystem/quorum/testnode" 10 | ) 11 | 12 | func clearGroup(api string, payload handlers.ClearGroupDataParam) (*handlers.ClearGroupDataResult, error) { 13 | payloadBytes, err := json.Marshal(payload) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | payloadStr := string(payloadBytes[:]) 19 | urlSuffix := fmt.Sprintf("/api/v1/group/clear") 20 | _, resp, err := testnode.RequestAPI(api, urlSuffix, "POST", payloadStr) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | if err := getResponseError(resp); err != nil { 26 | return nil, err 27 | } 28 | 29 | var result handlers.ClearGroupDataResult 30 | if err := json.Unmarshal(resp, &result); err != nil { 31 | return nil, err 32 | } 33 | 34 | validate := validator.New() 35 | if err := validate.Struct(result); err != nil { 36 | logger.Errorf("clear group response: %s, result: %+v", resp, result) 37 | return nil, err 38 | } 39 | 40 | return &result, nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/chainapi/api/config.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | //const name 4 | const GROUP_NAME string = "group_name" 5 | const GROUP_ID string = "group_id" 6 | const GROUP_OWNER_PUBKEY string = "owner_pubkey" 7 | const GROUP_ITEMS string = "group_items" 8 | const GROUP_ITEM string = "group_item" 9 | const GENESIS_BLOCK string = "genesis_block" 10 | const NODE_VERSION string = "node_version" 11 | const NODE_PUBKEY string = "node_publickey" 12 | const NODE_STATUS string = "node_status" 13 | const NODE_ID string = "node_id" 14 | const SIGNATURE string = "signature" 15 | const TRX_ID string = "trx_id" 16 | const PEERS string = "peers" 17 | const NODETYPE string = "node_type" 18 | 19 | //config 20 | const GROUP_NAME_MIN_LENGTH int = 5 21 | 22 | //error 23 | const ERROR_INFO string = "error" 24 | 25 | const BLACK_LIST_OP_PREFIX string = "blklistop_" 26 | -------------------------------------------------------------------------------- /pkg/chainapi/api/creategroup.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/rumsystem/quorum/internal/pkg/options" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | _ "github.com/rumsystem/quorum/pkg/pb" //import for swaggo 11 | ) 12 | 13 | // @Tags Groups 14 | // @Summary CreateGroupUrl 15 | // @Description Create a new group 16 | // @Accept json 17 | // @Produce json 18 | // @Param data body handlers.CreateGroupParam true "GroupInfo" 19 | // @Success 200 {object} handlers.CreateGroupResult 20 | // @Router /api/v1/group [post] 21 | func (h *Handler) CreateGroupUrl() echo.HandlerFunc { 22 | return func(c echo.Context) error { 23 | cc := c.(*utils.CustomContext) 24 | 25 | params := new(handlers.CreateGroupParam) 26 | if err := cc.BindAndValidate(params); err != nil { 27 | return err 28 | } 29 | 30 | baseUrl := cc.GetBaseURLFromRequest() 31 | res, err := handlers.CreateGroupUrl(baseUrl, params, options.GetNodeOptions(), h.Appdb) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | return c.JSON(http.StatusOK, res) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/chainapi/api/get_content_sdk_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | "time" 8 | 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 11 | ) 12 | 13 | func getContentNSdk(urls []string, payload *handlers.GetGroupCtnPrarms) ([]*quorumpb.Trx, error) { 14 | path := fmt.Sprintf("/api/v1/node/%s/groupctn", payload.GroupId) 15 | var result []*quorumpb.Trx 16 | if _, _, err := requestNSdk(urls, path, "GET", payload, nil, &result, true); err != nil { 17 | return nil, err 18 | } 19 | 20 | return result, nil 21 | } 22 | 23 | func TestGetContentNSdk(t *testing.T) { 24 | t.Parallel() 25 | 26 | // create group 27 | createGroupParam := handlers.CreateGroupParam{ 28 | GroupName: "test-get-cnt", 29 | ConsensusType: "poa", 30 | EncryptionType: "public", 31 | AppKey: "default", 32 | IncludeChainUrl: true, 33 | } 34 | group, err := createGroup(peerapi, createGroupParam) 35 | if err != nil { 36 | t.Errorf("createGroup failed: %s, payload: %+v", err, createGroupParam) 37 | } 38 | 39 | post := PostGroupParam{ 40 | GroupID: group.GroupId, 41 | Data: map[string]interface{}{ 42 | "Type": "Note", 43 | "Content": "hello world ...", 44 | }, 45 | } 46 | if _, err := postToGroup(peerapi, post); err != nil { 47 | t.Errorf("post to group failed: %s", err) 48 | } 49 | 50 | time.Sleep(10 * time.Second) 51 | 52 | _, urls, err := handlers.UrlToGroupSeed(group.Seed) 53 | if err != nil { 54 | t.Errorf("convert group send url failed: %s", err) 55 | } 56 | 57 | reverse := true 58 | if rand.Intn(20) > 10 { 59 | reverse = false 60 | } 61 | payload := handlers.GetGroupCtnPrarms{ 62 | GroupId: group.GroupId, 63 | Num: 20, 64 | Reverse: reverse, 65 | IncludeStartTrx: false, 66 | } 67 | 68 | if _, err := getContentNSdk(urls, &payload); err != nil { 69 | t.Errorf("get content via sdk api failed: %s", err) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /pkg/chainapi/api/get_user_encrypt_pubkeys_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/go-playground/validator/v10" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | func getUserEncryptPubKeys(urls []string, groupID string) (*GetUserEncryptPubKeysResult, error) { 12 | path := fmt.Sprintf("/api/v1/node/%s/encryptpubkeys", groupID) 13 | var result GetUserEncryptPubKeysResult 14 | if _, _, err := requestNSdk(urls, path, "GET", nil, nil, &result, false); err != nil { 15 | return nil, err 16 | } 17 | 18 | validate := validator.New() 19 | if err := validate.Struct(result); err != nil { 20 | return nil, err 21 | } 22 | 23 | return &result, nil 24 | } 25 | 26 | func TestGetUserEncryptPubKeys(t *testing.T) { 27 | t.Parallel() 28 | 29 | // create group 30 | createGroupParam := handlers.CreateGroupParam{ 31 | GroupName: "test-get-pubkeys", 32 | ConsensusType: "poa", 33 | EncryptionType: "private", 34 | AppKey: "default", 35 | IncludeChainUrl: true, 36 | } 37 | group, err := createGroup(peerapi, createGroupParam) 38 | if err != nil { 39 | t.Errorf("createGroup failed: %s, payload: %+v", err, createGroupParam) 40 | } 41 | 42 | _, urls, err := handlers.UrlToGroupSeed(group.Seed) 43 | if err != nil { 44 | t.Errorf("convert group send url failed: %s", err) 45 | } 46 | 47 | if _, err := getUserEncryptPubKeys(urls, group.GroupId); err != nil { 48 | t.Errorf("getUserEncryptPubKeys failed: %s", err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getannouncedgroupproducer.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags User 12 | // @Summary GetAnnouncedGroupProducer 13 | // @Description Get the list of group producers 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.AnnouncedProducerListItem 17 | // @Router /api/v1/group/{group_id}/announced/producers [get] 18 | func (h *Handler) GetAnnouncedGroupProducer(c echo.Context) (err error) { 19 | groupid := c.Param("group_id") 20 | 21 | res, err := handlers.GetAnnouncedGroupProducer(h.ChainAPIdb, groupid) 22 | if err != nil { 23 | return rumerrors.NewBadRequestError(err) 24 | } 25 | 26 | return c.JSON(http.StatusOK, res) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getannouncedgroupuser.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags User 12 | // @Summary GetAnnouncedGroupUsers 13 | // @Description Get the list of private group users 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.AnnouncedUserListItem 17 | // @Router /api/v1/group/{group_id}/announced/users [get] 18 | func (h *Handler) GetAnnouncedGroupUsers(c echo.Context) error { 19 | groupid := c.Param("group_id") 20 | 21 | res, err := handlers.GetAnnouncedGroupUsers(h.ChainAPIdb, groupid) 22 | if err != nil { 23 | return rumerrors.NewBadRequestError(err) 24 | } 25 | 26 | return c.JSON(http.StatusOK, res) 27 | } 28 | 29 | // @Tags User 30 | // @Summary GetAnnouncedGroupUser 31 | // @Description Get the one user announce status 32 | // @Produce json 33 | // @Param group_id path string true "Group Id" 34 | // @Param sign_pubkey path string true "User SignPubkey" 35 | // @Success 200 {object} handlers.AnnouncedUserListItem 36 | // @Router /api/v1/group/{group_id}/announced/user/{sign_pubkey} [get] 37 | func (h *Handler) GetAnnouncedGroupUser(c echo.Context) error { 38 | groupid := c.Param("group_id") 39 | sign_pubkey := c.Param("sign_pubkey") 40 | 41 | res, err := handlers.GetAnnouncedGroupUser(groupid, sign_pubkey) 42 | if err != nil { 43 | return rumerrors.NewBadRequestError(err) 44 | } 45 | 46 | return c.JSON(http.StatusOK, res) 47 | } 48 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getappconfigitem.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Management 12 | // @Summary GetAppConfigItem 13 | // @Description get app config item 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Param key path string true "itemKey" 17 | // @Success 200 {object} handlers.AppConfigKeyItem 18 | // @Router /api/v1/group/{group_id}/appconfig/{key} [get] 19 | func (h *Handler) GetAppConfigItem(c echo.Context) (err error) { 20 | groupId := c.Param("group_id") 21 | itemKey := c.Param("key") 22 | 23 | res, err := handlers.GetAppConfigByKey(itemKey, groupId) 24 | if err != nil { 25 | return rumerrors.NewBadRequestError(err) 26 | } 27 | 28 | return c.JSON(http.StatusOK, res) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getappconfigkey.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Management 12 | // @Summary GetAppConfigKey 13 | // @Description get app config key list 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.AppConfigKeyListItem 17 | // @Router /api/v1/group/{group_id}/appconfig/keylist [get] 18 | func (h *Handler) GetAppConfigKey(c echo.Context) (err error) { 19 | groupid := c.Param("group_id") 20 | res, err := handlers.GetAppConfigKeyList(groupid) 21 | if err != nil { 22 | return rumerrors.NewBadRequestError(err) 23 | } 24 | 25 | return c.JSON(http.StatusOK, res) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getblk.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strconv" 7 | 8 | "github.com/labstack/echo/v4" 9 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 10 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 11 | _ "github.com/rumsystem/quorum/pkg/pb" //import for swaggo 12 | ) 13 | 14 | // @Tags Chain 15 | // @Summary GetBlock 16 | // @Description Get a block from a group 17 | // @Produce json 18 | // @Param group_id path string true "Group Id" 19 | // @Param block_id path string true "Epoch" 20 | // @Success 200 {object} pb.Block 21 | // @Router /api/v1/block/{group_id}/{epoch} [get] 22 | func (h *Handler) GetBlock(c echo.Context) (err error) { 23 | groupid := c.Param("group_id") 24 | if groupid == "" { 25 | return rumerrors.NewBadRequestError("group_id can't be nil.") 26 | } 27 | 28 | blockIdStr := c.Param("block_id") 29 | blockId, err := strconv.ParseUint(blockIdStr, 10, 64) 30 | if err != nil { 31 | return c.JSON(http.StatusBadRequest, err.Error()) 32 | } 33 | 34 | groupmgr := chain.GetGroupMgr() 35 | if group, ok := groupmgr.Groups[groupid]; ok { 36 | block, err := group.GetBlock(blockId) 37 | if err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | 41 | return c.JSON(http.StatusOK, block) 42 | } else { 43 | return rumerrors.NewBadRequestError(fmt.Sprintf("Group %s not exist", groupid)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getbootstrapnodeinfo.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 8 | ) 9 | 10 | // @Tags Node 11 | // @Summary GetBootstrapNodeInfo 12 | // @Description Return the bootstrap node info 13 | // @Produce json 14 | // @Success 200 {object} map[string]string 15 | // @Router /api/v1/node [get] 16 | func (h *Handler) GetBootstrapNodeInfo(c echo.Context) (err error) { 17 | output := make(map[string]interface{}) 18 | output[NODE_STATUS] = "NODE_ONLINE" 19 | output[NODETYPE] = "bootstrap" 20 | output[NODE_ID] = nodectx.GetNodeCtx().PeerId.Pretty() 21 | return c.JSON(http.StatusOK, output) 22 | } 23 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getbootstrapnodeinfo_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/rumsystem/quorum/testnode" 8 | ) 9 | 10 | func TestGetBootstrapNodeInfo(t *testing.T) { 11 | t.Parallel() 12 | 13 | urlSuffix := "/api/v1/node" 14 | _, resp, err := testnode.RequestAPI(bootstrapapi, urlSuffix, "GET", "") 15 | if err != nil { 16 | t.Errorf("GET %s failed: %s", urlSuffix, err) 17 | } 18 | 19 | var data map[string]interface{} 20 | if err := json.Unmarshal(resp, &data); err != nil { 21 | t.Errorf("json.Unmarshal failed: %s, response: %s", err, resp) 22 | } 23 | 24 | expectKeys := []string{"node_status", "node_type", "node_id"} 25 | keys := GetMapKeys(data) 26 | if !StringSetEqual(expectKeys, keys) { 27 | t.Errorf("unexpected keys: %v, expect: %v", keys, expectKeys) 28 | } 29 | if data["node_status"] != "NODE_ONLINE" { 30 | t.Errorf("unexpected node_status: %s", data["node_status"]) 31 | } 32 | if data["node_type"] != "bootstrap" { 33 | t.Errorf("unexpected node_type: %s", data["node_type"]) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getchaintrxallowlist.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Management 12 | // @Summary GetChainTrxAllowList 13 | // @Description Get group allow list 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.ChainSendTrxRuleListItem 17 | // @Router /api/v1/group/{group_id}/trx/allowlist [get] 18 | func (h *Handler) GetChainTrxAllowList(c echo.Context) (err error) { 19 | groupid := c.Param("group_id") 20 | res, err := handlers.GetChainTrxAllowList(h.ChainAPIdb, groupid) 21 | if err != nil { 22 | return rumerrors.NewBadRequestError(err) 23 | } 24 | 25 | return c.JSON(http.StatusOK, res) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getchaintrxauthmode.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Management 13 | // @Summary GetChainTrxAuthMode 14 | // @Description GetChainTrxAuthMode 15 | // @Produce json 16 | // @Param group_id path string true "Group Id" 17 | // @Param trx_type path string true "trxType" 18 | // @Success 200 {array} handlers.TrxAuthItem 19 | // @Router /api/v1/group/{group_id}/trx/auth/{trx_type} [get] 20 | func (h *Handler) GetChainTrxAuthMode(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | params := new(handlers.TrxAuthParams) 23 | if err := cc.BindAndValidate(params); err != nil { 24 | return err 25 | } 26 | 27 | res, err := handlers.GetChainTrxAuthMode(h.ChainAPIdb, params.GroupId, params.TrxType) 28 | if err != nil { 29 | return rumerrors.NewBadRequestError(err) 30 | } 31 | 32 | return c.JSON(http.StatusOK, res) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getchaintrxdenylist.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Management 12 | // @Summary GetDeniedUserList 13 | // @Description Get the list of denied users 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.ChainSendTrxRuleListItem 17 | // @Router /api/v1/group/{group_id}/trx/denylist [get] 18 | func (h *Handler) GetChainTrxDenyList(c echo.Context) (err error) { 19 | groupid := c.Param("group_id") 20 | res, err := handlers.GetChainTrxDenyList(h.ChainAPIdb, groupid) 21 | if err != nil { 22 | return rumerrors.NewBadRequestError(err) 23 | } 24 | 25 | return c.JSON(http.StatusOK, res) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getgroupctn_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | func TestGetGroupContent(t *testing.T) { 12 | t.Parallel() 13 | 14 | // create group 15 | createGroupParam := handlers.CreateGroupParam{ 16 | GroupName: "test-group-content", 17 | ConsensusType: "poa", 18 | EncryptionType: "public", 19 | AppKey: "default", 20 | } 21 | group, err := createGroup(peerapi, createGroupParam) 22 | if err != nil { 23 | t.Errorf("createGroup failed: %s, payload: %+v", err, createGroupParam) 24 | } 25 | 26 | // join group 27 | joinGroupParam := handlers.JoinGroupParamV2{ 28 | Seed: group.Seed, 29 | } 30 | if _, err := joinGroup(peerapi2, joinGroupParam); err != nil { 31 | t.Errorf("joinGroup failed: %s, payload: %+v", err, joinGroupParam) 32 | } 33 | 34 | // post to group 35 | content := fmt.Sprintf("%s hello world", RandString(4)) 36 | name := fmt.Sprintf("%s post to group testing", RandString(4)) 37 | postGroupParam := PostGroupParam{ 38 | GroupID: group.GroupId, 39 | Data: map[string]interface{}{ 40 | "type": "Note", 41 | "content": content, 42 | "name": name, 43 | }, 44 | } 45 | 46 | postResult, err := postToGroup(peerapi, postGroupParam) 47 | if err != nil { 48 | t.Errorf("postToGroup failed: %s, payload: %+v", err, postGroupParam) 49 | } 50 | if postResult.TrxId == "" { 51 | t.Errorf("postToGroup failed: TrxId is empty") 52 | } 53 | 54 | // FIXME 55 | time.Sleep(time.Second * 30) 56 | 57 | // check peerapi received content 58 | for _, api := range []string{peerapi, peerapi2} { 59 | receivedContent, err := isReceivedGroupContent(api, group.GroupId, postResult.TrxId) 60 | if err != nil { 61 | t.Errorf("isReceivedGroupContent failed: %s", err) 62 | } 63 | if !receivedContent { 64 | t.Errorf("isReceivedGroupContent failed: content not received") 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getgroupproducer.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Management 12 | // @Summary GetGroupProducers 13 | // @Description Get the list of group producers 14 | // @Produce json 15 | // @Param group_id path string true "Group Id" 16 | // @Success 200 {array} handlers.ProducerListItem 17 | // @Router /api/v1/group/{group_id}/producers [get] 18 | func (h *Handler) GetGroupProducers(c echo.Context) (err error) { 19 | groupid := c.Param("group_id") 20 | if groupid == "" { 21 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 22 | } 23 | 24 | res, err := handlers.GetGroupProducers(h.ChainAPIdb, groupid) 25 | if err != nil { 26 | return rumerrors.NewBadRequestError(err) 27 | } 28 | 29 | return c.JSON(http.StatusOK, res) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getgroups_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | func TestGetGroups(t *testing.T) { 12 | t.Parallel() 13 | 14 | appKey := "default" 15 | consensusType := "poa" 16 | encryptionTypes := []string{"public", "private"} 17 | 18 | for _, encryptionType := range encryptionTypes { 19 | groupName := fmt.Sprintf("%s-%d", encryptionType, time.Now().Unix()) 20 | payload := handlers.CreateGroupParam{ 21 | AppKey: appKey, 22 | ConsensusType: consensusType, 23 | EncryptionType: encryptionType, 24 | GroupName: groupName, 25 | } 26 | 27 | if _, err := createGroup(peerapi, payload); err != nil { 28 | t.Errorf("create group failed: %s", err) 29 | } 30 | 31 | groups, err := getGroups(peerapi) 32 | if err != nil { 33 | t.Errorf("getGroups failed: %s", err) 34 | } 35 | 36 | if groups.GroupInfos == nil { 37 | t.Error("it should least one group, but groups is null") 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getgroupseed.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | "github.com/rumsystem/quorum/internal/pkg/utils" 10 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | ) 12 | 13 | // @Tags Groups 14 | // @Summary Get group seed 15 | // @Description get group seed from appdb 16 | // @Produce json 17 | // @Param group_id path string true "Group Id" 18 | // @Param include_chain_url query bool false "if include chain url" 19 | // @Success 200 {object} handlers.GetGroupSeedResult 20 | // @Router /api/v1/group/{group_id}/seed [get] 21 | func (h *Handler) GetGroupSeedHandler(c echo.Context) (err error) { 22 | cc := c.(*utils.CustomContext) 23 | var params handlers.GetGroupSeedParam 24 | if err := cc.BindAndValidate(¶ms); err != nil { 25 | return err 26 | } 27 | 28 | seed, err := handlers.GetGroupSeed(params.GroupId, h.Appdb) 29 | if err != nil { 30 | return rumerrors.NewBadRequestError(err) 31 | } 32 | 33 | var chainUrls []string 34 | 35 | if params.IncludeChainUrl { 36 | jwt, err := handlers.GetOrCreateGroupNodeJwt(params.GroupId) 37 | if err != nil { 38 | return rumerrors.NewInternalServerError(err) 39 | } 40 | 41 | // get chain api url 42 | baseUrl := cc.GetBaseURLFromRequest() 43 | chainapiUrl, err := utils.GetChainapiURL(baseUrl, jwt) 44 | if err != nil { 45 | return rumerrors.NewBadRequestError(err) 46 | } 47 | chainUrls = append(chainUrls, chainapiUrl) 48 | } 49 | 50 | seedurl, err := handlers.GroupSeedToUrl(1, chainUrls, seed) 51 | if err != nil { 52 | return rumerrors.NewInternalServerError(fmt.Sprintf("seedurl output failed: %s", err)) 53 | } 54 | 55 | result := handlers.GetGroupSeedResult{ 56 | Seed: seedurl, 57 | } 58 | return c.JSON(http.StatusOK, result) 59 | } 60 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getgroupseed_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | "time" 8 | 9 | "github.com/go-playground/validator/v10" 10 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | "github.com/rumsystem/quorum/testnode" 12 | ) 13 | 14 | func getGroupSeed(api string, groupID string) (*handlers.GetGroupSeedResult, error) { 15 | path := fmt.Sprintf("/api/v1/group/%s/seed", groupID) 16 | _, resp, err := testnode.RequestAPI(api, path, "GET", "") 17 | if err != nil { 18 | return nil, fmt.Errorf("get group seed failed: %s", err) 19 | } 20 | 21 | if err := getResponseError(resp); err != nil { 22 | return nil, err 23 | } 24 | 25 | var seed handlers.GetGroupSeedResult 26 | if err := json.Unmarshal(resp, &seed); err != nil { 27 | e := fmt.Errorf("response Unmarshal failed: %s, response: %s", err, resp) 28 | return nil, e 29 | } 30 | 31 | validate := validator.New() 32 | if err := validate.Struct(seed); err != nil { 33 | return nil, err 34 | } 35 | 36 | seedObj, _, err := handlers.UrlToGroupSeed(seed.Seed) 37 | if err != nil { 38 | return nil, err 39 | } 40 | if seedObj.GroupId != groupID { 41 | return nil, fmt.Errorf("group id not match, expect: %s, actual: %s", groupID, seedObj.GroupId) 42 | } 43 | 44 | return &seed, nil 45 | } 46 | 47 | func TestGetGroupSeed(t *testing.T) { 48 | t.Parallel() 49 | 50 | payload := handlers.CreateGroupParam{ 51 | AppKey: "default", 52 | ConsensusType: "poa", 53 | EncryptionType: "public", 54 | GroupName: fmt.Sprintf("test-seed-%d", time.Now().Unix()), 55 | } 56 | 57 | group, err := createGroup(peerapi, payload) 58 | if err != nil { 59 | t.Fatalf("create group failed: %s", err) 60 | } 61 | 62 | if _, err := getGroupSeed(peerapi, group.GroupId); err != nil { 63 | t.Fatalf("get group seed failed: %s", err) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getnetwork.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/libp2p/go-libp2p/core/host" 8 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p" 9 | "github.com/rumsystem/quorum/internal/pkg/options" 10 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | ) 12 | 13 | // @Tags Node 14 | // @Summary GetNetwork 15 | // @Description Get node's network information 16 | // @Produce json 17 | // @Success 200 {object} handlers.NetworkInfo 18 | // @Router /api/v1/network [get] 19 | func (h *Handler) GetNetwork(nodehost *host.Host, nodeinfo *p2p.NodeInfo, nodeopt *options.NodeOptions, ethaddr string) echo.HandlerFunc { 20 | return func(c echo.Context) error { 21 | result, err := handlers.GetNetwork(nodehost, nodeinfo, nodeopt, ethaddr) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | return c.JSON(http.StatusOK, result) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getnetwork_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/go-playground/validator/v10" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | "github.com/rumsystem/quorum/testnode" 10 | ) 11 | 12 | func TestGetNetwork(t *testing.T) { 13 | t.Parallel() 14 | 15 | _, resp, err := testnode.RequestAPI(peerapi, "/api/v1/network", "GET", "") 16 | if err != nil { 17 | t.Errorf("get network failed: %s", err) 18 | } 19 | 20 | if err := getResponseError(resp); err != nil { 21 | t.Errorf("request failed: %s, response: %s", err, resp) 22 | } 23 | 24 | var network handlers.NetworkInfo 25 | if err := json.Unmarshal(resp, &network); err != nil { 26 | t.Errorf("response data Unmarshal error: %s", err) 27 | } 28 | 29 | validate := validator.New() 30 | if err := validate.Struct(network); err != nil { 31 | t.Errorf("response data invalid: %s, response: %+v", err, network) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getnodeinfo.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | // @Tags Node 12 | // @Summary GetNodeInfo 13 | // @Description Return the node info 14 | // @Produce json 15 | // @Success 200 {object} handlers.NodeInfo 16 | // @Router /api/v1/node [get] 17 | func (h *Handler) GetNodeInfo(c echo.Context) (err error) { 18 | info, err := handlers.GetNodeInfo(h.Node.NetworkName) 19 | if err != nil { 20 | return rumerrors.NewBadRequestError(err) 21 | } 22 | 23 | return c.JSON(http.StatusOK, info) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/chainapi/api/getnodeinfo_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/go-playground/validator/v10" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | "github.com/rumsystem/quorum/testnode" 10 | ) 11 | 12 | func getNodeInfo(api string) (*handlers.NodeInfo, error) { 13 | _, resp, err := testnode.RequestAPI(api, "/api/v1/node", "GET", "") 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | var info handlers.NodeInfo 19 | if err := json.Unmarshal(resp, &info); err != nil { 20 | return nil, err 21 | } 22 | 23 | validate := validator.New() 24 | if err != validate.Struct(info) { 25 | return nil, err 26 | } 27 | 28 | return &info, nil 29 | } 30 | 31 | func getNodePublicKey(api string) (string, error) { 32 | info, err := getNodeInfo(api) 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | return info.NodePublickey, nil 38 | } 39 | 40 | func TestGetNodeInfo(t *testing.T) { 41 | t.Parallel() 42 | 43 | if _, err := getNodeInfo(peerapi); err != nil { 44 | t.Fatalf("getNodeInfo failed: %s", err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pkg/chainapi/api/gettrx.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Chain 13 | // @Summary GetTrx 14 | // @Description Get a transaction a group 15 | // @Produce json 16 | // @Param group_id path string true "Group Id" 17 | // @Param trx_id path string true "Transaction Id" 18 | // @Success 200 {object} pb.Trx 19 | // @Router /api/v1/trx/{group_id}/{trx_id} [get] 20 | func (h *Handler) GetTrx(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | var params handlers.GetTrxParam 23 | if err := cc.BindAndValidate(¶ms); err != nil { 24 | return err 25 | } 26 | 27 | trx, err := handlers.GetTrx(params.GroupId, params.TrxId) 28 | if err != nil { 29 | return rumerrors.NewBadRequestError(err) 30 | } 31 | 32 | return c.JSON(http.StatusOK, trx) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/api/handle.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/appdata" 7 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p" 8 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 9 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 10 | ) 11 | 12 | type ( 13 | Handler struct { 14 | Ctx context.Context 15 | Node *p2p.Node 16 | NodeCtx *nodectx.NodeCtx 17 | GitCommit string 18 | Appdb *appdata.AppDb 19 | ChainAPIdb def.APIHandlerIface 20 | WebsocketManager *WebsocketManager 21 | } 22 | ) 23 | -------------------------------------------------------------------------------- /pkg/chainapi/api/joingroup_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/go-playground/validator/v10" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | "github.com/rumsystem/quorum/testnode" 11 | ) 12 | 13 | func joinGroup(api string, payload handlers.JoinGroupParamV2) (*JoinGroupResult, error) { 14 | payloadByte, err := json.Marshal(payload) 15 | if err != nil { 16 | e := fmt.Errorf("json.Marshal failed: %s, joinGroupParam: %+v", err, payload) 17 | return nil, e 18 | } 19 | 20 | payloadStr := string(payloadByte[:]) 21 | urlPath := "/api/v2/group/join" 22 | _, resp, err := testnode.RequestAPI(api, urlPath, "POST", payloadStr) 23 | if err != nil { 24 | e := fmt.Errorf("request %s failed: %s, payload: %s", urlPath, err, payloadStr) 25 | return nil, e 26 | } 27 | 28 | if err := getResponseError(resp); err != nil { 29 | return nil, err 30 | } 31 | 32 | var result JoinGroupResult 33 | if err := json.Unmarshal(resp, &result); err != nil { 34 | e := fmt.Errorf("json.Unmarshal failed: %s, response: %s", err, resp) 35 | return nil, e 36 | } 37 | 38 | validate := validator.New() 39 | if err := validate.Struct(result); err != nil { 40 | e := fmt.Errorf("join group response body invalid: %s, response: %+v", err, result) 41 | return nil, e 42 | } 43 | 44 | return &result, nil 45 | } 46 | 47 | func TestJoinGroup(t *testing.T) { 48 | t.Parallel() 49 | 50 | // create group 51 | createGroupParam := handlers.CreateGroupParam{ 52 | GroupName: "test-join-group", 53 | ConsensusType: "poa", 54 | EncryptionType: "public", 55 | AppKey: "default", 56 | } 57 | group, err := createGroup(peerapi, createGroupParam) 58 | if err != nil { 59 | t.Errorf("create group failed: %s, payload: %+v", err, createGroupParam) 60 | } 61 | 62 | // join group 63 | joinGroupParam := handlers.JoinGroupParamV2{ 64 | Seed: group.Seed, 65 | } 66 | 67 | if _, err := joinGroup(peerapi2, joinGroupParam); err != nil { 68 | t.Errorf("joinGroup failed: %s, payload: %+v", err, joinGroupParam) 69 | } 70 | 71 | // check if it in group list 72 | inGroup, err := isInGroup(peerapi2, group.GroupId) 73 | if err != nil { 74 | t.Errorf("isInGroup failed: %s", err) 75 | } 76 | if !inGroup { 77 | t.Errorf("joined in group, but it is not in group list") 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pkg/chainapi/api/leavegroup.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Groups 13 | // @Summary LeaveGroup 14 | // @Description Leave a new group 15 | // @Accept json 16 | // @Produce json 17 | // @Param data body handlers.LeaveGroupParam true "LeaveGroupParam" 18 | // @success 200 {object} handlers.LeaveGroupResult "LeaveGroupResult" 19 | // @Router /api/v1/group/leave [post] 20 | func (h *Handler) LeaveGroup(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | params := new(handlers.LeaveGroupParam) 23 | 24 | if err := cc.BindAndValidate(params); err != nil { 25 | return err 26 | } 27 | 28 | res, err := handlers.LeaveGroup(params, h.Appdb) 29 | if err != nil { 30 | return rumerrors.NewBadRequestError(err) 31 | } 32 | 33 | return c.JSON(http.StatusOK, res) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/chainapi/api/leavegroup_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 7 | ) 8 | 9 | func TestLeaveGroup(t *testing.T) { 10 | t.Skip() 11 | t.Parallel() 12 | 13 | // create group 14 | createGroupParam := handlers.CreateGroupParam{ 15 | GroupName: "test-leave-group", 16 | ConsensusType: "poa", 17 | EncryptionType: "public", 18 | AppKey: "default", 19 | } 20 | group, err := createGroup(peerapi, createGroupParam) 21 | if err != nil { 22 | t.Errorf("createGroup failed: %s, payload: %+v", err, createGroupParam) 23 | } 24 | 25 | // join group 26 | joinGroupParam := handlers.JoinGroupParamV2{ 27 | Seed: group.Seed, 28 | } 29 | if _, err := joinGroup(peerapi2, joinGroupParam); err != nil { 30 | t.Errorf("joinGroup failed: %s, payload: %+v", err, joinGroupParam) 31 | } 32 | 33 | // list my group 34 | inGroup, err := isInGroup(peerapi2, group.GroupId) 35 | if err != nil { 36 | t.Errorf("isInGroup failed: %s", err) 37 | } 38 | if !inGroup { 39 | t.Errorf("try to joined in group, but it not in group list") 40 | } 41 | 42 | // leave group 43 | leaveGroupParam := handlers.LeaveGroupParam{ 44 | GroupId: group.GroupId, 45 | } 46 | _, err = leaveGroup(peerapi2, leaveGroupParam) 47 | if err != nil { 48 | t.Errorf("leaveGroup failed: %s", err) 49 | } 50 | 51 | // clear group, NOTE: need stop sync? 52 | if _, err := clearGroup(peerapi2, handlers.ClearGroupDataParam{GroupId: group.GroupId}); err != nil { 53 | t.Fatalf("clearGroup failed: %s", err) 54 | } 55 | 56 | // check group list 57 | inGroup, err = isInGroup(peerapi2, group.GroupId) 58 | if err != nil { 59 | t.Errorf("isInGroup failed: %s", err) 60 | } 61 | if inGroup { 62 | t.Errorf("left group, but it still in group list") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/chainapi/api/metrics.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "strings" 7 | 8 | "github.com/labstack/echo/v4" 9 | "github.com/prometheus/client_golang/prometheus" 10 | dto "github.com/prometheus/client_model/go" 11 | "github.com/prometheus/common/expfmt" 12 | "github.com/prometheus/prom2json" 13 | ) 14 | 15 | func (h *Handler) Metrics(c echo.Context) error { 16 | out := &bytes.Buffer{} 17 | metricFamilies, _ := prometheus.DefaultGatherer.Gather() 18 | for i := range metricFamilies { 19 | expfmt.MetricFamilyToText(out, metricFamilies[i]) 20 | 21 | } 22 | 23 | contentType := strings.ToLower(c.Request().Header.Get("Content-Type")) 24 | if strings.Contains(contentType, "application/json") { 25 | mfChan := make(chan *dto.MetricFamily, 1024) 26 | if err := prom2json.ParseReader(out, mfChan); err != nil { 27 | return err 28 | } 29 | result := []*prom2json.Family{} 30 | for mf := range mfChan { 31 | result = append(result, prom2json.NewFamily(mf)) 32 | } 33 | return c.JSON(http.StatusOK, result) 34 | } else { // plain text 35 | return c.String(http.StatusOK, string(out.Bytes())) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/chainapi/api/mgrappconfig.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Management 13 | // @Summary MgrAppConfig 14 | // @Description set app config 15 | // @Produce json 16 | // @Accept json 17 | // @Param data body handlers.AppConfigParam true "AppConfigParam" 18 | // @Success 200 {object} handlers.AppConfigResult 19 | // @Router /api/v1/group/appconfig [post] 20 | func (h *Handler) MgrAppConfig(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | 23 | params := new(handlers.AppConfigParam) 24 | if err := cc.BindAndValidate(params); err != nil { 25 | return err 26 | } 27 | 28 | res, err := handlers.MgrAppConfig(params) 29 | if err != nil { 30 | return rumerrors.NewBadRequestError(err) 31 | } 32 | 33 | return c.JSON(http.StatusOK, res) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/chainapi/api/mgrchainconfig.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Management 13 | // @Summary chainconfig 14 | // @Description chain config 15 | // @Accept json 16 | // @Produce json 17 | // @Param data body handlers.ChainConfigParams true "ChainConfigParams" 18 | // @Success 200 {object} handlers.ChainConfigResult 19 | // @Router /api/v1/group/chainconfig [post] 20 | func (h *Handler) MgrChainConfig(c echo.Context) (err error) { 21 | cc := c.(*utils.CustomContext) 22 | 23 | params := new(handlers.ChainConfigParams) 24 | if err := cc.BindAndValidate(params); err != nil { 25 | return err 26 | } 27 | 28 | res, err := handlers.MgrChainConfig(params) 29 | if err != nil { 30 | return rumerrors.NewBadRequestError(err) 31 | } 32 | 33 | return c.JSON(http.StatusOK, res) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/chainapi/api/mgrchainconfig_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | "time" 9 | 10 | handlers "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | ) 12 | 13 | func TestSetChainTrxAuthMode(t *testing.T) { 14 | t.Parallel() 15 | 16 | // create group 17 | payload := handlers.CreateGroupParam{ 18 | AppKey: "default", 19 | ConsensusType: "poa", 20 | EncryptionType: "public", 21 | GroupName: fmt.Sprintf("public-%d", time.Now().Unix()), 22 | } 23 | 24 | group, err := createGroup(peerapi, payload) 25 | if err != nil { 26 | t.Errorf("create group failed: %s", err) 27 | } 28 | 29 | trxAuthModes := []string{"follow_alw_list", "follow_dny_list"} 30 | for _, trxAuthMode := range trxAuthModes { 31 | for _, trxType := range trxTypes { 32 | authParams := handlers.TrxAuthModeParams{ 33 | TrxType: trxType, 34 | TrxAuthMode: trxAuthMode, 35 | } 36 | authBytes, err := json.Marshal(authParams) 37 | if err != nil { 38 | t.Errorf("json.Marshal failed: %s", err) 39 | } 40 | 41 | payload := handlers.ChainConfigParams{ 42 | GroupId: group.GroupId, 43 | Type: "set_trx_auth_mode", 44 | Config: string(authBytes), 45 | Memo: fmt.Sprintf("memo-%d", time.Now().Unix()), 46 | } 47 | 48 | if _, err := updateChainConfig(peerapi, payload); err != nil { 49 | t.Errorf("update chain config with payload: %+v failed: %s", payload, err) 50 | } 51 | 52 | time.Sleep(25 * time.Second) 53 | authItem, err := getChainTrxAuthMode(peerapi, handlers.TrxAuthParams{GroupId: group.GroupId, TrxType: trxType}) 54 | if err != nil { 55 | t.Errorf("get chain trx auth mode failed: %s", err) 56 | } 57 | if authItem.AuthType != strings.ToUpper(trxAuthMode) { 58 | t.Errorf("auth type not match, expect: %s, actual: %s", strings.ToUpper(trxAuthMode), authItem.AuthType) 59 | } 60 | } 61 | } 62 | } 63 | 64 | func updateChainConfig(api string, payload handlers.ChainConfigParams) (*handlers.ChainConfigResult, error) { 65 | var result handlers.ChainConfigResult 66 | _, _, err := requestAPI(api, "/api/v1/group/chainconfig", "POST", payload, nil, &result, false) 67 | if err != nil { 68 | e := fmt.Errorf("update group chain config failed: %s", err) 69 | return nil, e 70 | } 71 | 72 | return &result, nil 73 | } 74 | -------------------------------------------------------------------------------- /pkg/chainapi/api/nsdk_announce.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | "github.com/rumsystem/quorum/internal/pkg/utils" 10 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 12 | ) 13 | 14 | type ( 15 | NSdkAnnounceParams struct { 16 | GroupId string `param:"group_id" json:"-" validate:"required"` 17 | Data *quorumpb.AnnounceItem `json:"data" validate:"required"` 18 | } 19 | ) 20 | 21 | // @Tags LightNode 22 | // @Summary NSdkAnnounce 23 | // @Description Announce User's encryption Pubkey to the group for light node 24 | // @Accept json 25 | // @Produce json 26 | // @Param group_id path string true "Group Id" 27 | // @Param data body NSdkAnnounceParams true "AnnounceParam" 28 | // @Success 200 {object} handlers.AnnounceResult 29 | // @Router /api/v1/node/{group_id}/announce [post] 30 | func (h *Handler) NSdkAnnounce(c echo.Context) (err error) { 31 | cc := c.(*utils.CustomContext) 32 | payload := new(NSdkAnnounceParams) 33 | if err := cc.BindAndValidate(payload); err != nil { 34 | return err 35 | } 36 | 37 | groupmgr := chain.GetGroupMgr() 38 | group, ok := groupmgr.Groups[payload.GroupId] 39 | if !ok { 40 | return rumerrors.NewBadRequestError("INVALID_GROUP") 41 | } 42 | 43 | item := payload.Data 44 | trxId, err := group.UpdAnnounce(item) 45 | if err != nil { 46 | return err 47 | } 48 | var result *handlers.AnnounceResult 49 | result = &handlers.AnnounceResult{ 50 | GroupId: item.GroupId, 51 | AnnouncedSignPubkey: item.SignPubkey, 52 | AnnouncedEncryptPubkey: item.EncryptPubkey, 53 | Type: item.Type.String(), 54 | Action: item.Action.String(), 55 | Sign: item.AnnouncerSignature, 56 | TrxId: trxId, 57 | } 58 | 59 | return c.JSON(http.StatusOK, result) 60 | } 61 | -------------------------------------------------------------------------------- /pkg/chainapi/api/nsdk_groupctn.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | "github.com/rumsystem/quorum/internal/pkg/utils" 10 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 11 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 12 | ) 13 | 14 | // @Tags LightNode 15 | // @Summary GetNSdkContent 16 | // @Description get content 17 | // @Accept json 18 | // @Produce json 19 | // @Param group_id path string true "Group Id" 20 | // @Param get_content_params query handlers.GetGroupCtnPrarms true "get group content params" 21 | // @Success 200 {object} []quorumpb.Trx 22 | // @Router /api/v1/node/{group_id}/groupctn [get] 23 | func (h *Handler) GetNSdkContent(c echo.Context) (err error) { 24 | cc := c.(*utils.CustomContext) 25 | params := new(handlers.GetGroupCtnPrarms) 26 | if err := cc.BindAndValidate(params); err != nil { 27 | return err 28 | } 29 | 30 | groupmgr := chain.GetGroupMgr() 31 | group, ok := groupmgr.Groups[params.GroupId] 32 | if !ok { 33 | return rumerrors.NewBadRequestError(rumerrors.ErrGroupNotFound) 34 | } 35 | 36 | if params.Num == 0 { 37 | params.Num = 20 38 | } 39 | 40 | trxids, err := h.Appdb.GetGroupContentBySenders( 41 | params.GroupId, 42 | params.Senders, 43 | params.StartTrx, 44 | params.Num, 45 | params.Reverse, 46 | params.IncludeStartTrx, 47 | ) 48 | if err != nil { 49 | return rumerrors.NewBadRequestError(err) 50 | } 51 | 52 | trxList := []*quorumpb.Trx{} 53 | for _, trxid := range trxids { 54 | trx, err := group.GetTrx(trxid) 55 | if err != nil { 56 | c.Logger().Errorf("GetTrx Err: %s", err) 57 | continue 58 | } 59 | if trx != nil && trx.TrxId != "" { 60 | trxList = append(trxList, trx) 61 | } 62 | } 63 | 64 | return c.JSON(http.StatusOK, trxList) 65 | } 66 | -------------------------------------------------------------------------------- /pkg/chainapi/api/nsdk_userencryptpubkeys.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | "github.com/rumsystem/quorum/internal/pkg/utils" 10 | ) 11 | 12 | type ( 13 | GetNSdkUserEncryptPubKeysParams struct { 14 | GroupId string `param:"group_id" json:"group_id" url:"group_id" validate:"required,uuid4" example:"78cbab65-17e7-49d2-892a-311cec77c120"` 15 | } 16 | 17 | GetUserEncryptPubKeysResult struct { 18 | Keys []string `json:"keys" example:"age1gcd6v44ys4u72ljc543er65sj8qlscnwqp2nm4m9yg7zwcc0648q7swrka,age1fxfkenckddacqpm9ar3wvyg4ek32p9d7rlyz28y4catzfhjw4ggs8fvdl5"` 19 | } 20 | ) 21 | 22 | // @Tags LightNode 23 | // @Summary GetNSdkUserEncryptPubKeys 24 | // @Description get user encrypt pub keys 25 | // @Accept json 26 | // @Produce json 27 | // @Param group_id path string true "Group Id" 28 | // @Success 200 {object} GetUserEncryptPubKeysResult 29 | // @Router /api/v1/node/{group_id}/userencryptpubkeys [get] 30 | func (h *Handler) GetNSdkUserEncryptPubKeys(c echo.Context) (err error) { 31 | cc := c.(*utils.CustomContext) 32 | param := GetNSdkUserEncryptPubKeysParams{} 33 | if err := cc.BindAndValidate(¶m); err != nil { 34 | return err 35 | } 36 | groupmgr := chain.GetGroupMgr() 37 | group, ok := groupmgr.Groups[param.GroupId] 38 | if !ok { 39 | return rumerrors.NewBadRequestError("INVALID_GROUP") 40 | } 41 | 42 | keys, err := group.ChainCtx.GetUsesEncryptPubKeys() 43 | if err != nil { 44 | return err 45 | } 46 | 47 | result := GetUserEncryptPubKeysResult{Keys: keys} 48 | return c.JSON(http.StatusOK, result) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/chainapi/api/opa_helper.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/labstack/echo/v4" 7 | "github.com/rumsystem/quorum/internal/pkg/logging" 8 | appapi "github.com/rumsystem/quorum/pkg/chainapi/appapi" 9 | ) 10 | 11 | var opaLogger = logging.Logger("opa") 12 | 13 | func opaInputFunc(c echo.Context) interface{} { 14 | token, err := appapi.GetJWTToken(c) 15 | if err != nil { 16 | opaLogger.Warnf("get jwt failed: %s", err) 17 | return nil 18 | } 19 | 20 | r := c.Request() 21 | return map[string]interface{}{ 22 | "method": r.Method, 23 | "path": strings.Split(strings.Trim(r.URL.Path, "/"), "/"), 24 | "role": appapi.GetJWTRole(token), 25 | "allow_groups": appapi.GetJWTAllowGroups(token), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/chainapi/api/posttogroup.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | // @Tags Groups 13 | // @Summary PostToGroup 14 | // @Description Post object to a group 15 | // @Accept json 16 | // @Produce json 17 | // @Param group_id path string true "Group Id" 18 | // @Param data body handlers.PostToGroupParam true "payload" 19 | // @Success 200 {object} handlers.TrxResult 20 | // @Router /api/v1/group/{group_id}/content [post] 21 | func (h *Handler) PostToGroup(c echo.Context) (err error) { 22 | cc := c.(*utils.CustomContext) 23 | payload := handlers.PostToGroupParam{} 24 | if err := cc.BindAndValidate(&payload); err != nil { 25 | return err 26 | } 27 | 28 | res, err := handlers.PostToGroup(&payload) 29 | if err != nil { 30 | return rumerrors.NewBadRequestError(err) 31 | } 32 | 33 | return c.JSON(http.StatusOK, res) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/chainapi/api/posttogroup_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 7 | ) 8 | 9 | func TestPostToGroup(t *testing.T) { 10 | t.Parallel() 11 | 12 | // create group 13 | createGroupParam := handlers.CreateGroupParam{ 14 | GroupName: "test-post", 15 | ConsensusType: "poa", 16 | EncryptionType: "public", 17 | AppKey: "default", 18 | } 19 | group, err := createGroup(peerapi, createGroupParam) 20 | if err != nil { 21 | t.Errorf("createGroup failed: %s, payload: %+v", err, createGroupParam) 22 | } 23 | 24 | // join group 25 | joinGroupParam := handlers.JoinGroupParamV2{ 26 | Seed: group.Seed, 27 | } 28 | if _, err := joinGroup(peerapi2, joinGroupParam); err != nil { 29 | t.Errorf("joinGroup failed: %s, payload: %+v", err, joinGroupParam) 30 | } 31 | 32 | // post to group 33 | postGroupParam := PostGroupParam{ 34 | Data: map[string]interface{}{ 35 | "type": "Note", 36 | "content": "Hello World", 37 | "name": "post to group testing", 38 | }, 39 | GroupID: group.GroupId, 40 | } 41 | 42 | postResult, err := postToGroup(peerapi, postGroupParam) 43 | if err != nil { 44 | t.Errorf("postToGroup failed: %s, payload: %+v", err, postGroupParam) 45 | } 46 | if postResult.TrxId == "" { 47 | t.Errorf("postToGroup failed: TrxId is empty") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /pkg/chainapi/api/producer.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | // @Tags Management 10 | // @Summary AddProducer 11 | // @Description add a peer to the group producer list 12 | // @Accept json 13 | // @Produce json 14 | // @Param data body handlers.GrpProducerParam true "GrpProducerParam" 15 | // @Success 200 {object} handlers.GrpProducerResult 16 | // @Router /api/v1/group/producer [post] 17 | func (h *Handler) GroupProducer(c echo.Context) (err error) { 18 | return c.JSON(http.StatusMethodNotAllowed, "API UNDER CONSTRUCTION") 19 | /* 20 | cc := c.(*utils.CustomContext) 21 | params := new(handlers.GrpProducerParam) 22 | if err := cc.BindAndValidate(params); err != nil { 23 | return err 24 | } 25 | 26 | res, err := handlers.GroupProducer(h.ChainAPIdb, params) 27 | if err != nil { 28 | return rumerrors.NewBadRequestError(err) 29 | } 30 | 31 | return c.JSON(http.StatusOK, res) 32 | */ 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/api/seed.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | type SeedUrlextendParam struct { 13 | SeedURL string `json:"seed" validate:"required,url" example:"rum://seed?v=1&e=0&n=0&b=tknSczG2RC6hEBTXZyig7w&c=Za8zI2nAWaTNSvSv6cnPPxHCZef9sGtKtgsZ8iSxj0E&g=SfGcugfLTZ68Hc-xscFwMQ&k=AnRP4sojIvAH-Ugqnd7ZaM1H8j_c1pX6clyeXgAORiGZ&s=mrcA0LDzo54zUujZTINvWM_k2HSifv2T4JfYHAY2EzsCRGdR5vxHbvVNStlJOOBK_ohT6vFGs0FDk2pWYVRPUQE&t=FyvyFrtDGC0&a=timeline.dev&y=group_timeline&u=http%3A%2F%2F1.2.3.4%3A6090%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhbGxvd0dyb3VwcyI6WyI0OWYxOWNiYS0wN2NiLTRkOWUtYmMxZC1jZmIxYjFjMTcwMzEiXSwiZXhwIjoxODI3Mzc0MjgyLCJuYW1lIjoiYWxsb3ctNDlmMTljYmEtMDdjYi00ZDllLWJjMWQtY2ZiMWIxYzE3MDMxIiwicm9sZSI6Im5vZGUifQ.rr_tYm0aUdmOeM0EYVzNpKmoNDOpSGzD38s6tjlxuCo"` 14 | } 15 | 16 | type SeedUrlextendResult struct { 17 | Seed handlers.GroupSeed `json:"seed" validate:"required"` 18 | ChainapiUrls []string `json:"urls" validate:"required,gte=1,dive,required,url" example:"http://1.2.3.4:6090?jwt=xxx|https://xxx.com?jwt=yyy"` // multi items separate by `|` 19 | } 20 | 21 | func (h *Handler) SeedUrlextend(c echo.Context) error { 22 | cc := c.(*utils.CustomContext) 23 | 24 | param := new(SeedUrlextendParam) 25 | if err := cc.BindAndValidate(param); err != nil { 26 | return rumerrors.NewBadRequestError(err) 27 | } 28 | 29 | seed, urls, err := handlers.UrlToGroupSeed(param.SeedURL) 30 | if err != nil { 31 | return rumerrors.NewBadRequestError(err) 32 | } 33 | 34 | res := SeedUrlextendResult{ 35 | Seed: *seed, 36 | ChainapiUrls: urls, 37 | } 38 | 39 | return c.JSON(http.StatusOK, res) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/chainapi/api/startsync.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | ) 10 | 11 | type StartSyncResult struct { 12 | GroupId string `validate:"required"` 13 | Error string 14 | } 15 | 16 | // @Tags Group 17 | // @Summary StartSync 18 | // @Description Start sync 19 | // @Produce json 20 | // @Param group_id path string true "Group Id" 21 | // @Success 200 {object} StartSyncResult 22 | // @Router /api/v1/group/{group_id}/startsync [post] 23 | func (h *Handler) StartSync(c echo.Context) (err error) { 24 | groupid := c.Param("group_id") 25 | 26 | res, err := handlers.StartSync(groupid) 27 | if err != nil { 28 | return rumerrors.NewBadRequestError(err) 29 | } 30 | 31 | return c.JSON(http.StatusOK, res) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/chainapi/api/tools.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 10 | ) 11 | 12 | type PubkeyParam struct { 13 | EncodedPubkey string `from:"encoded_pubkey" json:"encoded_pubkey" validate:"required" example:"CAISIQPPewVN6uF9kAPmPl3XvDufBNGQhazxqk+nRnvBVFQgcw=="` 14 | } 15 | 16 | type PubkeyToEthaddrResult struct { 17 | Addr string `json:"addr" example:"0xC90B320afad63d82Fa2c888C47B54ADd5CDD2452"` 18 | } 19 | 20 | // @Tags Tools 21 | // @Summary PubkeyToEthaddr 22 | // @Description Convert a based64 encoded libp2p pubkey to the eth address 23 | // @Accept json 24 | // @Produce json 25 | // @Param data body PubkeyParam true "PubkeyParam" 26 | // @Success 200 {object} PubkeyToEthaddrResult 27 | // @Router /api/v1/tools/pubkeytoaddr [post] 28 | func (h *Handler) PubkeyToEthaddr(c echo.Context) (err error) { 29 | cc := c.(*utils.CustomContext) 30 | 31 | input := new(PubkeyParam) 32 | if err := cc.BindAndValidate(input); err != nil { 33 | return err 34 | } 35 | 36 | ethaddr, err := localcrypto.Libp2pPubkeyToEthaddr(input.EncodedPubkey) 37 | if err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | 41 | result := PubkeyToEthaddrResult{Addr: ethaddr} 42 | return c.JSON(http.StatusOK, result) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/chainapi/appapi/config.go: -------------------------------------------------------------------------------- 1 | package appapi 2 | 3 | //const name 4 | const GROUP_NAME string = "group_name" 5 | const GROUP_ID string = "group_id" 6 | const GROUP_OWNER_PUBKEY string = "owner_pubkey" 7 | const GROUP_ITEMS string = "group_items" 8 | const GROUP_ITEM string = "group_item" 9 | const GENESIS_BLOCK string = "genesis_block" 10 | const NODE_VERSION string = "node_version" 11 | const NODE_PUBKEY string = "node_publickey" 12 | const NODE_STATUS string = "node_status" 13 | const NODE_ID string = "node_id" 14 | const SIGNATURE string = "signature" 15 | const TRX_ID string = "trx_id" 16 | const PEERS string = "peers" 17 | const NODETYPE string = "node_type" 18 | 19 | //error 20 | const ERROR_INFO string = "error" 21 | -------------------------------------------------------------------------------- /pkg/chainapi/appapi/handle.go: -------------------------------------------------------------------------------- 1 | package appapi 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rumsystem/quorum/internal/pkg/appdata" 7 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 8 | ) 9 | 10 | type Handler struct { 11 | Ctx context.Context 12 | Appdb *appdata.AppDb 13 | Trxdb def.TrxStorageIface 14 | Apiroot string 15 | GitCommit string 16 | ConfigDir string 17 | PeerName string 18 | NodeName string 19 | } 20 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/addpeers.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p/core/peer" 5 | maddr "github.com/multiformats/go-multiaddr" 6 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 7 | ) 8 | 9 | // AddPeerParam list of multiaddr 10 | type AddPeerParam []string // Example: ["/ip4/94.23.17.189/tcp/62777/p2p/16Uiu2HAm5waftP3s4oE1EzGF2SyWeK726P5B8BSgFJqSiz6xScGz", "/ip4/132.145.109.63/tcp/10666/p2p/16Uiu2HAmTovb8kAJiYK8saskzz7cRQhb45NRK5AsbtdmYsLfD3RM"] 11 | 12 | type AddPeerResult struct { 13 | SuccCount int `json:"succ_count" example:"100"` 14 | ErrCount int `json:"err_count" example:"20"` 15 | Errs map[string]string `json:"error"` // Example: {"/ip4/132.145.109.63/tcp/10666/p2p/16Uiu2HAmTovb8kAJiYK8saskzz7cRQhb45NRK5AsbtdmYsLfD3RM": "error info"} 16 | 17 | } 18 | 19 | func AddPeers(input AddPeerParam) (*AddPeerResult, error) { 20 | peerserr := make(map[string]string) 21 | 22 | peersaddrinfo := []peer.AddrInfo{} 23 | for _, addr := range input { 24 | ma, err := maddr.NewMultiaddr(addr) 25 | if err != nil { 26 | peerserr[addr] = err.Error() 27 | continue 28 | } 29 | addrinfo, err := peer.AddrInfoFromP2pAddr(ma) 30 | if err != nil { 31 | peerserr[addr] = err.Error() 32 | continue 33 | } 34 | peersaddrinfo = append(peersaddrinfo, *addrinfo) 35 | } 36 | 37 | result := &AddPeerResult{SuccCount: 0, ErrCount: len(peerserr), Errs: peerserr} 38 | 39 | if len(peersaddrinfo) > 0 { 40 | count := nodectx.GetNodeCtx().AddPeers(peersaddrinfo) 41 | result.SuccCount = count 42 | } 43 | return result, nil 44 | } 45 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/autorelay.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p/core/peer" 5 | maddr "github.com/multiformats/go-multiaddr" 6 | "github.com/rumsystem/quorum/internal/pkg/conn/p2p" 7 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 8 | ) 9 | 10 | type AddRelayParam []string 11 | 12 | func AddRelayServers(input AddRelayParam) (bool, error) { 13 | peers := []peer.AddrInfo{} 14 | for _, addr := range input { 15 | ma, err := maddr.NewMultiaddr(addr) 16 | if err != nil { 17 | return false, err 18 | } 19 | addrinfo, err := peer.AddrInfoFromP2pAddr(ma) 20 | if err != nil { 21 | return false, err 22 | } 23 | peers = append(peers, *addrinfo) 24 | } 25 | 26 | nodectx.GetNodeCtx().AddPeers(peers) 27 | 28 | peerChan := p2p.GetRelayPeerChan() 29 | 30 | for _, peer := range peers { 31 | peerChan <- peer 32 | } 33 | 34 | return true, nil 35 | } 36 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/backup_block.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package handlers 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/rumsystem/quorum/internal/pkg/storage" 10 | ) 11 | 12 | // BackupBlock get block from data db and backup to `backupPath` 13 | func BackupBlock(dataDir, peerName, backupDataPath string) { 14 | datapath := dataDir + "/" + peerName 15 | dbManager, err := storage.CreateDb(datapath) 16 | if err != nil { 17 | logger.Fatalf("storage.CreateDb failed: %s", err) 18 | } 19 | defer dbManager.Db.Close() 20 | defer dbManager.GroupInfoDb.Close() 21 | 22 | // backup block 23 | backupDbMgr, err := storage.CreateDb(backupDataPath) 24 | if err != nil { 25 | logger.Fatalf("storage.CreateDb %s failed: %s", backupDataPath, err) 26 | } 27 | defer backupDbMgr.Db.Close() 28 | defer backupDbMgr.GroupInfoDb.Close() 29 | 30 | key := getBlockPrefixKey() 31 | err = dbManager.Db.PrefixForeach([]byte(key), func(k []byte, v []byte, err error) error { 32 | if err != nil { 33 | return err 34 | } 35 | 36 | if err := backupDbMgr.Db.Set(k, v); err != nil { 37 | return fmt.Errorf("backupDbMgr.Db.Set failed: %s", err) 38 | } 39 | return nil 40 | }) 41 | 42 | if err != nil { 43 | logger.Fatalf("backupDbMgr.Db.PrefixForeach failed: %s", err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/backup_group_seed.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "path/filepath" 8 | 9 | "github.com/rumsystem/quorum/internal/pkg/appdata" 10 | "github.com/rumsystem/quorum/internal/pkg/utils" 11 | ) 12 | 13 | // get myself group seeds 14 | func GetAllGroupSeeds(appdb *appdata.AppDb) ([]CreateGroupResult, error) { 15 | 16 | pbSeeds, err := appdb.GetAllGroupSeeds() 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | var seeds []CreateGroupResult 22 | for _, value := range pbSeeds { 23 | seed := FromPbGroupSeed(value) 24 | 25 | // FIXME: hardcode version 1 26 | seedUrl, err := GroupSeedToUrl(1, nil, &seed) 27 | if err != nil { 28 | logger.Errorf("GroupSeedToUrl failed: %s", err) 29 | return nil, err 30 | } 31 | 32 | item := CreateGroupResult{ 33 | Seed: seedUrl, 34 | GroupId: seed.GroupId, 35 | } 36 | seeds = append(seeds, item) 37 | } 38 | 39 | return seeds, nil 40 | } 41 | 42 | // saveAllGroupSeeds save group seed to `seedDir` 43 | func SaveAllGroupSeeds(appdb *appdata.AppDb, seedDir string) error { 44 | if err := utils.EnsureDir(seedDir); err != nil { 45 | return err 46 | } 47 | 48 | seeds, err := GetAllGroupSeeds(appdb) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | for _, seed := range seeds { 54 | seedByte, err := json.MarshalIndent(seed, "", " ") 55 | if err != nil { 56 | return fmt.Errorf("marshal group seed failed: %s", err) 57 | } 58 | 59 | path := filepath.Join(seedDir, fmt.Sprintf("%s.json", seed.GroupId)) 60 | if err := ioutil.WriteFile(path, seedByte, 0644); err != nil { 61 | return fmt.Errorf("write group seed failed: %s", err) 62 | } 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/cleargroupdata.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "github.com/go-playground/validator/v10" 5 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 6 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 7 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 8 | ) 9 | 10 | type ClearGroupDataParam struct { 11 | GroupId string `from:"group_id" json:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 12 | } 13 | 14 | type ClearGroupDataResult struct { 15 | GroupId string `json:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 16 | } 17 | 18 | func ClearGroupData(params *ClearGroupDataParam) (*ClearGroupDataResult, error) { 19 | validate := validator.New() 20 | err := validate.Struct(params) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | groupmgr := chain.GetGroupMgr() 26 | _, ok := groupmgr.Groups[params.GroupId] 27 | if ok { 28 | return nil, rumerrors.NewBadRequestError(rumerrors.ErrClearJoinedGroup) 29 | } 30 | 31 | nodename := nodectx.GetNodeCtx().Name 32 | err = nodectx.GetNodeCtx().GetChainStorage().RemoveGroupData(params.GroupId, nodename) 33 | return &ClearGroupDataResult{GroupId: params.GroupId}, err 34 | } 35 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/config.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | const ( 4 | Add = "Add" 5 | Like = "Like" 6 | Dislike = "Dislike" 7 | Update = "Update" 8 | Remove = "Remove" 9 | Group = "Group" 10 | User = "User" 11 | Auth = "Auth" 12 | Note = "Note" 13 | Page = "Page" 14 | File = "File" 15 | Producer = "Producer" 16 | Announce = "Announce" 17 | App = "App" 18 | ) 19 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/creategroup_native.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package handlers 5 | 6 | import ( 7 | "fmt" 8 | "time" 9 | 10 | "github.com/rumsystem/quorum/internal/pkg/appdata" 11 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 12 | "github.com/rumsystem/quorum/internal/pkg/options" 13 | "github.com/rumsystem/quorum/internal/pkg/utils" 14 | ) 15 | 16 | func GetOrCreateGroupNodeJwt(groupId string) (string, error) { 17 | nodeoptions := options.GetNodeOptions() 18 | 19 | jwtName := fmt.Sprintf("allow-%s", groupId) 20 | exp := time.Now().Add(time.Hour * 24 * 365 * 5) 21 | jwt, err := nodeoptions.GetOrCreateNodeJwt(groupId, jwtName, exp) 22 | if err != nil { 23 | return "", err 24 | } 25 | 26 | if jwt == "" { 27 | return "", rumerrors.ErrInvalidJWT 28 | } 29 | 30 | return jwt, nil 31 | } 32 | 33 | func CreateGroupUrl(baseUrl string, params *CreateGroupParam, nodeoptions *options.NodeOptions, appdb *appdata.AppDb) (*CreateGroupResult, error) { 34 | createGrpResult, err := CreateGroup(params, nodeoptions, appdb) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | var chainUrls []string 40 | if params.IncludeChainUrl { 41 | jwt, err := GetOrCreateGroupNodeJwt(createGrpResult.GroupId) 42 | if err != nil { 43 | return nil, err 44 | } 45 | if jwt == "" { 46 | return nil, rumerrors.ErrInvalidJWT 47 | } 48 | 49 | // get chain api url 50 | chainapiUrl, err := utils.GetChainapiURL(baseUrl, jwt) 51 | if err != nil { 52 | return nil, err 53 | } 54 | chainUrls = append(chainUrls, chainapiUrl) 55 | } 56 | 57 | // convert group seed to url 58 | seedurl, err := GroupSeedToUrl(1, chainUrls, createGrpResult) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | result := CreateGroupResult{ 64 | Seed: seedurl, 65 | GroupId: createGrpResult.GroupId, 66 | } 67 | return &result, nil 68 | } 69 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getannouncedgroupproducer.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 9 | ) 10 | 11 | type AnnouncedProducerListItem struct { 12 | AnnouncedPubkey string `validate:"required" example:"CAISIQOxCH2yVZPR8t6gVvZapxcIPBwMh9jB80pDLNeuA5s8hQ=="` 13 | AnnouncerSign string `validate:"required" example:"3046022100a853ca31f6f6719be213231b6428cecf64de5b1042dd8af1e140499507c85c40022100abd6828478f56da213ec10d361be8709333ff44cd0fa037409af9c0b67e6d0f5"` 14 | Result string `validate:"required" example:"ANNOUCNED"` 15 | // ACTION have 2 states: "ADD" means Producer is normal, "REMOVE" means Producer has announced to leave the group by itself 16 | Action string `validate:"required" example:"ADD"` 17 | Memo string `validate:"required" example:"Memo"` 18 | TimeStamp int64 `validate:"required" example:"1634756064250457600"` 19 | } 20 | 21 | func GetAnnouncedGroupProducer(chainapidb def.APIHandlerIface, groupid string) ([]*AnnouncedProducerListItem, error) { 22 | if groupid == "" { 23 | return nil, errors.New("group_id can't be nil.") 24 | } 25 | 26 | groupmgr := chain.GetGroupMgr() 27 | if group, ok := groupmgr.Groups[groupid]; ok { 28 | prdList, err := chainapidb.GetAnnounceProducersByGroup(group.GroupId, group.Nodename) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | prdResultList := []*AnnouncedProducerListItem{} 34 | for _, prd := range prdList { 35 | var item *AnnouncedProducerListItem 36 | item = &AnnouncedProducerListItem{} 37 | item.AnnouncedPubkey = prd.SignPubkey 38 | item.AnnouncerSign = prd.AnnouncerSignature 39 | item.Result = prd.Result.String() 40 | item.Action = prd.Action.String() 41 | item.TimeStamp = prd.TimeStamp 42 | item.Memo = prd.Memo 43 | prdResultList = append(prdResultList, item) 44 | } 45 | 46 | return prdResultList, nil 47 | } else { 48 | return nil, fmt.Errorf("Group %s not exist", groupid) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getappconfigitem.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | ) 9 | 10 | type AppConfigKeyItem struct { 11 | Name string `example:"test_string"` 12 | Type string `example:"STRING"` 13 | Value string `example:"123"` 14 | OwnerPubkey string `example:"CAISIQJOfMIyaYuVpzdeXq5p+ku/8pSB6XEmUJfHIJ3A0wCkIg=="` 15 | OwnerSign string `example:"304502210091dcc8d8e167c128ef59af1b6e2b2efece499043cc149014303b932485cde3240220427f81f2d7482df0d9a4ab2c019528b33776c73daf21ba98921ee6ff4417b1bc"` 16 | Memo string `example:"memo"` 17 | TimeStamp int64 `example:"1639518490895535600"` 18 | } 19 | 20 | func GetAppConfigByKey(itemKey, groupId string) (*AppConfigKeyItem, error) { 21 | if groupId == "" { 22 | return nil, errors.New("group_id can't be nil.") 23 | } 24 | 25 | groupmgr := chain.GetGroupMgr() 26 | if group, ok := groupmgr.Groups[groupId]; ok { 27 | configItem, err := group.GetAppConfigItem(itemKey) 28 | if err != nil { 29 | return nil, err 30 | } 31 | var item *AppConfigKeyItem 32 | item = &AppConfigKeyItem{} 33 | 34 | item.Name = configItem.Name 35 | item.Type = configItem.Type.String() 36 | item.Value = configItem.Value 37 | item.OwnerPubkey = configItem.OwnerPubkey 38 | item.OwnerSign = configItem.OwnerSign 39 | item.Memo = configItem.Memo 40 | item.TimeStamp = configItem.TimeStamp 41 | return item, nil 42 | } else { 43 | return nil, fmt.Errorf("Group %s not exist", groupId) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getappconfigkey.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | ) 9 | 10 | type AppConfigKeyListItem struct { 11 | Name string 12 | Type string 13 | } 14 | 15 | func GetAppConfigKeyList(groupId string) ([]*AppConfigKeyListItem, error) { 16 | if groupId == "" { 17 | return nil, errors.New("group_id can't be nil.") 18 | } 19 | 20 | result := []*AppConfigKeyListItem{} 21 | groupmgr := chain.GetGroupMgr() 22 | if group, ok := groupmgr.Groups[groupId]; ok { 23 | nameList, typeList, err := group.GetAppConfigKeyList() 24 | if err != nil { 25 | return nil, err 26 | } 27 | for i := range nameList { 28 | item := &AppConfigKeyListItem{ 29 | Name: nameList[i], 30 | Type: typeList[i], 31 | } 32 | 33 | result = append(result, item) 34 | } 35 | return result, nil 36 | } else { 37 | return nil, fmt.Errorf("Group %s not exist", groupId) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getchaintrxallowlist.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 5 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 6 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 7 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 8 | ) 9 | 10 | type ChainSendTrxRuleListItem struct { 11 | Pubkey string `validate:"required" example:"CAISIQNGAO67UTFSuWzySHKdy4IjBI/Q5XDMELPUSxHpBwQDcQ=="` 12 | TrxType []string `validate:"required" example:"POST,ANNOUNCE,REQ_BLOCK_FORWARD,REQ_BLOCK_BACKWARD,ASK_PEERID"` 13 | GroupOwnerPubkey string `validate:"required" example:"CAISIQPLW/J9xgdMWoJxFttChoGOOld8TpChnGFFyPADGL+0JA=="` 14 | GroupOwnerSign string `validate:"required" example:"304502210084bc833278dc98be6f279540b571ad5402f5c2d1e978c4c2298cddb079ca312002205f9374b9d27c628815aecff4ffe11329b17b8be12687223a072afa58e9f15f2c"` 15 | TimeStamp int64 `validate:"required" example:"1642609852758917000"` 16 | Memo string `example:"Memo"` 17 | } 18 | 19 | func GetChainTrxAllowList(chainapidb def.APIHandlerIface, groupid string) ([]*ChainSendTrxRuleListItem, error) { 20 | if groupid == "" { 21 | return nil, rumerrors.ErrInvalidGroupID 22 | } 23 | var result []*ChainSendTrxRuleListItem 24 | 25 | groupmgr := chain.GetGroupMgr() 26 | if group, ok := groupmgr.Groups[groupid]; ok { 27 | chainConfigItemList, allowItemList, err := chainapidb.GetSendTrxAuthListByGroupId(group.GroupId, quorumpb.AuthListType_ALLOW_LIST, group.Nodename) 28 | 29 | if err != nil { 30 | return nil, err 31 | } 32 | for i, alwItem := range allowItemList { 33 | var item *ChainSendTrxRuleListItem 34 | item = &ChainSendTrxRuleListItem{} 35 | 36 | item.Pubkey = alwItem.Pubkey 37 | item.GroupOwnerPubkey = chainConfigItemList[i].OwnerPubkey 38 | item.GroupOwnerSign = chainConfigItemList[i].OwnerSignature 39 | for _, trxType := range alwItem.Type { 40 | item.TrxType = append(item.TrxType, trxType.String()) 41 | } 42 | item.TimeStamp = chainConfigItemList[i].TimeStamp 43 | item.Memo = chainConfigItemList[i].Memo 44 | result = append(result, item) 45 | } 46 | return result, nil 47 | } else { 48 | return nil, rumerrors.ErrGroupNotFound 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getchaintrxdenyist.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 9 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 10 | ) 11 | 12 | func GetChainTrxDenyList(chainapidb def.APIHandlerIface, groupid string) ([]*ChainSendTrxRuleListItem, error) { 13 | if groupid == "" { 14 | return nil, errors.New("group_id can't be nil.") 15 | } 16 | var result []*ChainSendTrxRuleListItem 17 | 18 | groupmgr := chain.GetGroupMgr() 19 | if group, ok := groupmgr.Groups[groupid]; ok { 20 | chainConfigItem, denyItemList, err := chainapidb.GetSendTrxAuthListByGroupId(group.GroupId, quorumpb.AuthListType_DENY_LIST, group.Nodename) 21 | if err != nil { 22 | return nil, err 23 | } 24 | for i, blkItem := range denyItemList { 25 | var item *ChainSendTrxRuleListItem 26 | item = &ChainSendTrxRuleListItem{} 27 | 28 | item.Pubkey = blkItem.Pubkey 29 | item.GroupOwnerPubkey = chainConfigItem[i].OwnerPubkey 30 | item.GroupOwnerSign = chainConfigItem[i].OwnerSignature 31 | for _, trxType := range blkItem.Type { 32 | item.TrxType = append(item.TrxType, trxType.String()) 33 | } 34 | item.TimeStamp = chainConfigItem[i].TimeStamp 35 | item.Memo = chainConfigItem[i].Memo 36 | result = append(result, item) 37 | } 38 | return result, nil 39 | } else { 40 | return nil, fmt.Errorf("Group %s not exist", groupid) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getchintrxauthlist.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 5 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 6 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 7 | ) 8 | 9 | type TrxAuthItem struct { 10 | TrxType string `example:"POST"` 11 | AuthType string `example:"FOLLOW_ALW_LIST"` 12 | } 13 | 14 | type TrxAuthParams struct { 15 | GroupId string `param:"group_id" validate:"required,uuid4" example:"b3e1800a-af6e-4c67-af89-4ddcf831b6f7"` 16 | TrxType string `param:"trx_type" validate:"required,oneof=POST ANNOUNCE REQ_BLOCK" example:"POST"` 17 | } 18 | 19 | func GetChainTrxAuthMode(chainapidb def.APIHandlerIface, groupid string, trxType string) (*TrxAuthItem, error) { 20 | trxAuthItem := TrxAuthItem{} 21 | if groupid == "" { 22 | return nil, rumerrors.ErrInvalidGroupID 23 | } 24 | 25 | groupmgr := chain.GetGroupMgr() 26 | group, ok := groupmgr.Groups[groupid] 27 | if !ok { 28 | return nil, rumerrors.ErrGroupNotFound 29 | } 30 | 31 | trxTypeProto, err := getTrxTypeByString(trxType) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | trxAuthType, err := chainapidb.GetTrxAuthModeByGroupId(group.GroupId, trxTypeProto, group.Nodename) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | trxAuthItem.TrxType = trxTypeProto.String() 42 | trxAuthItem.AuthType = trxAuthType.String() 43 | return &trxAuthItem, nil 44 | } 45 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getgroupctn.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | type GetGroupCtnPrarms struct { 4 | GroupId string `param:"group_id" json:"group_id" url:"-" validate:"required,uuid4"` 5 | Num int `query:"num" json:"num" url:"num"` 6 | StartTrx string `query:"start_trx" json:"start_trx" url:"start_trx"` 7 | Reverse bool `query:"reverse" json:"reverse" url:"reverse,omitempty"` 8 | IncludeStartTrx bool `query:"include_start_trx" json:"include_start_trx" url:"include_start_trx,omitempty"` 9 | Senders []string `query:"senders" json:"senders" url:"senders"` 10 | } 11 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getgroupproducer.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 8 | "github.com/rumsystem/quorum/internal/pkg/storage/def" 9 | ) 10 | 11 | type ProducerListItem struct { 12 | ProducerPubkey string `example:"CAISIQOxCH2yVZPR8t6gVvZapxcIPBwMh9jB80pDLNeuA5s8hQ=="` 13 | OwnerPubkey string `example:"CAISIQNVGW0jrrKvo9/40lAyz/uICsyBbk465PmDKdWfcCM4JA=="` 14 | OwnerSign string `example:"304402202cbca750600cd0aeb3a1076e4aa20e9d1110fe706a553df90d0cd69289628eed022042188b48fa75d0197d9f5ce03499d3b95ffcdfb0ace707cf3eda9f12473db0ea"` 15 | TimeStamp int64 `example:"1634756661280204800"` 16 | BlockWithness int64 `example:"0"` 17 | } 18 | 19 | func GetGroupProducers(chainapidb def.APIHandlerIface, groupid string) ([]*ProducerListItem, error) { 20 | if groupid == "" { 21 | return nil, errors.New("group_id can't be nil.") 22 | } 23 | 24 | groupmgr := chain.GetGroupMgr() 25 | if group, ok := groupmgr.Groups[groupid]; ok { 26 | prdList, err := chainapidb.GetProducers(group.GroupId, group.Nodename) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | var prdResultList []*ProducerListItem 32 | for _, prd := range prdList { 33 | var item *ProducerListItem 34 | item = &ProducerListItem{} 35 | item.ProducerPubkey = prd.ProducerPubkey 36 | item.OwnerPubkey = prd.GroupOwnerPubkey 37 | item.OwnerSign = prd.GroupOwnerSign 38 | item.TimeStamp = prd.TimeStamp 39 | item.BlockWithness = prd.WithnessBlocks 40 | prdResultList = append(prdResultList, item) 41 | } 42 | 43 | return prdResultList, nil 44 | } else { 45 | return nil, fmt.Errorf("Group %s not exist", groupid) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/getgroupseed.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/rumsystem/quorum/internal/pkg/appdata" 8 | ) 9 | 10 | type GetGroupSeedParam struct { 11 | GroupId string `param:"group_id" validate:"required,uuid4" example:"19fbf6d8-90d1-450e-82b0-eaf9e38bc55b"` 12 | IncludeChainUrl bool `query:"include_chain_url" example:"true"` 13 | } 14 | 15 | func GetGroupSeed(groupId string, appdb *appdata.AppDb) (*GroupSeed, error) { 16 | pbSeed, err := appdb.GetGroupSeed(groupId) 17 | if err != nil { 18 | return nil, fmt.Errorf("get group seeds failed: %s", err) 19 | } 20 | 21 | if pbSeed == nil { 22 | return nil, errors.New("group seed not found") 23 | } 24 | 25 | seed := FromPbGroupSeed(pbSeed) 26 | 27 | return &seed, nil 28 | } 29 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/gettrx.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | 6 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 7 | "github.com/rumsystem/quorum/pkg/pb" 8 | ) 9 | 10 | type GetTrxParam struct { 11 | GroupId string `param:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 12 | TrxId string `param:"trx_id" validate:"required,uuid4" example:"22d5c38d-5921-4b75-8562-c110dcfd5ee8"` 13 | } 14 | 15 | func GetTrx(groupid string, trxid string) (*pb.Trx, error) { 16 | groupmgr := chain.GetGroupMgr() 17 | if group, ok := groupmgr.Groups[groupid]; ok { 18 | trx, err := group.GetTrx(trxid) 19 | if err != nil || trx != nil { 20 | return trx, err 21 | } 22 | return group.GetTrxFromCache(trxid) 23 | 24 | } else { 25 | return nil, fmt.Errorf("group %s not exist", groupid) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/leavegroup.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-playground/validator/v10" 7 | "github.com/rumsystem/quorum/internal/pkg/appdata" 8 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 9 | ) 10 | 11 | type LeaveGroupParam struct { 12 | GroupId string `from:"group_id" json:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 13 | } 14 | 15 | type LeaveGroupResult struct { 16 | GroupId string `json:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 17 | } 18 | 19 | func LeaveGroup(params *LeaveGroupParam, appdb *appdata.AppDb) (*LeaveGroupResult, error) { 20 | validate := validator.New() 21 | if err := validate.Struct(params); err != nil { 22 | return nil, err 23 | } 24 | 25 | groupmgr := chain.GetGroupMgr() 26 | group, ok := groupmgr.Groups[params.GroupId] 27 | if !ok { 28 | return nil, fmt.Errorf("Group %s not exist", params.GroupId) 29 | } 30 | 31 | group.StopSync() 32 | if err := group.LeaveGrp(); err != nil { 33 | return nil, err 34 | } 35 | 36 | delete(groupmgr.Groups, params.GroupId) 37 | 38 | //var groupSignPubkey []byte 39 | //ks := localcrypto.GetKeystore() 40 | 41 | //hexkey, err := ks.GetEncodedPubkey("default", localcrypto.Sign) 42 | //pubkeybytes, err := hex.DecodeString(hexkey) 43 | //p2ppubkey, err := p2pcrypto.UnmarshalSecp256k1PublicKey(pubkeybytes) 44 | //groupSignPubkey, err = p2pcrypto.MarshalPublicKey(p2ppubkey) 45 | //if err != nil { 46 | // return nil, errors.New("group key can't be decoded, err:" + err.Error()) 47 | //} 48 | 49 | //var buffer bytes.Buffer 50 | //buffer.Write(groupSignPubkey) 51 | //buffer.Write([]byte(params.GroupId)) 52 | //hash := localcrypto.Hash(buffer.Bytes()) 53 | //signature, err := ks.EthSignByKeyName(params.GroupId, hash) 54 | //encodedString := hex.EncodeToString(signature) 55 | 56 | // delete group seed from appdata 57 | if err := appdb.DelGroupSeed(params.GroupId); err != nil { 58 | return nil, fmt.Errorf("save group seed failed: %s", err) 59 | } 60 | 61 | return &LeaveGroupResult{GroupId: params.GroupId}, nil 62 | } 63 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/logger.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import logging "github.com/ipfs/go-log/v2" 4 | 5 | var ( 6 | logger = logging.Logger("handlers") 7 | nodename = "default" // NOTE: hardcode 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/posttogroup.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | 8 | chain "github.com/rumsystem/quorum/internal/pkg/chainsdk/core" 9 | ) 10 | 11 | type PostToGroupParam struct { 12 | GroupId string `param:"group_id" json:"group_id" validate:"required,uuid4" example:"ac0eea7c-2f3c-4c67-80b3-136e46b924a8"` 13 | /* Data Example: 14 | { 15 | "type": "Create", 16 | "object": { 17 | "type": "Note", 18 | "id": 1, 19 | "content": "hello world" 20 | } 21 | } 22 | */ 23 | Data map[string]interface{} `json:"data" validate:"required"` // json object 24 | } 25 | 26 | type TrxResult struct { 27 | TrxId string `json:"trx_id" validate:"required,uuid4" example:"9e54c173-c1dd-429d-91fa-a6b43c14da77"` 28 | } 29 | 30 | func PostToGroup(payload *PostToGroupParam) (*TrxResult, error) { 31 | groupmgr := chain.GetGroupMgr() 32 | group, ok := groupmgr.Groups[payload.GroupId] 33 | if !ok { 34 | return nil, fmt.Errorf("Group %s not exist", payload.GroupId) 35 | } 36 | data, err := json.Marshal(payload.Data) 37 | if err != nil { 38 | return nil, errors.New(fmt.Sprintf("Invalid Data field, not json object, json.Marshal failed: %s", err)) 39 | } 40 | 41 | trxId, err := group.PostToGroup(data) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return &TrxResult{trxId}, nil 46 | } 47 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/startsync.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type StartSyncResult struct { 8 | GroupId string `validate:"required" example:"5ed3f9fe-81e2-450d-9146-7a329aac2b62"` 9 | Error string `example:""` 10 | } 11 | 12 | func StartSync(groupid string) (*StartSyncResult, error) { 13 | /* 14 | if groupid == "" { 15 | return nil, fmt.Errorf("group_id can't be nil") 16 | } 17 | 18 | groupmgr := chain.GetGroupMgr() 19 | group, ok := groupmgr.Groups[groupid] 20 | if !ok { 21 | return nil, fmt.Errorf("group %s not exist", groupid) 22 | } 23 | 24 | startSyncResult := &StartSyncResult{GroupId: group.Item.GroupId, Error: ""} 25 | if err := group.StartSync(true); err != nil { 26 | startSyncResult.Error = err.Error() 27 | } 28 | 29 | return startSyncResult, nil 30 | */ 31 | 32 | return nil, fmt.Errorf("Deprecated") 33 | } 34 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/utils.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "strings" 8 | 9 | "github.com/rumsystem/quorum/internal/pkg/options" 10 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 11 | ) 12 | 13 | func initSignKey(groupId string, ks localcrypto.Keystore, nodeoptions *options.NodeOptions) (string, error) { 14 | b64key, err := ks.GetEncodedPubkey(groupId, localcrypto.Sign) 15 | if err != nil && strings.HasPrefix(err.Error(), "key not exist ") { 16 | newsignaddr, err := ks.NewKeyWithDefaultPassword(groupId, localcrypto.Sign) 17 | if err == nil && newsignaddr != "" { 18 | err = nodeoptions.SetSignKeyMap(groupId, newsignaddr) 19 | if err != nil { 20 | return "", errors.New(fmt.Sprintf("save key map %s err: %s", newsignaddr, err.Error())) 21 | } 22 | b64key, err = ks.GetEncodedPubkey(groupId, localcrypto.Sign) 23 | } else { 24 | return "", errors.New("create new group key err:" + err.Error()) 25 | } 26 | } 27 | return b64key, nil 28 | } 29 | 30 | func initEncryptKey(groupId string, bks localcrypto.Keystore) (string, error) { 31 | userEncryptKey, err := bks.GetEncodedPubkey(groupId, localcrypto.Encrypt) 32 | if err != nil { 33 | if strings.HasPrefix(err.Error(), "key not exist ") { 34 | userEncryptKey, err = bks.NewKeyWithDefaultPassword(groupId, localcrypto.Encrypt) 35 | if err != nil { 36 | return "", err 37 | } 38 | } else { 39 | return "", err 40 | } 41 | } 42 | return userEncryptKey, nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/chainapi/handlers/utils_test.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUrlToGroupSeed(t *testing.T) { 8 | //url := "rum://seed?v=1&e=0&b=VcxDHxv5SgKTraKbmVt9Qw&c=puq1Mlvkv4Hy-J6NwzqUZHnXKTLr-P16i7VH_9Bn_mw&g=IxYjCaT6SLCP3z2YVJRYBg&k=CAISIQPkmgFL5D4btXcF7R8UD101i_186HAl2WWL8RSqTWZmxA&s=MEYCIQDzXvq3kzir7lw0MhgE8iAxNzV6SXgoCgyQJ09mi5UDgQIhAPgG0LMT-EjfNtoGHqAvqfHChHrXw9q6J2EG1suA0PtR&t=Fvl8Us8CsHI&a=my_test_group%E4%B8%AD%E6%96%87&u=127.0.0.1%3A8080" 9 | 10 | /* commented by cuicat 11 | url := "rum://seed?v=1&e=0&n=0&b=AEEmbwS1TBmjWVb9DW66KA&c=J1qik-4-ZElyhSGLnV4Gl3MRjGOnOIiLtrzEe7WqpoM&g=Wl-JkJR3Qfut52MqeNpmLg&k=CAISIQIiN0qnKdEhpDvfFdwdap9aSXoUZh99mUE0ED789AzahA&s=MEQCIBo4nZgGQiUlu5hu_VsFVkJUnkOlp0ZdQuXwcPeAPNV7AiAUjeuOjhTaGZbyKojAOQx3Ps_sVygIxhoHuKulFxADfw&t=FvppFL7rjgg&a=my_test_group%E4%B8%AD%E6%96%871&y=test_app&u=127.0.0.1%3A8080" 12 | seed, err := UrlToGroupSeed(url) 13 | if err != nil { 14 | t.Errorf("UrlToGroupSeed failed: %s", err) 15 | } 16 | 17 | _ = seed 18 | //verify 19 | */ 20 | } 21 | -------------------------------------------------------------------------------- /pkg/consensus/cofig.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | type Config struct { 4 | N int // participating nodes 5 | f int // faulty nodes 6 | Nodes []string // pubkey list for all partticipating nodes 7 | BatchSize int // maximum number of trxs will be commited in one epoch 8 | MyPubkey string // my pubkey 9 | } 10 | -------------------------------------------------------------------------------- /pkg/consensus/def/chainiface.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | chaindef "github.com/rumsystem/quorum/internal/pkg/chainsdk/def" 5 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 6 | ) 7 | 8 | type ChainMolassesIface interface { 9 | GetTrxFactory() chaindef.TrxFactoryIface 10 | SaveChainInfoToDb() error 11 | ApplyTrxsFullNode(trxs []*quorumpb.Trx, nodename string) error 12 | ApplyTrxsProducerNode(trxs []*quorumpb.Trx, nodename string) error 13 | SetCurrEpoch(currEpoch uint64) 14 | IncCurrEpoch() 15 | GetCurrEpoch() uint64 16 | SetCurrBlockId(currBlock uint64) 17 | IncCurrBlockId() 18 | GetCurrBlockId() uint64 19 | SetLastUpdate(lastUpdate int64) 20 | GetLastUpdate() int64 21 | } 22 | -------------------------------------------------------------------------------- /pkg/consensus/def/consensus.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | type Consensus interface { 4 | Name() string 5 | Producer() Producer 6 | User() User 7 | SetProducer(p Producer) 8 | SetUser(u User) 9 | StartPropose() 10 | } 11 | -------------------------------------------------------------------------------- /pkg/consensus/def/producer.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 5 | ) 6 | 7 | type Producer interface { 8 | NewProducer(item *quorumpb.GroupItem, nodename string, iface ChainMolassesIface) 9 | RecreateBft() 10 | AddBlock(block *quorumpb.Block) error 11 | AddTrx(trx *quorumpb.Trx) 12 | HandleHBMsg(hb *quorumpb.HBMsgv1) error 13 | StartPropose() 14 | } 15 | -------------------------------------------------------------------------------- /pkg/consensus/def/user.go: -------------------------------------------------------------------------------- 1 | package def 2 | 3 | import ( 4 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 5 | ) 6 | 7 | type User interface { 8 | NewUser(item *quorumpb.GroupItem, nodename string, iface ChainMolassesIface) 9 | AddBlock(block *quorumpb.Block) error 10 | } 11 | -------------------------------------------------------------------------------- /pkg/consensus/molasses.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "github.com/rumsystem/quorum/pkg/consensus/def" 5 | ) 6 | 7 | type Molasses struct { 8 | name string 9 | producer def.Producer 10 | user def.User 11 | } 12 | 13 | func NewMolasses(p def.Producer, u def.User) *Molasses { 14 | return &Molasses{name: "Molasses", producer: p, user: u} 15 | } 16 | 17 | func (m *Molasses) Name() string { 18 | return m.name 19 | } 20 | 21 | func (m *Molasses) Producer() def.Producer { 22 | return m.producer 23 | } 24 | 25 | func (m *Molasses) User() def.User { 26 | return m.user 27 | } 28 | 29 | func (m *Molasses) SetProducer(p def.Producer) { 30 | m.producer = p 31 | } 32 | 33 | func (m *Molasses) SetUser(u def.User) { 34 | m.user = u 35 | } 36 | 37 | func (m *Molasses) StartPropose() { 38 | if m.producer != nil { 39 | m.producer.StartPropose() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /pkg/consensus/msgsender.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | guuid "github.com/google/uuid" 5 | "github.com/rumsystem/quorum/internal/pkg/conn" 6 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | func SendHBRBCMsg(groupId string, msg *quorumpb.RBCMsg, epoch uint64) error { 11 | connMgr, err := conn.GetConn().GetConnMgr(groupId) 12 | if err != nil { 13 | return err 14 | } 15 | 16 | rbcb, err := proto.Marshal(msg) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | hbmsg := &quorumpb.HBMsgv1{ 22 | MsgId: guuid.New().String(), 23 | Epoch: epoch, 24 | PayloadType: quorumpb.HBMsgPayloadType_RBC, 25 | Payload: rbcb, 26 | } 27 | 28 | return connMgr.BroadcastHBMsg(hbmsg) 29 | } 30 | 31 | func SendHBAABMsg(groupId string, msg *quorumpb.BBAMsg, epoch int64) error { 32 | //TBD 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /pkg/consensus/trxbuffer.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | 7 | "github.com/rumsystem/quorum/internal/pkg/nodectx" 8 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 9 | ) 10 | 11 | // just a simple wrap of HBB Trx Buffer DB 12 | type TrxBuffer struct { 13 | queueId string 14 | } 15 | 16 | func NewTrxBuffer(queueId string) *TrxBuffer { 17 | b := &TrxBuffer{ 18 | queueId: queueId, 19 | } 20 | rand.Seed(time.Now().UnixNano()) 21 | return b 22 | } 23 | 24 | func (b *TrxBuffer) GetBufferLen() (int, error) { 25 | return nodectx.GetNodeCtx().GetChainStorage().GeBufferedTrxLenHBB(b.queueId) 26 | } 27 | 28 | func (b *TrxBuffer) Push(trx *quorumpb.Trx) error { 29 | return nodectx.GetNodeCtx().GetChainStorage().AddTrxHBB(trx, b.queueId) 30 | } 31 | 32 | func (b *TrxBuffer) Delete(trxId string) error { 33 | return nodectx.GetNodeCtx().GetChainStorage().RemoveTrxHBB(trxId, b.queueId) 34 | } 35 | 36 | func (b *TrxBuffer) Clear() error { 37 | return nodectx.GetNodeCtx().GetChainStorage().RemoveAllTrxHBB(b.queueId) 38 | } 39 | 40 | func (b *TrxBuffer) GetTrxById(trxId string) (*quorumpb.Trx, error) { 41 | return nodectx.GetNodeCtx().GetChainStorage().GetTrxByIdHBB(trxId, b.queueId) 42 | } 43 | 44 | func (b *TrxBuffer) GetAllTrxInBuffer() ([]*quorumpb.Trx, error) { 45 | return nodectx.GetNodeCtx().GetChainStorage().GetAllTrxHBB(b.queueId) 46 | } 47 | 48 | // since trx is buffered in *random" way, no sequence is created 49 | // just return the first n items in the slice is enough 50 | // caller should check the length of return trx slice 51 | func (b *TrxBuffer) GetNRandTrx(n int) ([]*quorumpb.Trx, error) { 52 | //get len 53 | len, err := nodectx.GetNodeCtx().GetChainStorage().GeBufferedTrxLenHBB(b.queueId) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | trxs, err := nodectx.GetNodeCtx().GetChainStorage().GetAllTrxHBB(b.queueId) 59 | 60 | if n >= len { 61 | //return all trxs in buffer 62 | return trxs, err 63 | } else { 64 | //return first n trxs in buffer 65 | return trxs[:n], err 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/constants/network.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const ( 4 | USER_CHANNEL_PREFIX = "user_channel_" 5 | PRODUCER_CHANNEL_PREFIX = "prod_channel_" 6 | SYNC_CHANNEL_PREFIX = "sync_channel_" 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/crypto/aes.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "io" 8 | ) 9 | 10 | func CreateAesKey() ([]byte, error) { 11 | key := make([]byte, 32) 12 | _, err := rand.Read(key) 13 | return key, err 14 | } 15 | 16 | func AesEncrypt(data, key []byte) ([]byte, error) { 17 | cphr, err := aes.NewCipher(key) 18 | if err != nil { 19 | return nil, err 20 | } 21 | gcm, err := cipher.NewGCM(cphr) 22 | if err != nil { 23 | return nil, err 24 | } 25 | nonce := make([]byte, gcm.NonceSize()) 26 | if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 27 | return nil, err 28 | } 29 | return gcm.Seal(nonce, nonce, data, nil), nil 30 | } 31 | 32 | func AesDecode(data, key []byte) ([]byte, error) { 33 | c, err := aes.NewCipher(key) 34 | if err != nil { 35 | return nil, err 36 | } 37 | gcmDecrypt, err := cipher.NewGCM(c) 38 | if err != nil { 39 | return nil, err 40 | } 41 | nonceSize := gcmDecrypt.NonceSize() 42 | if len(data) < nonceSize { 43 | return nil, err 44 | } 45 | nonce, encrypteddata := data[:nonceSize], data[nonceSize:] 46 | plaintext, err := gcmDecrypt.Open(nil, nonce, encrypteddata, nil) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return plaintext, nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/crypto/aes_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestAesEcryptAndDecrypt(t *testing.T) { 10 | key, err := CreateAesKey() 11 | if err != nil { 12 | t.Fatalf("CreateAesKey failed: %s", err) 13 | } 14 | 15 | plaintext := []byte(fmt.Sprintf("Hello, World! %s", time.Now())) 16 | ciphertext, err := AesEncrypt(plaintext, key) 17 | if err != nil { 18 | t.Fatalf("AesEncrypt failed: %s", err) 19 | } 20 | 21 | plaintext2, err := AesDecode(ciphertext, key) 22 | if err != nil { 23 | t.Fatalf("AesDecode failed: %s", err) 24 | } 25 | 26 | if string(plaintext) != string(plaintext2) { 27 | t.Fatalf("AesDecode failed, decrypt text is: %s, expect: %s", plaintext2, plaintext) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pkg/crypto/age_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "strings" 7 | "testing" 8 | 9 | "filippo.io/age" 10 | ) 11 | 12 | func TestAgeEncryptAndDecrypt(t *testing.T) { 13 | password := "My.passw0rd" 14 | recipient, err := age.NewScryptRecipient(password) 15 | if err != nil { 16 | t.Fatalf("age.NewScryptRecipient failed: %s", err) 17 | } 18 | 19 | plaintext := []byte("Hello, world!") 20 | encrypted := new(bytes.Buffer) 21 | 22 | if err := AgeEncrypt([]age.Recipient{recipient}, bytes.NewReader(plaintext), encrypted); err != nil { 23 | t.Fatalf("AgeEncrypt failed: %s", err) 24 | } 25 | 26 | decryptedReader, err := AgeDecrypt(password, encrypted) 27 | if err != nil { 28 | t.Fatalf("AgeDecrypt failed: %s", err) 29 | } 30 | 31 | decrypted, err := ioutil.ReadAll(decryptedReader) 32 | if err != nil { 33 | t.Fatalf("ioutil.ReadAll failed: %s", err) 34 | } 35 | 36 | if string(decrypted) != string(plaintext) { 37 | t.Fatalf("decrypted text does not match plaintext, got: %s expect: %s", decrypted, plaintext) 38 | } 39 | } 40 | 41 | func TestAgeDecryptIdentityWithPassword(t *testing.T) { 42 | password := "My.passw0rd" 43 | recipient, err := age.NewScryptRecipient(password) 44 | if err != nil { 45 | t.Fatalf("age.NewScryptRecipient failed: %s", err) 46 | } 47 | 48 | key, err := age.GenerateX25519Identity() 49 | if err != nil { 50 | t.Fatalf("age.GenerateX25519Identity failed: %s", err) 51 | } 52 | 53 | output := new(bytes.Buffer) 54 | if err := AgeEncrypt([]age.Recipient{recipient}, strings.NewReader(key.String()), output); err != nil { 55 | t.Fatalf("AgeEncrypt failed: %s", err) 56 | } 57 | 58 | decKey, err := AgeDecryptIdentityWithPassword(output, nil, password) 59 | if err != nil { 60 | t.Fatalf("AgeDecryptIdentityWithPassword failed: %s", err) 61 | } 62 | 63 | if decKey == nil { 64 | t.Fatalf("AgeDecryptIdentityWithPassword returned nil key") 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/crypto/data.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "filippo.io/age" 5 | "io" 6 | ) 7 | 8 | func EncryptDataForGroup(groupid string, dst io.Writer) (io.WriteCloser, error) { 9 | //TODO: 10 | //get recipients by groupid, recipients []age.Recipient 11 | //TEST ONLY mock key: 12 | //age1helmw6nufy93lcg5lylv2qxvdjdej8srcfk2hz3amw6lgms0td3qtw72fy 13 | mypub, err := age.ParseX25519Recipient("age1helmw6nufy93lcg5lylv2qxvdjdej8srcfk2hz3amw6lgms0td3qtw72fy") 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | recipients := []age.Recipient{mypub} 19 | return age.Encrypt(dst, recipients...) 20 | } 21 | func DecryptDataForGroup(groupid string, src io.Reader) (io.Reader, error) { 22 | 23 | //TODO: 24 | //get my group public key 25 | //TEST ONLY mock key: 26 | //AGE-SECRET-KEY-1S77E2S2TF4SEVXTGJFQLN8NC6VG7TTLKYCNHSMA5CMYZAFY98NTQEN8QVV 27 | 28 | mykey, err := age.ParseX25519Identity("AGE-SECRET-KEY-1S77E2S2TF4SEVXTGJFQLN8NC6VG7TTLKYCNHSMA5CMYZAFY98NTQEN8QVV") 29 | if err != nil { 30 | return nil, err 31 | } 32 | return age.Decrypt(src, mykey) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/crypto/keystore_native.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package crypto 5 | 6 | func InitKeystore(KeyStoreName, KeyStoreDir string) (int, error) { 7 | signkeycount := 0 8 | var err error 9 | ks, signkeycount, err = InitDirKeyStore(KeyStoreName, KeyStoreDir) 10 | return signkeycount, err 11 | } 12 | -------------------------------------------------------------------------------- /pkg/crypto/keystore_native_test.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | // +build !js 3 | 4 | package crypto 5 | 6 | import "testing" 7 | 8 | func TestInitKeystore(t *testing.T) { 9 | keystoreName := "test-keystore" 10 | keystoreDir := t.TempDir() 11 | 12 | signkeycount, err := InitKeystore(keystoreName, keystoreDir) 13 | if err != nil { 14 | t.Fatalf("InitKeystore failed: %s", err) 15 | } 16 | 17 | if signkeycount != 0 { 18 | t.Fatal("InitKeystore failed: signkeycount != 0") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pkg/crypto/tools.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/base64" 6 | "errors" 7 | 8 | "github.com/decred/dcrd/dcrec/secp256k1/v4" 9 | ethcrypto "github.com/ethereum/go-ethereum/crypto" 10 | p2pcrypto "github.com/libp2p/go-libp2p/core/crypto" 11 | ) 12 | 13 | // Hash return the SHA256 checksum of the data 14 | func Hash(data []byte) []byte { 15 | h := sha256.New() 16 | h.Write([]byte(data)) 17 | hashed := h.Sum(nil) 18 | return hashed 19 | } 20 | 21 | func Libp2pPubkeyToEthBase64(libp2ppubkey string) (string, error) { 22 | p2pkeyBytes, err := p2pcrypto.ConfigDecodeKey(libp2ppubkey) 23 | if err != nil { 24 | //is not a libp2pkey, may an ethkey? 25 | return libp2ppubkey, err 26 | } 27 | 28 | pubkey, err := p2pcrypto.UnmarshalPublicKey(p2pkeyBytes) 29 | if err != nil { 30 | return libp2ppubkey, err 31 | } 32 | 33 | secp256k1pubkey, ok := pubkey.(*p2pcrypto.Secp256k1PublicKey) 34 | if ok == true { 35 | spubkey := (*secp256k1.PublicKey)(secp256k1pubkey) 36 | return base64.RawURLEncoding.EncodeToString(ethcrypto.CompressPubkey(spubkey.ToECDSA())), nil 37 | } 38 | return libp2ppubkey, errors.New("convert to Secp256k1PublicKey failed") 39 | } 40 | -------------------------------------------------------------------------------- /pkg/crypto/tools_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHash(t *testing.T) { 9 | var golden256 = []struct { 10 | in string 11 | out string 12 | }{ 13 | {"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, 14 | {"a", "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"}, 15 | {"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"}, 16 | {"message digest", "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"}, 17 | { 18 | "abcdefghijklmnopqrstuvwxyz", 19 | "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73", 20 | }, 21 | { 22 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 23 | "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", 24 | }, 25 | { 26 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 27 | "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", 28 | }, 29 | { 30 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 31 | "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e", 32 | }, 33 | } 34 | 35 | for _, x := range golden256 { 36 | hb := Hash([]byte(x.in)) 37 | hs := fmt.Sprintf("%x", hb) 38 | if hs != x.out { 39 | t.Errorf("Hash(%q) = %q, want %q", x.in, hs, x.out) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/data/util.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | 7 | "github.com/rumsystem/quorum/internal/pkg/logging" 8 | ) 9 | 10 | const TRX_DATA_SIZE_LIMIT = 300 * 1024 //300Kb 11 | var dataLog = logging.Logger("data") 12 | 13 | func IsTrxDataWithinSizeLimit(data []byte) (bool, error) { 14 | size := binary.Size(data) 15 | if size > TRX_DATA_SIZE_LIMIT { 16 | e := fmt.Errorf("trx.Data size %dkb over %dkb", size/1024, TRX_DATA_SIZE_LIMIT/1024) 17 | dataLog.Warn(e) 18 | return false, e 19 | } 20 | 21 | return true, nil 22 | } 23 | -------------------------------------------------------------------------------- /pkg/makefile: -------------------------------------------------------------------------------- 1 | PROTOC_GEN_GO = $(GOPATH)/bin/protoc-gen-go 2 | PROTOC = $(shell which protoc) 3 | 4 | compile: chain.proto activity_stream.proto rumexchange.proto 5 | 6 | chain.proto: 7 | protoc -I=pb --go_out=pb pb/chain.proto 8 | mv pb/github.com/rumsystem/quorum/pkg/pb/chain.pb.go pb/chain.pb.go 9 | sed -i 's/TimeStamp,omitempty/TimeStamp,omitempty,string/g' pb/chain.pb.go 10 | 11 | activity_stream.proto: 12 | protoc -I=pb --go_out=pb pb/activity_stream.proto 13 | mv pb/github.com/rumsystem/quorum/pkg/pb/activity_stream.pb.go pb/activity_stream.pb.go 14 | sed -i 's/TimeStamp,omitempty/TimeStamp,omitempty,string/g' pb/activity_stream.pb.go 15 | 16 | rumexchange.proto: 17 | protoc -I=pb --go_out=pb pb/rumexchange.proto 18 | mv pb/github.com/rumsystem/quorum/pkg/pb/rumexchange.pb.go pb/rumexchange.pb.go 19 | sed -i 's/TimeStamp,omitempty/TimeStamp,omitempty,string/g' pb/rumexchange.pb.go 20 | 21 | build: compile 22 | 23 | buildall: compile 24 | 25 | all: compile 26 | -------------------------------------------------------------------------------- /pkg/nodesdk/Readme.md: -------------------------------------------------------------------------------- 1 | NodeSDK v0.0.1 -------------------------------------------------------------------------------- /pkg/nodesdk/api/announce.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | func (h *NodeSDKHandler) Announce(c echo.Context) (err error) { 10 | return c.JSON(http.StatusOK, nil) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/bindaliaskeyname.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 10 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 11 | ) 12 | 13 | type BindKeyAliasParams struct { 14 | Alias string `json:"alias" validate:"required"` 15 | KeyName string `json:"keyname" validate:"required"` 16 | Type string `json:"type" validate:"required,oneof=encrypt sign"` 17 | } 18 | 19 | func (h *NodeSDKHandler) BindAliasWithKeyName() echo.HandlerFunc { 20 | return func(c echo.Context) error { 21 | cc := c.(*utils.CustomContext) 22 | params := new(BindKeyAliasParams) 23 | if err := cc.BindAndValidate(params); err != nil { 24 | return err 25 | } 26 | 27 | ks := nodesdkctx.GetKeyStore() 28 | dirks, ok := ks.(*localcrypto.DirKeyStore) 29 | if !ok { 30 | return rumerrors.NewBadRequestError("Open keystore failed") 31 | } 32 | 33 | password := os.Getenv("RUM_KSPASSWD") 34 | 35 | keyname := dirks.AliasToKeyname(params.Alias) 36 | if keyname != "" { 37 | if err := dirks.UnAlias(params.Alias, password); err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | } 41 | 42 | if err := dirks.NewAlias(params.Alias, params.KeyName, password); err != nil { 43 | return rumerrors.NewBadRequestError(err) 44 | } 45 | 46 | return cc.Success() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getallalias.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type KeyItem struct { 13 | Alias []string 14 | Keyname string 15 | Keytype string 16 | } 17 | 18 | type GetAllAliasResult struct { 19 | Keys []*KeyItem `json:"keys"` 20 | } 21 | 22 | func (h *NodeSDKHandler) GetAllAlias() echo.HandlerFunc { 23 | return func(c echo.Context) error { 24 | ks := nodesdkctx.GetKeyStore() 25 | dirks, ok := ks.(*localcrypto.DirKeyStore) 26 | if !ok { 27 | return rumerrors.NewBadRequestError("cast to DirKeyStore failed") 28 | } 29 | 30 | keys, err := dirks.ListAll() 31 | if err != nil { 32 | return rumerrors.NewBadRequestError("Open keystore failed") 33 | } 34 | 35 | var keyitems []*KeyItem 36 | for _, keyitem := range keys { 37 | var item *KeyItem 38 | item = &KeyItem{} 39 | item.Alias = keyitem.Alias 40 | item.Keyname = keyitem.Keyname 41 | if keyitem.Type == localcrypto.Encrypt { 42 | item.Keytype = "encrypt" 43 | } else { 44 | item.Keytype = "sign" 45 | } 46 | keyitems = append(keyitems, item) 47 | } 48 | 49 | result := GetAllAliasResult{keyitems} 50 | return c.JSON(http.StatusOK, &result) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getannouncedusers.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | func (h *NodeSDKHandler) GetAnnouncedUsers(c echo.Context) (err error) { 13 | groupid := c.Param("group_id") 14 | 15 | if groupid == "" { 16 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 17 | } 18 | 19 | signPubkey := c.Param("sign_pubkey") 20 | 21 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 22 | if err != nil { 23 | return rumerrors.NewBadRequestError(err) 24 | } 25 | 26 | reqItem := new(AnnGrpUser) 27 | reqItem.GroupId = groupid 28 | reqItem.SignPubkey = signPubkey 29 | 30 | itemBytes, err := json.Marshal(reqItem) 31 | if err != nil { 32 | return rumerrors.NewBadRequestError(err) 33 | } 34 | 35 | encryptData, err := getEncryptData(itemBytes, nodesdkGroupItem.Group.CipherKey) 36 | if err != nil { 37 | return rumerrors.NewBadRequestError(err) 38 | } 39 | 40 | getItem := new(NodeSDKGetChainDataItem) 41 | getItem.Req = encryptData 42 | getItem.ReqType = ANNOUNCED_USER 43 | 44 | //just get the first one 45 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 46 | if err != nil { 47 | return rumerrors.NewBadRequestError(err) 48 | } 49 | 50 | err = httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl) 51 | if err != nil { 52 | return rumerrors.NewBadRequestError(err) 53 | } 54 | 55 | result := new([]*AnnGrpUser) 56 | err = httpClient.RequestChainAPI(GetChainDataURI(groupid), http.MethodPost, getItem, nil, result) 57 | if err != nil { 58 | return rumerrors.NewBadRequestError(err) 59 | } 60 | 61 | return c.JSON(http.StatusOK, result) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getapihosturl.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | pkgutils "github.com/rumsystem/quorum/internal/pkg/utils" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type GetApiHostParams struct { 13 | GroupId string `param:"group_id" validate:"required,uuid4"` 14 | } 15 | 16 | type GetApiHostResult struct { 17 | URLs []string `json:"urls" validate:"required"` 18 | } 19 | 20 | func (h *NodeSDKHandler) GetApiHostUrl(c echo.Context) (err error) { 21 | cc := c.(*pkgutils.CustomContext) 22 | params := new(GetApiHostParams) 23 | if err := cc.BindAndValidate(params); err != nil { 24 | return err 25 | } 26 | 27 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(params.GroupId) 28 | if err != nil { 29 | return rumerrors.NewBadRequestError(err) 30 | } 31 | result := GetApiHostResult{URLs: nodesdkGroupItem.ApiUrl} 32 | 33 | return c.JSON(http.StatusOK, result) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getappconfigitem.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type GetAppConfigResultItem struct { 13 | Name string 14 | Type string 15 | Value string 16 | OwnerPubkey string 17 | Memo string 18 | Timestamp int 19 | } 20 | 21 | func (h *NodeSDKHandler) GetAppConfigItem(c echo.Context) (err error) { 22 | groupid := c.Param("group_id") 23 | if groupid == "" { 24 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 25 | } 26 | 27 | key := c.Param("key") 28 | if key == "" { 29 | return rumerrors.NewBadRequestError("empty key") 30 | } 31 | 32 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 33 | if err != nil { 34 | return rumerrors.NewBadRequestError(err) 35 | } 36 | 37 | reqItem := new(AppConfigItem) 38 | reqItem.GroupId = groupid 39 | reqItem.Key = key 40 | 41 | itemBytes, err := json.Marshal(reqItem) 42 | if err != nil { 43 | return rumerrors.NewBadRequestError(err) 44 | } 45 | 46 | encryptData, err := getEncryptData(itemBytes, nodesdkGroupItem.Group.CipherKey) 47 | if err != nil { 48 | return rumerrors.NewBadRequestError(err) 49 | } 50 | 51 | getItem := new(NodeSDKGetChainDataItem) 52 | getItem.Req = encryptData 53 | getItem.ReqType = APPCONFIG_ITEM_BYKEY 54 | 55 | //just get the first one 56 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 57 | if err != nil { 58 | return rumerrors.NewBadRequestError(err) 59 | } 60 | 61 | err = httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl) 62 | if err != nil { 63 | return rumerrors.NewBadRequestError(err) 64 | } 65 | 66 | result := new(*GetAppConfigResultItem) 67 | err = httpClient.RequestChainAPI(GetChainDataURI(groupid), http.MethodPost, getItem, nil, result) 68 | if err != nil { 69 | return rumerrors.NewBadRequestError(err) 70 | } 71 | 72 | return c.JSON(http.StatusOK, result) 73 | } 74 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getappconfigkey.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type AppConfigKeyListResultItem struct { 13 | Name string 14 | Type string 15 | } 16 | 17 | func (h *NodeSDKHandler) GetAppConfigKey(c echo.Context) (err error) { 18 | groupid := c.Param("group_id") 19 | if groupid == "" { 20 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 21 | } 22 | 23 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 24 | if err != nil { 25 | return rumerrors.NewBadRequestError(err) 26 | } 27 | 28 | reqItem := new(AppConfigKeyListItem) 29 | reqItem.GroupId = groupid 30 | 31 | itemBytes, err := json.Marshal(reqItem) 32 | if err != nil { 33 | return rumerrors.NewBadRequestError(err) 34 | } 35 | 36 | encryptData, err := getEncryptData(itemBytes, nodesdkGroupItem.Group.CipherKey) 37 | if err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | 41 | getItem := new(NodeSDKGetChainDataItem) 42 | getItem.Req = encryptData 43 | getItem.ReqType = APPCONFIG_KEYLIST 44 | 45 | //just get the first one 46 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 47 | if err != nil { 48 | return rumerrors.NewBadRequestError(err) 49 | } 50 | 51 | if err := httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl); err != nil { 52 | return rumerrors.NewBadRequestError(err) 53 | } 54 | 55 | result := new([]*AppConfigKeyListResultItem) 56 | err = httpClient.RequestChainAPI(GetChainDataURI(groupid), http.MethodPost, getItem, nil, result) 57 | if err != nil { 58 | return rumerrors.NewBadRequestError(err) 59 | } 60 | 61 | return c.JSON(http.StatusOK, result) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getblock.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 9 | quorumpb "github.com/rumsystem/quorum/pkg/pb" 10 | ) 11 | 12 | const GET_BLOCK_URI string = "/api/v1/block" 13 | 14 | func (h *NodeSDKHandler) GetBlock() echo.HandlerFunc { 15 | return func(c echo.Context) error { 16 | groupid := c.Param("group_id") 17 | if groupid == "" { 18 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 19 | } 20 | 21 | blockid := c.Param("block_id") 22 | if blockid == "" { 23 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidBlockID) 24 | } 25 | 26 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 27 | if err != nil { 28 | return rumerrors.NewBadRequestError(err) 29 | } 30 | 31 | //just get the first one 32 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 33 | if err != nil { 34 | return rumerrors.NewBadRequestError(err) 35 | } 36 | 37 | if err := httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl); err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | 41 | path := GET_BLOCK_URI + "/" + groupid + "/" + blockid 42 | 43 | result := new(quorumpb.Block) 44 | err = httpClient.RequestChainAPI(path, http.MethodGet, nil, nil, result) 45 | if err != nil { 46 | return rumerrors.NewBadRequestError(err) 47 | } 48 | 49 | return c.JSON(http.StatusOK, result) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getgroupbyid.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type GetGroupByIdParams struct { 13 | GroupId string `json:"group_id" validate:"required,uuid4"` 14 | } 15 | 16 | func (h *NodeSDKHandler) GetGroupById() echo.HandlerFunc { 17 | return func(c echo.Context) error { 18 | var err error 19 | 20 | groupid := c.Param("group_id") 21 | if groupid == "" { 22 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 23 | } 24 | 25 | groupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 26 | if err != nil { 27 | return rumerrors.NewBadRequestError(err) 28 | } 29 | 30 | groupInfo := &GroupInfo{} 31 | groupInfo.GroupId = groupItem.Group.GroupId 32 | groupInfo.GroupName = groupItem.Group.GroupName 33 | groupInfo.SignAlias = groupItem.SignAlias 34 | groupInfo.EncryptAlias = groupItem.EncryptAlias 35 | 36 | ethaddr, err := localcrypto.Libp2pPubkeyToEthaddr(groupItem.Group.UserSignPubkey) 37 | if err != nil { 38 | return rumerrors.NewBadRequestError(err) 39 | } 40 | 41 | groupInfo.UserEthaddr = ethaddr 42 | groupInfo.ConsensusType = groupItem.Group.ConsenseType.String() 43 | groupInfo.EncryptionType = groupItem.Group.EncryptType.String() 44 | groupInfo.CipherKey = groupItem.Group.CipherKey 45 | groupInfo.AppKey = groupItem.Group.AppKey 46 | groupInfo.LastUpdated = groupItem.Group.LastUpdate 47 | 48 | //TBD cuicat 49 | //groupInfo.Epoch = groupItem.Group.Epoch 50 | groupInfo.ChainApis = groupItem.ApiUrl 51 | 52 | return c.JSON(http.StatusOK, groupInfo) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getgroupinfo.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | func (h *NodeSDKHandler) GetGroupInfo(c echo.Context) (err error) { 13 | groupid := c.Param("group_id") 14 | if groupid == "" { 15 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 16 | } 17 | 18 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 19 | if err != nil { 20 | return rumerrors.NewBadRequestError(err) 21 | } 22 | 23 | reqItem := new(GrpInfo) 24 | reqItem.GroupId = groupid 25 | 26 | itemBytes, err := json.Marshal(reqItem) 27 | if err != nil { 28 | return rumerrors.NewBadRequestError(err) 29 | } 30 | 31 | encryptData, err := getEncryptData(itemBytes, nodesdkGroupItem.Group.CipherKey) 32 | if err != nil { 33 | return rumerrors.NewBadRequestError(err) 34 | } 35 | 36 | getItem := new(NodeSDKGetChainDataItem) 37 | getItem.Req = encryptData 38 | getItem.ReqType = GROUP_INFO 39 | 40 | //just get the first one 41 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 42 | if err != nil { 43 | return rumerrors.NewBadRequestError(err) 44 | } 45 | 46 | err = httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl) 47 | if err != nil { 48 | return rumerrors.NewBadRequestError(err) 49 | } 50 | 51 | result := new(GrpInfoNodeSDK) 52 | err = httpClient.RequestChainAPI(GetChainDataURI(groupid), http.MethodPost, getItem, nil, result) 53 | if err != nil { 54 | return rumerrors.NewBadRequestError(err) 55 | } 56 | 57 | //verify groupInfo by check provider and signature 58 | 59 | //update db 60 | //save nodesdkgroupitem to db 61 | grpInfo, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 62 | if err != nil { 63 | return rumerrors.NewBadRequestError(err) 64 | } 65 | 66 | //TBD cuicat 67 | //grpInfo.Group.Epoch = result.Epoch 68 | grpInfo.Group.LastUpdate = result.LatestUpdate 69 | 70 | if err := nodesdkctx.GetCtx().GetChainStorage().UpdGroupV2(grpInfo); err != nil { 71 | return rumerrors.NewBadRequestError(err) 72 | } 73 | 74 | return c.JSON(http.StatusOK, result) 75 | } 76 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getgroupseed.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type GetGroupSeedParams struct { 13 | GroupId string `json:"group_id" validate:"required,uuid4"` 14 | } 15 | 16 | func (h *NodeSDKHandler) GetGroupSeed() echo.HandlerFunc { 17 | return func(c echo.Context) error { 18 | groupid := c.Param("group_id") 19 | 20 | if groupid == "" { 21 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 22 | } 23 | 24 | pbseed, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupSeed(groupid) 25 | if err != nil { 26 | return rumerrors.NewBadRequestError(err) 27 | } 28 | seed := handlers.FromPbGroupSeed(pbseed) 29 | 30 | groupInfo, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 31 | if err != nil { 32 | return rumerrors.NewBadRequestError(err) 33 | } 34 | 35 | seedurl, err := handlers.GroupSeedToUrl(1, groupInfo.GetApiUrl(), &seed) 36 | if err != nil { 37 | return rumerrors.NewBadRequestError(err) 38 | } 39 | 40 | output := map[string]string{} 41 | output["seed"] = seedurl 42 | 43 | return c.JSON(http.StatusOK, output) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/getproducers.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | func (h *NodeSDKHandler) GetProducers(c echo.Context) (err error) { 13 | groupid := c.Param("group_id") 14 | if groupid == "" { 15 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 16 | } 17 | 18 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 19 | if err != nil { 20 | return rumerrors.NewBadRequestError(err) 21 | } 22 | 23 | reqItem := new(GrpProducer) 24 | reqItem.GroupId = groupid 25 | 26 | itemBytes, err := json.Marshal(reqItem) 27 | if err != nil { 28 | return rumerrors.NewBadRequestError(err) 29 | } 30 | 31 | encryptData, err := getEncryptData(itemBytes, nodesdkGroupItem.Group.CipherKey) 32 | if err != nil { 33 | return rumerrors.NewBadRequestError(err) 34 | } 35 | 36 | getItem := new(NodeSDKGetChainDataItem) 37 | getItem.Req = encryptData 38 | getItem.ReqType = GROUP_PRODUCER 39 | 40 | //just get the first one 41 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 42 | if err != nil { 43 | return rumerrors.NewBadRequestError(err) 44 | } 45 | 46 | err = httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl) 47 | if err != nil { 48 | return rumerrors.NewBadRequestError(err) 49 | } 50 | 51 | result := new([]*ProducerListItem) 52 | err = httpClient.RequestChainAPI(GetChainDataURI(groupid), http.MethodPost, getItem, nil, result) 53 | if err != nil { 54 | return rumerrors.NewBadRequestError(err) 55 | } 56 | 57 | return c.JSON(http.StatusOK, result) 58 | } 59 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/gettrx.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 9 | ) 10 | 11 | type Trx struct { 12 | TrxId string 13 | Type string 14 | GroupId string 15 | Data string 16 | TimeStamp string 17 | Version string 18 | Expired string 19 | ResendCount string 20 | SenderPubkey string 21 | SenderSign string 22 | StorageType string 23 | } 24 | 25 | const GET_TRX_URI string = "/api/v1/trx" 26 | 27 | func (h *NodeSDKHandler) GetTrx() echo.HandlerFunc { 28 | return func(c echo.Context) error { 29 | groupid := c.Param("group_id") 30 | if groupid == "" { 31 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidGroupID) 32 | } 33 | 34 | trxid := c.Param("trx_id") 35 | if trxid == "" { 36 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidTrxID) 37 | } 38 | 39 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(groupid) 40 | if err != nil { 41 | return rumerrors.NewBadRequestError(err) 42 | } 43 | 44 | //just get the first one 45 | httpClient, err := nodesdkctx.GetCtx().GetHttpClient(nodesdkGroupItem.Group.GroupId) 46 | if err != nil { 47 | return rumerrors.NewBadRequestError(err) 48 | } 49 | 50 | err = httpClient.UpdApiServer(nodesdkGroupItem.ApiUrl) 51 | if err != nil { 52 | return rumerrors.NewBadRequestError(err) 53 | } 54 | 55 | path := GET_TRX_URI + "/" + groupid + "/" + trxid 56 | 57 | result := new(Trx) 58 | err = httpClient.RequestChainAPI(path, http.MethodGet, nil, nil, result) 59 | if err != nil { 60 | return rumerrors.NewBadRequestError(err) 61 | } 62 | 63 | return c.JSON(http.StatusOK, result) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/handle.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "context" 5 | 6 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 7 | ) 8 | 9 | type ( 10 | NodeSDKHandler struct { 11 | Ctx context.Context 12 | NodeSdkCtx *nodesdkctx.NodeSdkCtx 13 | GitCommit string 14 | } 15 | ) 16 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/leavegroup.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 10 | ) 11 | 12 | type LeaveGroupParams struct { 13 | GroupId string `json:"group_id" validate:"required,uuid4"` 14 | } 15 | 16 | type LeaveGroupResult struct { 17 | GroupId string `json:"group_id" validate:"required,uuid4"` 18 | } 19 | 20 | func (h *NodeSDKHandler) LeaveGroup() echo.HandlerFunc { 21 | return func(c echo.Context) error { 22 | cc := c.(*utils.CustomContext) 23 | 24 | params := new(LeaveGroupParams) 25 | if err := cc.BindAndValidate(params); err != nil { 26 | return err 27 | } 28 | 29 | // save nodesdkgroupitem to db 30 | if err := nodesdkctx.GetCtx().GetChainStorage().RmGroup(params.GroupId); err != nil { 31 | return rumerrors.NewBadRequestError(err) 32 | } 33 | 34 | leaveGroupResult := &LeaveGroupResult{GroupId: params.GroupId} 35 | 36 | return c.JSON(http.StatusOK, leaveGroupResult) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/mgrappconfig.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | ) 8 | 9 | func (h *NodeSDKHandler) MgrAppConfig(c echo.Context) (err error) { 10 | return c.JSON(http.StatusOK, nil) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/rmalias.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | 7 | "github.com/labstack/echo/v4" 8 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 9 | "github.com/rumsystem/quorum/internal/pkg/utils" 10 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 11 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 12 | ) 13 | 14 | type RmAliasParams struct { 15 | Alias string `json:"alias" validate:"required"` 16 | } 17 | 18 | func (h *NodeSDKHandler) RmAlias() echo.HandlerFunc { 19 | return func(c echo.Context) error { 20 | cc := c.(*utils.CustomContext) 21 | params := new(RmAliasParams) 22 | if err := cc.BindAndValidate(params); err != nil { 23 | return err 24 | } 25 | 26 | ks := nodesdkctx.GetKeyStore() 27 | dirks, ok := ks.(*localcrypto.DirKeyStore) 28 | if !ok { 29 | return rumerrors.NewBadRequestError("Open keystore failed") 30 | } 31 | 32 | password := os.Getenv("RUM_KSPASSWD") 33 | 34 | if err := dirks.UnAlias(params.Alias, password); err != nil { 35 | return rumerrors.NewBadRequestError(err) 36 | } 37 | 38 | return c.JSON(http.StatusOK, "done") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/seed.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/labstack/echo/v4" 7 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 8 | "github.com/rumsystem/quorum/internal/pkg/utils" 9 | "github.com/rumsystem/quorum/pkg/chainapi/handlers" 10 | ) 11 | 12 | type SeedUrlextendParam struct { 13 | SeedURL string `json:"seed" validate:"required,url"` 14 | } 15 | 16 | type SeedUrlextendResult struct { 17 | Seed handlers.GroupSeed `json:"seed" validate:"required"` 18 | ChainapiUrls []string `json:"urls" validate:"required,gte=1,dive,required,url"` 19 | } 20 | 21 | func (h *NodeSDKHandler) SeedUrlextend(c echo.Context) error { 22 | cc := c.(*utils.CustomContext) 23 | 24 | param := new(SeedUrlextendParam) 25 | if err := cc.BindAndValidate(param); err != nil { 26 | return rumerrors.NewBadRequestError(err) 27 | } 28 | 29 | seed, urls, err := handlers.UrlToGroupSeed(param.SeedURL) 30 | if err != nil { 31 | return rumerrors.NewBadRequestError(err) 32 | } 33 | 34 | res := SeedUrlextendResult{ 35 | Seed: *seed, 36 | ChainapiUrls: urls, 37 | } 38 | 39 | return c.JSON(http.StatusOK, res) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/updapihosturl.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "github.com/labstack/echo/v4" 5 | rumerrors "github.com/rumsystem/quorum/internal/pkg/errors" 6 | "github.com/rumsystem/quorum/internal/pkg/utils" 7 | pkgutils "github.com/rumsystem/quorum/internal/pkg/utils" 8 | nodesdkctx "github.com/rumsystem/quorum/pkg/nodesdk/nodesdkctx" 9 | ) 10 | 11 | type UpdApiHostUrlParams struct { 12 | GroupId string `json:"group_id" validate:"required,uuid4"` 13 | ChainAPIUrls []string `json:"urls" validate:"required,gte=1,unique,dive,required,url"` 14 | } 15 | 16 | func (h *NodeSDKHandler) UpdApiHostUrl(c echo.Context) (err error) { 17 | cc := c.(*pkgutils.CustomContext) 18 | params := new(UpdApiHostUrlParams) 19 | if err := cc.BindAndValidate(params); err != nil { 20 | return err 21 | } 22 | 23 | for _, _url := range params.ChainAPIUrls { 24 | _, jwt, err := utils.ParseChainapiURL(_url) 25 | if err != nil { 26 | return rumerrors.NewBadRequestError("invalid chain api url") 27 | } 28 | if jwt == "" { 29 | return rumerrors.NewBadRequestError(rumerrors.ErrInvalidJWT) 30 | } 31 | } 32 | 33 | nodesdkGroupItem, err := nodesdkctx.GetCtx().GetChainStorage().GetGroupInfoV2(params.GroupId) 34 | if err != nil { 35 | return rumerrors.NewBadRequestError(err) 36 | } 37 | 38 | nodesdkGroupItem.ApiUrl = params.ChainAPIUrls 39 | 40 | if err := nodesdkctx.GetCtx().GetChainStorage().UpdGroupV2(nodesdkGroupItem); err != nil { 41 | return rumerrors.NewBadRequestError(err) 42 | } 43 | 44 | return cc.Success() 45 | } 46 | -------------------------------------------------------------------------------- /pkg/nodesdk/api/utils.go: -------------------------------------------------------------------------------- 1 | package nodesdkapi 2 | 3 | import ( 4 | "encoding/hex" 5 | 6 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 7 | ) 8 | 9 | func getEncryptData(data []byte, cipherKey string) ([]byte, error) { 10 | 11 | ciperKey, err := hex.DecodeString(cipherKey) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | encryptData, err := localcrypto.AesEncrypt(data, ciperKey) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return encryptData, nil 22 | } 23 | -------------------------------------------------------------------------------- /pkg/nodesdk/nodesdkctx/nodesdkctx.go: -------------------------------------------------------------------------------- 1 | package nodesdk 2 | 3 | import ( 4 | "context" 5 | 6 | p2pcrypto "github.com/libp2p/go-libp2p/core/crypto" 7 | "github.com/libp2p/go-libp2p/core/peer" 8 | "github.com/rumsystem/quorum/internal/pkg/storage" 9 | chainstorage "github.com/rumsystem/quorum/internal/pkg/storage/chain" 10 | localcrypto "github.com/rumsystem/quorum/pkg/crypto" 11 | 12 | //nodesdkdb "github.com/rumsystem/quorum/pkg/nodesdk/db" 13 | http_client "github.com/rumsystem/quorum/pkg/nodesdk/http" 14 | ) 15 | 16 | type NodeSdkCtx struct { 17 | Ctx context.Context 18 | Keystore localcrypto.Keystore 19 | HttpClients map[string]*http_client.HttpClient 20 | Name string 21 | Version string 22 | PeerId peer.ID 23 | PublicKey p2pcrypto.PubKey 24 | chaindb *chainstorage.Storage 25 | } 26 | 27 | var dbMgr *storage.DbMgr 28 | 29 | var nodesdkCtx *NodeSdkCtx 30 | 31 | func GetCtx() *NodeSdkCtx { 32 | return nodesdkCtx 33 | } 34 | 35 | func Init(ctx context.Context, name string, db *storage.DbMgr, chaindb *chainstorage.Storage) { 36 | nodesdkCtx = &NodeSdkCtx{} 37 | nodesdkCtx.Name = name 38 | nodesdkCtx.Ctx = ctx 39 | nodesdkCtx.Version = "1.0.0" 40 | nodesdkCtx.chaindb = chaindb 41 | nodesdkCtx.HttpClients = make(map[string]*http_client.HttpClient) 42 | dbMgr = db 43 | } 44 | 45 | func GetDbMgr() *storage.DbMgr { 46 | return dbMgr 47 | } 48 | 49 | func GetKeyStore() localcrypto.Keystore { 50 | return nodesdkCtx.Keystore 51 | } 52 | 53 | func (ctx *NodeSdkCtx) GetChainStorage() *chainstorage.Storage { 54 | return nodesdkCtx.chaindb 55 | } 56 | 57 | func (ctx *NodeSdkCtx) GetHttpClient(groupId string) (*http_client.HttpClient, error) { 58 | if _, ok := ctx.HttpClients[groupId]; !ok { 59 | client := &http_client.HttpClient{} 60 | err := client.Init() 61 | if err != nil { 62 | return nil, err 63 | } 64 | ctx.HttpClients[groupId] = client 65 | } 66 | 67 | c, _ := ctx.HttpClients[groupId] 68 | return c, nil 69 | } 70 | -------------------------------------------------------------------------------- /pkg/pb/rumexchange.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package quorum.pb; 3 | import "chain.proto"; 4 | option go_package = "github.com/rumsystem/quorum/pkg/pb"; 5 | 6 | message RumDataMsg { 7 | RumDataMsgType MsgType = 1; 8 | optional Package DataPackage = 2; 9 | } 10 | 11 | enum RumDataMsgType { 12 | CHAIN_DATA = 0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /pkg/pb/utils.go: -------------------------------------------------------------------------------- 1 | package pb 2 | 3 | import ( 4 | "fmt" 5 | "google.golang.org/protobuf/proto" 6 | "google.golang.org/protobuf/types/known/anypb" 7 | "strings" 8 | ) 9 | 10 | func ContentToBytes(content proto.Message) ([]byte, error) { 11 | any, err := anypb.New(content) 12 | 13 | if err != nil { 14 | return nil, err 15 | } 16 | encodedcontent, err := proto.Marshal(any) 17 | return encodedcontent, err 18 | } 19 | 20 | func BytesToMessageDefault(content []byte) (proto.Message, string, error) { 21 | anyobj := &anypb.Any{} 22 | var msg proto.Message 23 | if len(content) == 0 { 24 | return nil, "", fmt.Errorf("content must not be nil") 25 | } 26 | err := proto.Unmarshal(content, anyobj) 27 | if err != nil { 28 | return nil, "", err 29 | } 30 | 31 | msg, err = anyobj.UnmarshalNew() 32 | if err != nil { 33 | return nil, "", err 34 | } 35 | typeurl := strings.Replace(anyobj.TypeUrl, "type.googleapis.com/", "", 1) 36 | return msg, typeurl, err 37 | } 38 | 39 | func BytesToMessage(trxid string, content []byte) (proto.Message, string, error) { 40 | anyobj := &anypb.Any{} 41 | 42 | var ctnobj proto.Message 43 | var typeurl string 44 | 45 | if len(content) == 0 { 46 | ctnobj = &Object{} 47 | typeurl = "quorum.pb.Object" 48 | return ctnobj, typeurl, nil 49 | } 50 | 51 | err := proto.Unmarshal(content, anyobj) 52 | if err != nil { 53 | return nil, "", fmt.Errorf("Unmarshal trx.Data id %s Err: %s", trxid, err) 54 | } 55 | ctnobj, err = anyobj.UnmarshalNew() 56 | if err != nil { //old data pb.Object{} compatibility 57 | ctnobj = &Object{} 58 | err = proto.Unmarshal(content, ctnobj) 59 | if err != nil { 60 | return nil, "", fmt.Errorf("try old data compatibility Unmarshal %s Err: %s", trxid, err) 61 | } else { 62 | typeurl = "quorum.pb.Object" 63 | } 64 | } else { 65 | typeurl = strings.Replace(anyobj.TypeUrl, "type.googleapis.com/", "", 1) 66 | } 67 | return ctnobj, typeurl, nil 68 | } 69 | -------------------------------------------------------------------------------- /scripts/protoupdate.sh: -------------------------------------------------------------------------------- 1 | protoc -I=pkg/pb --go_out=pkg/pb pkg/pb/chain.proto 2 | mv pkg/pb/github.com/rumsystem/quorum/pkg/pb/chain.pb.go pkg/pb/chain.pb.go 3 | sed -i 's/TimeStamp,omitempty/TimeStamp,omitempty,string/g' pkg/pb/chain.pb.go 4 | 5 | protoc -I=pkg/pb --go_out=pkg/pb pkg/pb/rumexchange.proto 6 | mv pkg/pb/github.com/rumsystem/quorum/pkg/pb/rumexchange.pb.go pkg/pb/rumexchange.pb.go 7 | 8 | protoc -I=pkg/pb --go_out=pkg/pb pkg/pb/activity_stream.proto 9 | mv pkg/pb/github.com/rumsystem/quorum/pkg/pb/activity_stream.pb.go pkg/pb/activity_stream.pb.go 10 | sed -i 's/TimeStamp,omitempty/TimeStamp,omitempty,string/g' pkg/pb/activity_stream.pb.go 11 | -------------------------------------------------------------------------------- /scripts/runbootstrap.sh: -------------------------------------------------------------------------------- 1 | RUM_KSPASSWD=ketchup-ramp-secret-lock-catalog-gorilla-later-belt-stage-custom go run main.go bootstrapnode --listen /ip4/0.0.0.0/tcp/10666 --apiport 10667 2 | -------------------------------------------------------------------------------- /systemd/quorum.service.sample: -------------------------------------------------------------------------------- 1 | # quorum.service 2 | 3 | [Unit] 4 | Description=RUM node 5 | After=network.target network-online.target 6 | Requires=network-online.target 7 | 8 | [Service] 9 | User=rum 10 | Group=rum 11 | RuntimeMaxSec=24h 12 | Environment="RUM_KSPASSWD=YOUR_PASSWORD" 13 | ExecStart=/usr/local/bin/quorum_linux fullnode --peername peer0 --listen /ip4/0.0.0.0/tcp/27002 --listen /ip4/0.0.0.0/tcp/27003/ws --apiport 28002 --apihost 127.0.0.1 --peer /ip4/94.23.17.189/tcp/62777/p2p/16Uiu2HAm5waftP3s4oE1EzGF2SyWeK726P5B8BSgFJqSiz6xScGz,/ip4/132.145.109.63/tcp/10666/p2p/16Uiu2HAmTovb8kAJiYK8saskzz7cRQhb45NRK5AsbtdmYsLfD3RM --configdir /var/data/peer0data/config --datadir /var/data/peer0data/peerdata --keystoredir /var/data/peer0data/keystore 14 | TimeoutStopSec=10s 15 | LimitNOFILE=1048576 16 | LimitNPROC=512 17 | PrivateTmp=true 18 | Restart=always 19 | RestartSec=10 20 | ProtectSystem=full 21 | AmbientCapabilities=CAP_NET_BIND_SERVICE 22 | 23 | [Install] 24 | WantedBy=multi-user.target 25 | -------------------------------------------------------------------------------- /testnode/fork.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package testnode 5 | 6 | import ( 7 | //"fmt" 8 | "io" 9 | "os" 10 | "os/exec" 11 | "sync" 12 | "syscall" 13 | ) 14 | 15 | func Fork(pidch chan int, keystorepassword string, cmdName string, cmdArgs ...string) { 16 | go func() { 17 | command := exec.Command(cmdName, cmdArgs...) 18 | 19 | var stdout, stderr []byte 20 | var errStdout, errStderr error 21 | stdoutIn, _ := command.StdoutPipe() 22 | stderrIn, _ := command.StderrPipe() 23 | 24 | command.Env = append(os.Environ(), 25 | "RUM_KSPASSWD="+keystorepassword, 26 | ) 27 | 28 | logger.Debugf("run command: %s", command) 29 | command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 30 | err := command.Start() 31 | if err != nil { 32 | logger.Warn(err, string(stderr)) 33 | } 34 | 35 | var wg sync.WaitGroup 36 | wg.Add(1) 37 | go func() { 38 | stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn) 39 | wg.Done() 40 | }() 41 | 42 | stderr, errStderr = copyAndCapture(os.Stderr, stderrIn) 43 | wg.Wait() 44 | 45 | if errStdout != nil || errStderr != nil { 46 | logger.Fatal("failed to capture stdout or stderr") 47 | } 48 | //outStr, errStr := string(stdout), string(stderr) 49 | _, _ = string(stdout), string(stderr) 50 | //fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr) 51 | 52 | pidch <- command.Process.Pid 53 | }() 54 | } 55 | 56 | func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) { 57 | var out []byte 58 | buf := make([]byte, 1024, 1024) 59 | for { 60 | n, err := r.Read(buf[:]) 61 | if n > 0 { 62 | d := buf[:n] 63 | out = append(out, d...) 64 | _, err := w.Write(d) 65 | if err != nil { 66 | return out, err 67 | } 68 | } 69 | if err != nil { 70 | // Read returns io.EOF at the end of file, which is not an error for us 71 | if err == io.EOF { 72 | err = nil 73 | } 74 | return out, err 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /testnode/fork_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package testnode 5 | 6 | import ( 7 | "fmt" 8 | "io" 9 | "os" 10 | "os/exec" 11 | "sync" 12 | ) 13 | 14 | func Fork(pidch chan int, keystorepassword string, cmdName string, cmdArgs ...string) { 15 | go func() { 16 | command := exec.Command(cmdName, cmdArgs...) 17 | 18 | var stdout, stderr []byte 19 | var errStdout, errStderr error 20 | stdoutIn, _ := command.StdoutPipe() 21 | stderrIn, _ := command.StderrPipe() 22 | 23 | command.Env = append(os.Environ(), 24 | "RUM_KSPASSWD="+keystorepassword, 25 | ) 26 | 27 | logger.Debugf("run command: %s", command) 28 | err := command.Start() 29 | if err != nil { 30 | logger.Error(err, string(stderr)) 31 | } 32 | 33 | var wg sync.WaitGroup 34 | wg.Add(1) 35 | go func() { 36 | stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn) 37 | wg.Done() 38 | }() 39 | 40 | stderr, errStderr = copyAndCapture(os.Stderr, stderrIn) 41 | wg.Wait() 42 | 43 | if errStdout != nil || errStderr != nil { 44 | logger.Error("failed to capture stdout or stderr") 45 | } 46 | outStr, errStr := string(stdout), string(stderr) 47 | fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr) 48 | 49 | pidch <- command.Process.Pid 50 | }() 51 | } 52 | 53 | func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) { 54 | var out []byte 55 | buf := make([]byte, 1024, 1024) 56 | for { 57 | n, err := r.Read(buf[:]) 58 | if n > 0 { 59 | d := buf[:n] 60 | out = append(out, d...) 61 | _, err := w.Write(d) 62 | if err != nil { 63 | return out, err 64 | } 65 | } 66 | if err != nil { 67 | // Read returns io.EOF at the end of file, which is not an error for us 68 | if err == io.EOF { 69 | err = nil 70 | } 71 | return out, err 72 | } 73 | } 74 | } 75 | --------------------------------------------------------------------------------