From 7899c807b91db1cce7edaa35930172dacdf5edd3 Mon Sep 17 00:00:00 2001 From: brennan lamey Date: Wed, 15 Nov 2023 10:39:58 -0600 Subject: [PATCH 01/13] auto kwil cli docs auto kwil cli docs mostly finished with migrating kwil admin, still cleaning uo mostly finished with migrating kwil admin, still cleaning up refactored kwil admin into a standard cobra app minor changes to doc generation registering txsvc in the admin svc as well made an example admin grpc client added admin client that includes kwild client added documentation for tls added protobuf for expanded admin svc various changes and cleanup for rpcs http codegen added http client using generated stubs, fixed several bugs in current proto definitions refactoring the clients gateway client concept added gateway client to kwil-cli everything building, still some issues various bug fixes final cleanup, tweaks fixed bug causing failures in integration tests update ci check swagger generated code added url parsing util since stdlib is very finnicky when managing grpc, http, and unix update linter skip dirs update assert import tidy enable swagger check added integration test mounting for volumes fixed docker compose issue in acceptance test debugging integration test unix sockets improved output formatting for kwil-admin various upgrades to tests for validators fixed all integration tests updated run permissions of swagger check script addressed Jons feedback, trying new permission with failing script fixed failing unit tests added kwil-admin to main dockerfile retrying due to transient ci error trying to fix failing CI build fix dockerfile copy command added a node info utility, and also added integration tests changed all kwild flags to use hyphens, since it is far more common figured bug caused by updating flags to hyphens from underscores changed flags to use hyphens instead of underscores in flags, to be in line with GNU standards fixed typo that linter was complaining about added functionsvc client removed node info, due to security issues added setup peer command, which makes it easy to join a running network. Also changed genesis to exist in root dir added list pending joins output and formatting upgrades --- .github/workflows/ci.yaml | 9 + .gitignore | 3 + .golangci.yml | 3 + Taskfile-pb.yml | 87 +- Taskfile.yml | 9 +- build/package/docker/kwild.dockerfile | 6 +- build/package/docker/kwild.shell.dockerfile | 24 - cmd/common/display/format.go | 202 +++ .../display/format_test.go | 19 +- cmd/common/display/message.go | 40 + .../display/message_test.go | 21 +- cmd/common/generate/cobra.go | 126 ++ cmd/common/generate/generate.go | 160 +++ cmd/common/generate/generate_test.go | 43 + .../cmds/system => common/version}/version.go | 13 +- .../system => common/version}/version_test.go | 4 +- cmd/internal/display/format.go | 98 -- cmd/internal/display/message.go | 27 - cmd/kwil-admin/args.go | 25 - cmd/kwil-admin/cmds/common/paths.go | 16 + cmd/kwil-admin/cmds/common/rpc.go | 165 +++ cmd/kwil-admin/cmds/key/cmd.go | 23 + cmd/kwil-admin/cmds/key/gen.go | 53 + cmd/kwil-admin/cmds/key/info.go | 53 + cmd/kwil-admin/cmds/node/cmd.go | 25 + cmd/kwil-admin/cmds/node/gen-auth-key.go | 68 + cmd/kwil-admin/cmds/node/peers.go | 61 + cmd/kwil-admin/cmds/node/status.go | 61 + cmd/kwil-admin/cmds/node/version.go | 43 + cmd/kwil-admin/cmds/root.go | 36 + cmd/kwil-admin/cmds/setup/cmd.go | 44 + cmd/kwil-admin/cmds/setup/genesis-hash.go | 49 + cmd/kwil-admin/cmds/setup/init.go | 63 + cmd/kwil-admin/cmds/setup/peer.go | 84 ++ cmd/kwil-admin/cmds/setup/reset-state.go | 54 + cmd/kwil-admin/cmds/setup/reset.go | 75 ++ cmd/kwil-admin/cmds/setup/testnet.go | 93 ++ cmd/kwil-admin/cmds/utils/cmd.go | 21 + cmd/kwil-admin/cmds/utils/ping.go | 43 + cmd/kwil-admin/cmds/utils/query-tx.go | 85 ++ cmd/kwil-admin/cmds/validators/approve.go | 49 + cmd/kwil-admin/cmds/validators/cmd.go | 31 + cmd/kwil-admin/cmds/validators/join-status.go | 115 ++ cmd/kwil-admin/cmds/validators/join.go | 43 + cmd/kwil-admin/cmds/validators/leave.go | 43 + .../cmds/validators/list-join-requests.go | 90 ++ cmd/kwil-admin/cmds/validators/list.go | 82 ++ cmd/kwil-admin/cmds/validators/remove.go | 49 + cmd/kwil-admin/generate/generate.go | 23 + cmd/kwil-admin/key.go | 70 - cmd/kwil-admin/main.go | 119 +- cmd/kwil-admin/message.go | 80 -- cmd/kwil-admin/message_test.go | 84 -- cmd/kwil-admin/node.go | 208 --- cmd/kwil-admin/nodecfg/generate.go | 117 +- cmd/kwil-admin/nodecfg/toml.go | 19 +- cmd/kwil-admin/nodecfg/toml_test.go | 7 +- cmd/kwil-admin/setup.go | 189 --- cmd/kwil-admin/validator.go | 203 --- cmd/kwil-cli/cmds/common/authinfo.go | 106 +- cmd/kwil-cli/cmds/common/authinfo_test.go | 7 +- cmd/kwil-cli/cmds/common/flags.go | 16 + cmd/kwil-cli/cmds/common/roundtripper.go | 153 ++- cmd/kwil-cli/cmds/configure/configure.go | 27 +- cmd/kwil-cli/cmds/database/batch.go | 71 +- cmd/kwil-cli/cmds/database/call.go | 84 +- cmd/kwil-cli/cmds/database/cmd.go | 4 +- cmd/kwil-cli/cmds/database/deploy.go | 45 +- cmd/kwil-cli/cmds/database/drop.go | 39 +- cmd/kwil-cli/cmds/database/execute.go | 69 +- cmd/kwil-cli/cmds/database/list.go | 32 +- cmd/kwil-cli/cmds/database/message_test.go | 2 +- cmd/kwil-cli/cmds/database/query.go | 47 +- cmd/kwil-cli/cmds/database/read_schema.go | 45 +- cmd/kwil-cli/cmds/root.go | 41 + cmd/kwil-cli/cmds/utils/auth.go | 81 +- cmd/kwil-cli/cmds/utils/chain_id.go | 26 +- cmd/kwil-cli/cmds/utils/message.go | 28 +- cmd/kwil-cli/cmds/utils/message_test.go | 45 +- cmd/kwil-cli/cmds/utils/ping.go | 21 +- cmd/kwil-cli/cmds/utils/printConfig.go | 10 +- cmd/kwil-cli/cmds/utils/tx_query.go | 27 +- cmd/kwil-cli/cmds/utils/utils.go | 4 +- cmd/kwil-cli/config/flags.go | 48 +- cmd/kwil-cli/generate/gen.go | 23 + cmd/kwil-cli/main.go | 37 +- cmd/kwild/config/config.go | 331 +++-- cmd/kwild/config/config_test.go | 6 +- cmd/kwild/config/default_config.toml | 6 +- cmd/kwild/config/genesis.go | 7 +- cmd/kwild/flags.go | 76 +- cmd/kwild/main.go | 89 +- cmd/kwild/server/build.go | 171 ++- cmd/kwild/server/cometbft.go | 15 +- cmd/kwild/server/server.go | 16 +- cmd/kwild/server/utils.go | 6 +- core/adminclient/client.go | 119 ++ core/adminclient/opts.go | 23 + core/client/client.go | 287 +--- core/client/iter.go | 170 --- core/client/kgw.go | 168 --- core/client/kgw_test.go | 20 - core/client/opts.go | 101 +- core/client/tx.go | 9 +- core/gatewayclient/client.go | 164 +++ core/gatewayclient/msg.go | 60 + core/gatewayclient/opts.go | 35 + core/go.mod | 7 +- core/go.sum | 13 + core/rpc/client/admin/admin.go | 22 + core/rpc/client/admin/admin_client.go | 104 -- core/rpc/client/admin/grpc/client.go | 170 +++ core/rpc/client/defaults.go | 16 + core/rpc/client/error.go | 31 +- core/rpc/client/function/function.go | 12 + core/rpc/client/function/http/client.go | 67 + core/rpc/client/function/http/opts.go | 17 + core/rpc/client/gateway/gateway.go | 38 + core/rpc/client/gateway/http/client.go | 128 ++ core/rpc/client/gateway/http/opts.go | 17 + core/rpc/client/user/grpc/client.go | 26 +- core/rpc/client/user/grpc/rpc.go | 81 +- core/rpc/client/user/http/client.go | 370 +++--- core/rpc/client/user/http/client_opt.go | 54 - core/rpc/client/user/http/convert.go | 255 ++++ core/rpc/client/user/http/cookie_test.go | 72 - core/rpc/client/user/http/opts.go | 19 + core/rpc/client/user/http/req.go | 437 ------- core/rpc/client/user/http/req_test.go | 564 -------- core/rpc/client/user/http/rpc.go | 232 ---- .../get_account_not_exist_expect.json | 5 - .../get_account_not_exist_response.json | 7 - .../http/testdata/get_account_ok_expect.json | 5 - .../testdata/get_account_ok_response.json | 7 - .../http/testdata/get_schema_ok_expect.json | 275 ---- .../http/testdata/get_schema_ok_response.json | 312 ----- .../testdata/tx_query_not_found_response.json | 5 - .../http/testdata/tx_query_ok_expect.json | 26 - .../http/testdata/tx_query_ok_response.json | 28 - core/rpc/client/user/http/typewrap.go | 225 ---- core/rpc/client/user/txsvc.go | 27 + core/rpc/conversion/tx.go | 59 +- core/rpc/http/function/.gitignore | 24 + .../rpc/http/function/.swagger-codegen-ignore | 23 + .../http/function/.swagger-codegen/VERSION | 1 + core/rpc/http/function/.travis.yml | 8 + core/rpc/http/function/README.md | 39 + core/rpc/http/function/api/swagger.yaml | 89 ++ .../rpc/http/function/api_function_service.go | 120 ++ core/rpc/http/function/client.go | 473 +++++++ core/rpc/http/function/configuration.go | 71 + .../http/function/docs/FunctionServiceApi.md | 34 + .../docs/FunctionVerifySignatureRequest.md | 11 + .../docs/FunctionVerifySignatureResponse.md | 10 + core/rpc/http/function/docs/RpcStatus.md | 11 + core/rpc/http/function/docs/TxSignature.md | 10 + core/rpc/http/function/git_push.sh | 52 + ...model_function_verify_signature_request.go | 15 + ...odel_function_verify_signature_response.go | 14 + core/rpc/http/function/model_rpc_status.go | 15 + core/rpc/http/function/model_tx_signature.go | 14 + core/rpc/http/function/response.go | 42 + core/rpc/http/tx/.gitignore | 24 + core/rpc/http/tx/.swagger-codegen-ignore | 23 + core/rpc/http/tx/.swagger-codegen/VERSION | 1 + core/rpc/http/tx/.travis.yml | 8 + core/rpc/http/tx/README.md | 79 ++ core/rpc/http/tx/api/swagger.yaml | 1165 +++++++++++++++++ core/rpc/http/tx/api_tx_service.go | 1080 +++++++++++++++ core/rpc/http/tx/client.go | 473 +++++++ core/rpc/http/tx/configuration.go | 71 + .../http/tx/docs/ExtensionsExtensionConfig.md | 10 + core/rpc/http/tx/docs/RpcStatus.md | 11 + core/rpc/http/tx/docs/TxAccount.md | 11 + core/rpc/http/tx/docs/TxAccountStatus.md | 8 + core/rpc/http/tx/docs/TxAction.md | 15 + core/rpc/http/tx/docs/TxAttribute.md | 10 + core/rpc/http/tx/docs/TxBroadcastRequest.md | 9 + core/rpc/http/tx/docs/TxBroadcastResponse.md | 9 + core/rpc/http/tx/docs/TxCallRequest.md | 11 + core/rpc/http/tx/docs/TxCallRequestBody.md | 9 + core/rpc/http/tx/docs/TxCallResponse.md | 9 + core/rpc/http/tx/docs/TxChainInfoResponse.md | 11 + core/rpc/http/tx/docs/TxColumn.md | 11 + .../http/tx/docs/TxEstimatePriceRequest.md | 9 + .../http/tx/docs/TxEstimatePriceResponse.md | 9 + core/rpc/http/tx/docs/TxExtensions.md | 11 + core/rpc/http/tx/docs/TxForeignKey.md | 12 + core/rpc/http/tx/docs/TxForeignKeyAction.md | 10 + core/rpc/http/tx/docs/TxGetAccountResponse.md | 9 + core/rpc/http/tx/docs/TxGetConfigResponse.md | 11 + core/rpc/http/tx/docs/TxGetSchemaResponse.md | 9 + core/rpc/http/tx/docs/TxIndex.md | 11 + .../http/tx/docs/TxListDatabasesResponse.md | 9 + core/rpc/http/tx/docs/TxNodeInfoResponse.md | 11 + core/rpc/http/tx/docs/TxPingResponse.md | 9 + core/rpc/http/tx/docs/TxQueryRequest.md | 10 + core/rpc/http/tx/docs/TxQueryResponse.md | 9 + core/rpc/http/tx/docs/TxSchema.md | 13 + core/rpc/http/tx/docs/TxServiceApi.md | 310 +++++ core/rpc/http/tx/docs/TxSignature.md | 10 + core/rpc/http/tx/docs/TxTable.md | 12 + core/rpc/http/tx/docs/TxTransaction.md | 12 + core/rpc/http/tx/docs/TxTransactionBody.md | 14 + core/rpc/http/tx/docs/TxTransactionResult.md | 14 + core/rpc/http/tx/docs/TxTxQueryRequest.md | 9 + core/rpc/http/tx/docs/TxTxQueryResponse.md | 12 + core/rpc/http/tx/git_push.sh | 52 + .../tx/model_extensions_extension_config.go | 14 + core/rpc/http/tx/model_rpc_status.go | 15 + core/rpc/http/tx/model_tx_account.go | 15 + core/rpc/http/tx/model_tx_account_status.go | 17 + core/rpc/http/tx/model_tx_action.go | 19 + core/rpc/http/tx/model_tx_attribute.go | 14 + .../rpc/http/tx/model_tx_broadcast_request.go | 13 + .../http/tx/model_tx_broadcast_response.go | 13 + core/rpc/http/tx/model_tx_call_request.go | 16 + .../rpc/http/tx/model_tx_call_request_body.go | 13 + core/rpc/http/tx/model_tx_call_response.go | 13 + .../http/tx/model_tx_chain_info_response.go | 15 + core/rpc/http/tx/model_tx_column.go | 15 + .../tx/model_tx_estimate_price_request.go | 13 + .../tx/model_tx_estimate_price_response.go | 13 + core/rpc/http/tx/model_tx_extensions.go | 15 + core/rpc/http/tx/model_tx_foreign_key.go | 16 + .../http/tx/model_tx_foreign_key_action.go | 14 + .../http/tx/model_tx_get_account_response.go | 13 + .../http/tx/model_tx_get_config_response.go | 15 + .../http/tx/model_tx_get_schema_response.go | 13 + core/rpc/http/tx/model_tx_index.go | 15 + .../tx/model_tx_list_databases_response.go | 13 + .../http/tx/model_tx_node_info_response.go | 16 + core/rpc/http/tx/model_tx_ping_response.go | 13 + core/rpc/http/tx/model_tx_query_request.go | 14 + core/rpc/http/tx/model_tx_query_response.go | 13 + core/rpc/http/tx/model_tx_schema.go | 17 + core/rpc/http/tx/model_tx_signature.go | 14 + core/rpc/http/tx/model_tx_table.go | 16 + core/rpc/http/tx/model_tx_transaction.go | 16 + core/rpc/http/tx/model_tx_transaction_body.go | 18 + .../http/tx/model_tx_transaction_result.go | 19 + core/rpc/http/tx/model_tx_tx_query_request.go | 13 + .../rpc/http/tx/model_tx_tx_query_response.go | 16 + core/rpc/http/tx/response.go | 42 + core/rpc/protobuf/admin/v0/messages.pb.go | 1159 +++++++++++----- core/rpc/protobuf/admin/v0/service.pb.go | 156 ++- core/rpc/protobuf/admin/v0/service_grpc.pb.go | 303 ++++- core/rpc/protobuf/function/v0/messages.pb.go | 244 ++++ core/rpc/protobuf/function/v0/service.pb.go | 86 ++ .../protobuf/function/v0/service_grpc.pb.go | 109 ++ core/rpc/protobuf/tx/v1/call.pb.go | 34 +- core/rpc/protobuf/tx/v1/dataset.pb.go | 323 ++++- core/rpc/protobuf/tx/v1/info.pb.go | 220 ++++ core/rpc/protobuf/tx/v1/service.pb.go | 281 ++-- core/rpc/protobuf/tx/v1/service.pb.gw.go | 512 -------- core/rpc/protobuf/tx/v1/service_grpc.pb.go | 244 +--- core/rpc/protobuf/tx/v1/signature.pb.go | 184 +-- core/rpc/transport/grpc.go | 16 +- core/types/admin/types.go | 5 +- core/types/gateway/gateway.go | 21 + core/types/types.go | 32 +- core/utils/url/errors.go | 7 + core/utils/url/url.go | 134 ++ core/utils/url/url_test.go | 89 ++ deployments/compose/kwil/docker-compose.yml | 30 +- go.mod | 18 +- go.sum | 27 +- internal/abci/cometbft/genesis.go | 12 +- internal/abci/utils.go | 69 +- internal/admin/admin.go | 96 -- internal/admin/opts.go | 20 - internal/admin/tls.go | 26 - internal/services/grpc/admin/v0/service.go | 246 +++- .../sig_verify.go => function/v0/service.go} | 19 +- internal/services/grpc/txsvc/v1/convert.go | 31 +- internal/services/grpc/txsvc/v1/validator.go | 74 -- internal/services/grpc_gateway/gateway.go | 7 +- internal/services/http/api/embed.go | 7 +- .../http/api/function/v0.swagger.json | 121 ++ internal/services/http/api/swaggerui.html | 28 +- .../http/api/{ => tx}/v1.swagger.json | 390 +----- internal/services/http/swagger/handler.go | 9 +- proto | 2 +- scripts/swagger/check_up | 25 + test/acceptance/docker-compose.yml | 15 +- test/acceptance/driver.go | 2 +- test/acceptance/helper.go | 43 +- test/acceptance/kwild_test.go | 9 +- test/driver/cli_driver.go | 193 +-- test/driver/client_driver.go | 43 +- test/driver/operator/cli_driver.go | 149 +++ test/driver/operator/operator.go | 9 + test/go.mod | 11 +- test/go.sum | 21 +- test/integration/docker-compose.yml | 53 +- test/integration/driver.go | 2 - test/integration/helper.go | 106 +- test/integration/kwild_test.go | 7 +- test/specifications/dsl.go | 6 + test/specifications/info.go | 20 + test/stress/hammer.go | 36 +- test/stress/transport.go | 30 +- 302 files changed, 14101 insertions(+), 7865 deletions(-) delete mode 100644 build/package/docker/kwild.shell.dockerfile create mode 100644 cmd/common/display/format.go rename cmd/{internal => common}/display/format_test.go (67%) create mode 100644 cmd/common/display/message.go rename cmd/{internal => common}/display/message_test.go (72%) create mode 100644 cmd/common/generate/cobra.go create mode 100644 cmd/common/generate/generate.go create mode 100644 cmd/common/generate/generate_test.go rename cmd/{kwil-cli/cmds/system => common/version}/version.go (88%) rename cmd/{kwil-cli/cmds/system => common/version}/version_test.go (94%) delete mode 100644 cmd/internal/display/format.go delete mode 100644 cmd/internal/display/message.go delete mode 100644 cmd/kwil-admin/args.go create mode 100644 cmd/kwil-admin/cmds/common/paths.go create mode 100644 cmd/kwil-admin/cmds/common/rpc.go create mode 100644 cmd/kwil-admin/cmds/key/cmd.go create mode 100644 cmd/kwil-admin/cmds/key/gen.go create mode 100644 cmd/kwil-admin/cmds/key/info.go create mode 100644 cmd/kwil-admin/cmds/node/cmd.go create mode 100644 cmd/kwil-admin/cmds/node/gen-auth-key.go create mode 100644 cmd/kwil-admin/cmds/node/peers.go create mode 100644 cmd/kwil-admin/cmds/node/status.go create mode 100644 cmd/kwil-admin/cmds/node/version.go create mode 100644 cmd/kwil-admin/cmds/root.go create mode 100644 cmd/kwil-admin/cmds/setup/cmd.go create mode 100644 cmd/kwil-admin/cmds/setup/genesis-hash.go create mode 100644 cmd/kwil-admin/cmds/setup/init.go create mode 100644 cmd/kwil-admin/cmds/setup/peer.go create mode 100644 cmd/kwil-admin/cmds/setup/reset-state.go create mode 100644 cmd/kwil-admin/cmds/setup/reset.go create mode 100644 cmd/kwil-admin/cmds/setup/testnet.go create mode 100644 cmd/kwil-admin/cmds/utils/cmd.go create mode 100644 cmd/kwil-admin/cmds/utils/ping.go create mode 100644 cmd/kwil-admin/cmds/utils/query-tx.go create mode 100644 cmd/kwil-admin/cmds/validators/approve.go create mode 100644 cmd/kwil-admin/cmds/validators/cmd.go create mode 100644 cmd/kwil-admin/cmds/validators/join-status.go create mode 100644 cmd/kwil-admin/cmds/validators/join.go create mode 100644 cmd/kwil-admin/cmds/validators/leave.go create mode 100644 cmd/kwil-admin/cmds/validators/list-join-requests.go create mode 100644 cmd/kwil-admin/cmds/validators/list.go create mode 100644 cmd/kwil-admin/cmds/validators/remove.go create mode 100644 cmd/kwil-admin/generate/generate.go delete mode 100644 cmd/kwil-admin/key.go delete mode 100644 cmd/kwil-admin/message.go delete mode 100644 cmd/kwil-admin/message_test.go delete mode 100644 cmd/kwil-admin/node.go delete mode 100644 cmd/kwil-admin/setup.go delete mode 100644 cmd/kwil-admin/validator.go create mode 100644 cmd/kwil-cli/cmds/common/flags.go create mode 100644 cmd/kwil-cli/cmds/root.go create mode 100644 cmd/kwil-cli/generate/gen.go create mode 100644 core/adminclient/client.go create mode 100644 core/adminclient/opts.go delete mode 100644 core/client/kgw.go delete mode 100644 core/client/kgw_test.go create mode 100644 core/gatewayclient/client.go create mode 100644 core/gatewayclient/msg.go create mode 100644 core/gatewayclient/opts.go create mode 100644 core/rpc/client/admin/admin.go delete mode 100644 core/rpc/client/admin/admin_client.go create mode 100644 core/rpc/client/admin/grpc/client.go create mode 100644 core/rpc/client/defaults.go create mode 100644 core/rpc/client/function/function.go create mode 100644 core/rpc/client/function/http/client.go create mode 100644 core/rpc/client/function/http/opts.go create mode 100644 core/rpc/client/gateway/gateway.go create mode 100644 core/rpc/client/gateway/http/client.go create mode 100644 core/rpc/client/gateway/http/opts.go delete mode 100644 core/rpc/client/user/http/client_opt.go create mode 100644 core/rpc/client/user/http/convert.go delete mode 100644 core/rpc/client/user/http/cookie_test.go create mode 100644 core/rpc/client/user/http/opts.go delete mode 100644 core/rpc/client/user/http/req.go delete mode 100644 core/rpc/client/user/http/req_test.go delete mode 100644 core/rpc/client/user/http/rpc.go delete mode 100644 core/rpc/client/user/http/testdata/get_account_not_exist_expect.json delete mode 100644 core/rpc/client/user/http/testdata/get_account_not_exist_response.json delete mode 100644 core/rpc/client/user/http/testdata/get_account_ok_expect.json delete mode 100644 core/rpc/client/user/http/testdata/get_account_ok_response.json delete mode 100644 core/rpc/client/user/http/testdata/get_schema_ok_expect.json delete mode 100644 core/rpc/client/user/http/testdata/get_schema_ok_response.json delete mode 100644 core/rpc/client/user/http/testdata/tx_query_not_found_response.json delete mode 100644 core/rpc/client/user/http/testdata/tx_query_ok_expect.json delete mode 100644 core/rpc/client/user/http/testdata/tx_query_ok_response.json delete mode 100644 core/rpc/client/user/http/typewrap.go create mode 100644 core/rpc/client/user/txsvc.go create mode 100644 core/rpc/http/function/.gitignore create mode 100644 core/rpc/http/function/.swagger-codegen-ignore create mode 100644 core/rpc/http/function/.swagger-codegen/VERSION create mode 100644 core/rpc/http/function/.travis.yml create mode 100644 core/rpc/http/function/README.md create mode 100644 core/rpc/http/function/api/swagger.yaml create mode 100644 core/rpc/http/function/api_function_service.go create mode 100644 core/rpc/http/function/client.go create mode 100644 core/rpc/http/function/configuration.go create mode 100644 core/rpc/http/function/docs/FunctionServiceApi.md create mode 100644 core/rpc/http/function/docs/FunctionVerifySignatureRequest.md create mode 100644 core/rpc/http/function/docs/FunctionVerifySignatureResponse.md create mode 100644 core/rpc/http/function/docs/RpcStatus.md create mode 100644 core/rpc/http/function/docs/TxSignature.md create mode 100644 core/rpc/http/function/git_push.sh create mode 100644 core/rpc/http/function/model_function_verify_signature_request.go create mode 100644 core/rpc/http/function/model_function_verify_signature_response.go create mode 100644 core/rpc/http/function/model_rpc_status.go create mode 100644 core/rpc/http/function/model_tx_signature.go create mode 100644 core/rpc/http/function/response.go create mode 100644 core/rpc/http/tx/.gitignore create mode 100644 core/rpc/http/tx/.swagger-codegen-ignore create mode 100644 core/rpc/http/tx/.swagger-codegen/VERSION create mode 100644 core/rpc/http/tx/.travis.yml create mode 100644 core/rpc/http/tx/README.md create mode 100644 core/rpc/http/tx/api/swagger.yaml create mode 100644 core/rpc/http/tx/api_tx_service.go create mode 100644 core/rpc/http/tx/client.go create mode 100644 core/rpc/http/tx/configuration.go create mode 100644 core/rpc/http/tx/docs/ExtensionsExtensionConfig.md create mode 100644 core/rpc/http/tx/docs/RpcStatus.md create mode 100644 core/rpc/http/tx/docs/TxAccount.md create mode 100644 core/rpc/http/tx/docs/TxAccountStatus.md create mode 100644 core/rpc/http/tx/docs/TxAction.md create mode 100644 core/rpc/http/tx/docs/TxAttribute.md create mode 100644 core/rpc/http/tx/docs/TxBroadcastRequest.md create mode 100644 core/rpc/http/tx/docs/TxBroadcastResponse.md create mode 100644 core/rpc/http/tx/docs/TxCallRequest.md create mode 100644 core/rpc/http/tx/docs/TxCallRequestBody.md create mode 100644 core/rpc/http/tx/docs/TxCallResponse.md create mode 100644 core/rpc/http/tx/docs/TxChainInfoResponse.md create mode 100644 core/rpc/http/tx/docs/TxColumn.md create mode 100644 core/rpc/http/tx/docs/TxEstimatePriceRequest.md create mode 100644 core/rpc/http/tx/docs/TxEstimatePriceResponse.md create mode 100644 core/rpc/http/tx/docs/TxExtensions.md create mode 100644 core/rpc/http/tx/docs/TxForeignKey.md create mode 100644 core/rpc/http/tx/docs/TxForeignKeyAction.md create mode 100644 core/rpc/http/tx/docs/TxGetAccountResponse.md create mode 100644 core/rpc/http/tx/docs/TxGetConfigResponse.md create mode 100644 core/rpc/http/tx/docs/TxGetSchemaResponse.md create mode 100644 core/rpc/http/tx/docs/TxIndex.md create mode 100644 core/rpc/http/tx/docs/TxListDatabasesResponse.md create mode 100644 core/rpc/http/tx/docs/TxNodeInfoResponse.md create mode 100644 core/rpc/http/tx/docs/TxPingResponse.md create mode 100644 core/rpc/http/tx/docs/TxQueryRequest.md create mode 100644 core/rpc/http/tx/docs/TxQueryResponse.md create mode 100644 core/rpc/http/tx/docs/TxSchema.md create mode 100644 core/rpc/http/tx/docs/TxServiceApi.md create mode 100644 core/rpc/http/tx/docs/TxSignature.md create mode 100644 core/rpc/http/tx/docs/TxTable.md create mode 100644 core/rpc/http/tx/docs/TxTransaction.md create mode 100644 core/rpc/http/tx/docs/TxTransactionBody.md create mode 100644 core/rpc/http/tx/docs/TxTransactionResult.md create mode 100644 core/rpc/http/tx/docs/TxTxQueryRequest.md create mode 100644 core/rpc/http/tx/docs/TxTxQueryResponse.md create mode 100644 core/rpc/http/tx/git_push.sh create mode 100644 core/rpc/http/tx/model_extensions_extension_config.go create mode 100644 core/rpc/http/tx/model_rpc_status.go create mode 100644 core/rpc/http/tx/model_tx_account.go create mode 100644 core/rpc/http/tx/model_tx_account_status.go create mode 100644 core/rpc/http/tx/model_tx_action.go create mode 100644 core/rpc/http/tx/model_tx_attribute.go create mode 100644 core/rpc/http/tx/model_tx_broadcast_request.go create mode 100644 core/rpc/http/tx/model_tx_broadcast_response.go create mode 100644 core/rpc/http/tx/model_tx_call_request.go create mode 100644 core/rpc/http/tx/model_tx_call_request_body.go create mode 100644 core/rpc/http/tx/model_tx_call_response.go create mode 100644 core/rpc/http/tx/model_tx_chain_info_response.go create mode 100644 core/rpc/http/tx/model_tx_column.go create mode 100644 core/rpc/http/tx/model_tx_estimate_price_request.go create mode 100644 core/rpc/http/tx/model_tx_estimate_price_response.go create mode 100644 core/rpc/http/tx/model_tx_extensions.go create mode 100644 core/rpc/http/tx/model_tx_foreign_key.go create mode 100644 core/rpc/http/tx/model_tx_foreign_key_action.go create mode 100644 core/rpc/http/tx/model_tx_get_account_response.go create mode 100644 core/rpc/http/tx/model_tx_get_config_response.go create mode 100644 core/rpc/http/tx/model_tx_get_schema_response.go create mode 100644 core/rpc/http/tx/model_tx_index.go create mode 100644 core/rpc/http/tx/model_tx_list_databases_response.go create mode 100644 core/rpc/http/tx/model_tx_node_info_response.go create mode 100644 core/rpc/http/tx/model_tx_ping_response.go create mode 100644 core/rpc/http/tx/model_tx_query_request.go create mode 100644 core/rpc/http/tx/model_tx_query_response.go create mode 100644 core/rpc/http/tx/model_tx_schema.go create mode 100644 core/rpc/http/tx/model_tx_signature.go create mode 100644 core/rpc/http/tx/model_tx_table.go create mode 100644 core/rpc/http/tx/model_tx_transaction.go create mode 100644 core/rpc/http/tx/model_tx_transaction_body.go create mode 100644 core/rpc/http/tx/model_tx_transaction_result.go create mode 100644 core/rpc/http/tx/model_tx_tx_query_request.go create mode 100644 core/rpc/http/tx/model_tx_tx_query_response.go create mode 100644 core/rpc/http/tx/response.go create mode 100644 core/rpc/protobuf/function/v0/messages.pb.go create mode 100644 core/rpc/protobuf/function/v0/service.pb.go create mode 100644 core/rpc/protobuf/function/v0/service_grpc.pb.go create mode 100644 core/rpc/protobuf/tx/v1/info.pb.go create mode 100644 core/types/gateway/gateway.go create mode 100644 core/utils/url/errors.go create mode 100644 core/utils/url/url.go create mode 100644 core/utils/url/url_test.go delete mode 100644 internal/admin/admin.go delete mode 100644 internal/admin/opts.go delete mode 100644 internal/admin/tls.go rename internal/services/grpc/{txsvc/v1/sig_verify.go => function/v0/service.go} (51%) delete mode 100644 internal/services/grpc/txsvc/v1/validator.go create mode 100644 internal/services/http/api/function/v0.swagger.json rename internal/services/http/api/{ => tx}/v1.swagger.json (71%) create mode 100644 scripts/swagger/check_up create mode 100644 test/driver/operator/cli_driver.go create mode 100644 test/driver/operator/operator.go create mode 100644 test/specifications/info.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 903060988..f1441eb1f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,6 +26,9 @@ jobs: version: '23.4' repo-token: ${{ secrets.KWIL_MACH_SECRET }} +# - name: Install swagger-codegen +# uses: swagger-api/swagger-codegen/.github/actions/generate/action.yml@main + - name: Install Taskfile uses: arduino/setup-task@v1 with: @@ -53,6 +56,12 @@ jobs: run: | ./scripts/proto/check_up + - name: Ensure generated swagger Go code is up-to-date + # This script gets a permissions error. I cannot figure out why, @yaiba do you know? The others don't. + run: | + chmod +x ./scripts/swagger/check_up + ./scripts/swagger/check_up + - name: Compile packages, apps, and specs run: | # enter workspace mode to do this on one line go work init && go work use . ./parse ./test ./core diff --git a/.gitignore b/.gitignore index 115c08e7c..be49fdaa6 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ deployments/helm/*/charts/ dist/* +# tools +swagger-codegen-cli.jar + # kwild .testnet diff --git a/.golangci.yml b/.golangci.yml index 275b31bda..42d61f4bf 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,8 @@ run: deadline: 10m + skip-dirs: + - core/rpc/protobuf + - core/rpc/http output: format: github-actions,colored-line-number diff --git a/Taskfile-pb.yml b/Taskfile-pb.yml index 0c05e079c..b8f867b37 100644 --- a/Taskfile-pb.yml +++ b/Taskfile-pb.yml @@ -3,32 +3,14 @@ version: '3' tasks: compile: cmds: - - task: compile:v1 + - task: tx:v1 + - task: tx:v1:swagger - task: admin:v0 +# - task: function:v0 +# - task: function:v0:swagger - # compile:v0: - # desc: Compiles v0 protobuf - # internal: true - # deps: [update] - # preconditions: - # - sh: a="libprotoc 23.4";b=`protoc --version`;test "$a" = "$b" - # msg: "Protobuf compiler version is not 23.4, please install the correct version" - # cmds: - # - | - # protoc -I ./proto \ - # --go_out=. --go_opt module=kwil \ - # --go-grpc_out=. --go-grpc_opt module=kwil \ - # --grpc-gateway_out=. --grpc-gateway_opt module=kwil --grpc-gateway_opt generate_unbound_methods=true \ - # --openapiv2_out=. --openapiv2_opt allow_merge=true --openapiv2_opt merge_file_name=api/openapi-spec/api/v0/api \ - # proto/kwil/*/v0/*.proto - # sources: - # - proto/kwil/*/v0/*.proto - # generates: - # - api/protobuf/*/v0/*.go - # - api/openapi-spec/api/v0/api.swagger.json - - compile:v1: - desc: Compiles v1 protobuf + tx:v1: + desc: Compiles TxService v1 protobuf preconditions: - sh: a="libprotoc 23.4";b=`protoc --version`;test "$a" = "$b" msg: "Protobuf compiler version is not 23.4, please install the correct version" @@ -39,14 +21,25 @@ tasks: --go-grpc_out=. --go-grpc_opt module=github.com/kwilteam/kwil-db \ --grpc-gateway_out=. --grpc-gateway_opt module=github.com/kwilteam/kwil-db \ --grpc-gateway_opt generate_unbound_methods=true \ - --openapiv2_out=internal/services/http/api --openapiv2_opt allow_merge=true \ - --openapiv2_opt merge_file_name=v1 \ - proto/kwil/*/v1/*.proto + --openapiv2_out=internal/services/http/api/tx \ + --openapiv2_opt allow_merge=true --openapiv2_opt merge_file_name=v1 \ + proto/kwil/tx/v1/*.proto + sources: + - proto/kwil/tx/v1/*.proto + generates: + - core/rpc/protobuf/tx/v1/*.go + - internal/services/http/api/tx/v1.swagger.json + + tx:v1:swagger: # more general for all platforms + desc: Generates swagger codegen for TxService v1 + cmds: + # if swagger-codegen-cli.jar does not exist, download it + - test -f swagger-codegen-cli.jar || wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.51/swagger-codegen-cli-3.0.51.jar -O swagger-codegen-cli.jar + - java -jar swagger-codegen-cli.jar generate -i internal/services/http/api/tx/v1.swagger.json -l go -o core/rpc/http/tx sources: - - proto/kwil/*/v1/*.proto + - internal/services/http/api/tx/v1.swagger.json generates: - - core/rpc/protobuf/*/v1/*.go - - internal/services/http/api/v1.swagger.json + - core/rpc/http/tx/* admin:v0: desc: Compiles admin v0 protobuf @@ -63,3 +56,37 @@ tasks: - proto/kwil/admin/v0/*.proto generates: - core/rpc/protobuf/admin/v0/*.go + + function:v0: + desc: Compiles functions v0 protobuf + preconditions: + - sh: a="libprotoc 23.4";b=`protoc --version`;test "$a" = "$b" + msg: "Protobuf compiler version is not 23.4, please install the correct version" + cmds: + - | + protoc -I ./proto \ + --go_out=. --go_opt module=github.com/kwilteam/kwil-db \ + --go-grpc_out=. --go-grpc_opt module=github.com/kwilteam/kwil-db \ + --openapiv2_out=internal/services/http/api/function \ + --openapiv2_opt allow_merge=true --openapiv2_opt merge_file_name=v0 \ + proto/kwil/function/v0/*.proto + sources: + - proto/kwil/function/v0/*.proto + generates: + - core/rpc/protobuf/function/v0/*.go + - internal/services/http/api/function/v0.swagger.json +# - internal/services/http/api/function/v0.swagger.json +# put in cmds +# --openapiv2_out=internal/services/http/api/function \ +# --openapiv2_opt allow_merge=true --openapiv2_opt merge_file_name=v1 \ + + function:v0:swagger: # more general for all platforms + desc: Generates swagger codegen for TxService v1 + cmds: + # if swagger-codegen-cli.jar does not exist, download it + - test -f swagger-codegen-cli.jar || wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.51/swagger-codegen-cli-3.0.51.jar -O swagger-codegen-cli.jar + - java -jar swagger-codegen-cli.jar generate -i internal/services/http/api/function/v0.swagger.json -l go -o core/rpc/http/function + sources: + - internal/services/http/api/function/v0.swagger.json + generates: + - core/rpc/http/function/* \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml index 6f2d9dd50..098ae1b0e 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -63,7 +63,8 @@ tasks: lint: desc: Lint with golangci-lint cmds: - - golangci-lint run ./... ./core/... ./test/... ./parse/... -c .golangci.yml --skip-dirs ./core/rpc/protobuf + # skip-dirs only works in .yaml + - golangci-lint run ./... ./core/... ./test/... ./parse/... -c .golangci.yml linter: desc: Install the linter (not for CI which has an action for this) @@ -98,6 +99,12 @@ tasks: generates: - .build/kwild + generate:docs: + desc: Generate docs for CLIs + cmds: + - go run ./cmd/kwil-cli/generate -out ./gen + - go run ./cmd/kwil-admin/generate -out ./gen + # ************ docker ************ vendor: desc: Generate vendor diff --git a/build/package/docker/kwild.dockerfile b/build/package/docker/kwild.dockerfile index 1ecb636a5..88a9172c2 100644 --- a/build/package/docker/kwild.dockerfile +++ b/build/package/docker/kwild.dockerfile @@ -12,11 +12,13 @@ COPY . . RUN test -f go.work && rm go.work || true RUN GOWORK=off GIT_VERSION=$version GIT_COMMIT=$git_commit BUILD_TIME=$build_time CGO_ENABLED=0 TARGET="/app/dist" GO_BUILDTAGS=$go_build_tags ./scripts/build/binary kwild -RUN chmod +x /app/dist/kwild-* +RUN GIT_VERSION=$version GIT_COMMIT=$git_commit BUILD_TIME=$build_time CGO_ENABLED=0 TARGET="/app/dist" ./scripts/build/binary kwil-admin +RUN chmod +x /app/dist/kwild-* /app/dist/kwil-admin-* -FROM scratch AS assemble +FROM alpine:3.17 WORKDIR /app COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=build /app/dist/kwild-* ./kwild +COPY --from=build /app/dist/kwil-admin-* ./kwil-admin EXPOSE 50051 50151 8080 26656 26657 ENTRYPOINT ["/app/kwild"] diff --git a/build/package/docker/kwild.shell.dockerfile b/build/package/docker/kwild.shell.dockerfile deleted file mode 100644 index 666849454..000000000 --- a/build/package/docker/kwild.shell.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM golang:alpine AS stage - -ARG version -ARG build_time -ARG git_commit -ARG go_build_tags - -WORKDIR /app -RUN apk update && apk add git ca-certificates-bundle - -COPY . . -RUN test -f go.work && rm go.work || true - -RUN GOWORK=off GIT_VERSION=$version GIT_COMMIT=$git_commit BUILD_TIME=$build_time CGO_ENABLED=0 TARGET="/app/dist" GO_BUILDTAGS=$go_build_tags ./scripts/build/binary kwild -RUN GOWORK=off GIT_VERSION=$version GIT_COMMIT=$git_commit BUILD_TIME=$build_time CGO_ENABLED=0 TARGET="/app/dist" ./scripts/build/binary kwil-admin -RUN chmod +x /app/dist/kwild-* /app/dist/kwil-admin-* - -FROM alpine:3.17 -WORKDIR /app -COPY --from=stage /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=stage /app/dist/kwild-* ./kwild -COPY --from=stage /app/dist/kwil-admin-* ./kwil-admin -EXPOSE 50051 50151 8080 26656 26657 -ENTRYPOINT ["/app/kwild"] diff --git a/cmd/common/display/format.go b/cmd/common/display/format.go new file mode 100644 index 000000000..a0fee10df --- /dev/null +++ b/cmd/common/display/format.go @@ -0,0 +1,202 @@ +// Package display provides interfaces and functions to format the command +// line output and print. +package display + +import ( + "encoding" + "encoding/json" + "fmt" + "io" + "os" + + "github.com/spf13/cobra" +) + +// BindOutputFormatFlag binds the output format flag to the command. +// This should be added on the root command. +func BindOutputFormatFlag(cmd *cobra.Command) { + cmd.PersistentFlags().String("output", defaultOutputFormat.string(), "the format for command output - either `text` or `json`") +} + +// BindSilenceFlag binds the silence flag to the passed command. +// If bound, the command will silence logs. +// If true, display commands will not print to stdout or stderr. +// The flag will be bound to all subcommands of the given command. +func BindSilenceFlag(cmd *cobra.Command) { + cmd.PersistentFlags().BoolP("silence", "S", false, "Silence logs") +} + +// ShouldSilence returns the value of the silence flag +func ShouldSilence(cmd *cobra.Command) bool { + s, _ := cmd.Flags().GetBool("silence") + return s +} + +// OutputFormat is the format for command output +// It implements the pflag.Value interface +type OutputFormat string + +// String implements the Stringer interface +// NOTE: cannot use the pointer receiver here +func (o OutputFormat) string() string { + return string(o) +} + +// Valid returns true if the output format is valid. +func (o OutputFormat) valid() bool { + switch o { + case outputFormatText, outputFormatJSON: + return true + default: + return false + } +} + +const ( + outputFormatText OutputFormat = "text" + outputFormatJSON OutputFormat = "json" + + defaultOutputFormat = outputFormatText +) + +// emptyResult is used as a placeholder for when the result is empty. +// It implements the MsgFormatter interface +type emptyResult struct{} + +func (e *emptyResult) MarshalText() ([]byte, error) { + return []byte(""), nil +} + +func (e *emptyResult) MarshalJSON() ([]byte, error) { + return []byte(`""`), nil +} + +// MsgFormatter is an interface that wraps the MarshalText and MarshalJSON +// It defines the requirements for something to be printed. +type MsgFormatter interface { + json.Marshaler + encoding.TextMarshaler +} + +type wrappedMsg struct { + Result MsgFormatter `json:"result"` + Error string `json:"error"` +} + +// printJson prints the wrappedMsg in json format. It prints to stdout. +func (w *wrappedMsg) printJson(stdout io.Writer, _ io.Writer) error { + msg, err := json.MarshalIndent(w, "", " ") + if err != nil { + return err + } + + fmt.Fprintln(stdout, string(msg)) + return nil +} + +// printText prints the wrappedMsg in text format. It prints to stdout if +// `w.Error` is empty, otherwise it prints to stderr. +func (w *wrappedMsg) printText(stdout io.Writer, stderr io.Writer) error { + if w.Error != "" { + fmt.Fprintln(stderr, w.Error) + return nil + } + + msg, err := w.Result.MarshalText() + if err != nil { + return err + } + + fmt.Fprintln(stdout, string(msg)) + return nil +} + +// wrapMsg wraps response and error in a wrappedMsg struct. +func wrapMsg(msg MsgFormatter, err error) *wrappedMsg { + if err != nil { + return &wrappedMsg{ + Result: &emptyResult{}, + Error: err.Error(), + } + } + + return &wrappedMsg{ + Result: msg, + Error: "", + } +} + +func prettyPrint(msg *wrappedMsg, format OutputFormat, stdout io.Writer, stderr io.Writer) error { + switch format { + case outputFormatJSON: + return msg.printJson(stdout, stderr) + case outputFormatText: + return msg.printText(stdout, stderr) + default: + return fmt.Errorf("invalid output format: %s", format) + } +} + +// Print is a helper function to wrap and print message in given format. +func Print(msg MsgFormatter, err error, format OutputFormat) error { + wrappedMsg := wrapMsg(msg, err) + return prettyPrint(wrappedMsg, format, os.Stdout, os.Stderr) +} + +// PrintCmd prints output based on the commands output format flag. +// If not format flag is provided, it will default to text in stdout. +func PrintCmd(cmd *cobra.Command, msg MsgFormatter) error { + if ShouldSilence(cmd) { + return nil + } + + wrappedMsg := &wrappedMsg{ + Result: msg, + Error: "", + } + + format, err := cmd.Flags().GetString("output") + if err != nil || format == "" { + format = defaultOutputFormat.string() + } + if !OutputFormat(format).valid() { + // set the output format in cmd to the default output format to avoid error being thrown twice + err := cmd.Flags().Set("output", defaultOutputFormat.string()) + if err != nil { + return err + } + + return fmt.Errorf("invalid output format: %s", format) + } + + return prettyPrint(wrappedMsg, OutputFormat(format), os.Stdout, os.Stderr) +} + +// PrintErr prints the error according to the commands output format flag. +func PrintErr(cmd *cobra.Command, err error) error { + if ShouldSilence(cmd) { + return nil + } + + outputFormat, err2 := getOutputFormat(cmd) + if err2 != nil { + return err2 + } + + return prettyPrint(&wrappedMsg{ + Result: &emptyResult{}, + Error: err.Error(), + }, outputFormat, os.Stdout, os.Stderr) +} + +func getOutputFormat(cmd *cobra.Command) (OutputFormat, error) { + format, err := cmd.Flags().GetString("output") + if err != nil || format == "" { + format = defaultOutputFormat.string() + } + if !OutputFormat(format).valid() { + return "", fmt.Errorf("invalid output format: %s", format) + } + + return OutputFormat(format), nil +} diff --git a/cmd/internal/display/format_test.go b/cmd/common/display/format_test.go similarity index 67% rename from cmd/internal/display/format_test.go rename to cmd/common/display/format_test.go index 73635912a..256fde20f 100644 --- a/cmd/internal/display/format_test.go +++ b/cmd/common/display/format_test.go @@ -1,4 +1,4 @@ -package display_test +package display import ( "bytes" @@ -8,7 +8,6 @@ import ( "os" "testing" - "github.com/kwilteam/kwil-db/cmd/internal/display" "github.com/stretchr/testify/assert" ) @@ -29,8 +28,8 @@ func (d *demoFormat) MarshalText() ([]byte, error) { } func Example_wrappedMsg_text() { - msg := display.WrapMsg(&demoFormat{data: []byte("demo")}, nil) - display.PrettyPrint(msg, "text", os.Stdout, os.Stderr) + msg := wrapMsg(&demoFormat{data: []byte("demo")}, nil) + prettyPrint(msg, "text", os.Stdout, os.Stderr) // Output: Whatever format: demo } @@ -39,8 +38,8 @@ func Test_wrappedMsg_text_withError(t *testing.T) { var stdout bytes.Buffer err := errors.New("an error") - msg := display.WrapMsg(&demoFormat{data: []byte("demo")}, err) - display.PrettyPrint(msg, "text", &stdout, &stderr) + msg := wrapMsg(&demoFormat{data: []byte("demo")}, err) + prettyPrint(msg, "text", &stdout, &stderr) output := stdout.Bytes() assert.Equal(t, "", string(output), "stdout should be empty") @@ -50,8 +49,8 @@ func Test_wrappedMsg_text_withError(t *testing.T) { } func Example_wrappedMsg_json() { - msg := display.WrapMsg(&demoFormat{data: []byte("demo")}, nil) - display.PrettyPrint(msg, "json", os.Stdout, os.Stderr) + msg := wrapMsg(&demoFormat{data: []byte("demo")}, nil) + prettyPrint(msg, "json", os.Stdout, os.Stderr) // Output: { // "result": { // "name_to_whatever": "demo_whatever" @@ -62,8 +61,8 @@ func Example_wrappedMsg_json() { func Example_wrappedMsg_json_withError() { err := errors.New("an error") - msg := display.WrapMsg(&demoFormat{data: []byte("demo")}, err) - display.PrettyPrint(msg, "json", os.Stdout, os.Stderr) + msg := wrapMsg(&demoFormat{data: []byte("demo")}, err) + prettyPrint(msg, "json", os.Stdout, os.Stderr) // Output: // { // "result": "", diff --git a/cmd/common/display/message.go b/cmd/common/display/message.go new file mode 100644 index 000000000..e80dca41e --- /dev/null +++ b/cmd/common/display/message.go @@ -0,0 +1,40 @@ +package display + +import ( + "encoding/hex" + "encoding/json" + "fmt" +) + +type TxHashResponse struct { + TxHash string `json:"tx_hash"` +} + +// RespTxHash is used to represent a transaction hash in cli +// NOTE: it's different from transactions.TxHash, this is for display purpose. +// It implements the MsgFormatter interface +type RespTxHash []byte + +func (h RespTxHash) Hex() string { + return hex.EncodeToString(h) +} + +func (h RespTxHash) MarshalJSON() ([]byte, error) { + return json.Marshal(TxHashResponse{TxHash: h.Hex()}) +} + +func (h RespTxHash) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("TxHash: %s", h.Hex())), nil +} + +// RespString is used to represent a string in cli +// It implements the MsgFormatter interface +type RespString string + +func (s RespString) MarshalJSON() ([]byte, error) { + return json.Marshal(string(s)) // must convert to string to avoid infinite recursion +} + +func (s RespString) MarshalText() ([]byte, error) { + return []byte(s), nil +} diff --git a/cmd/internal/display/message_test.go b/cmd/common/display/message_test.go similarity index 72% rename from cmd/internal/display/message_test.go rename to cmd/common/display/message_test.go index cd852c735..75ab91e98 100644 --- a/cmd/internal/display/message_test.go +++ b/cmd/common/display/message_test.go @@ -1,4 +1,4 @@ -package display_test +package display import ( "bytes" @@ -7,14 +7,13 @@ import ( "os" "testing" - "github.com/kwilteam/kwil-db/cmd/internal/display" "github.com/stretchr/testify/assert" ) // NOTE: could do this for all the other tests, // but using Example* is more handy and obvious func Test_RespTxHash(t *testing.T) { - resp := display.RespTxHash("1024") + resp := RespTxHash("1024") expectJson := `{"tx_hash":"31303234"}` expectText := `TxHash: 31303234` @@ -28,8 +27,8 @@ func Test_RespTxHash(t *testing.T) { } func ExampleRespTxHash_text() { - msg := display.WrapMsg(display.RespTxHash("1024"), nil) - display.PrettyPrint(msg, "text", os.Stdout, os.Stderr) + msg := wrapMsg(RespTxHash("1024"), nil) + prettyPrint(msg, "text", os.Stdout, os.Stderr) // Output: // TxHash: 31303234 } @@ -39,8 +38,8 @@ func TestRespTxHash_text_withError(t *testing.T) { var stdout bytes.Buffer err := errors.New("an error") - msg := display.WrapMsg(display.RespTxHash("1024"), err) - display.PrettyPrint(msg, "text", &stdout, &stderr) + msg := wrapMsg(RespTxHash("1024"), err) + prettyPrint(msg, "text", &stdout, &stderr) output, err := io.ReadAll(&stdout) assert.NoError(t, err, "ReadAll should not return error") @@ -52,8 +51,8 @@ func TestRespTxHash_text_withError(t *testing.T) { } func ExampleRespTxHash_json() { - msg := display.WrapMsg(display.RespTxHash("1024"), nil) - display.PrettyPrint(msg, "json", os.Stdout, os.Stderr) + msg := wrapMsg(RespTxHash("1024"), nil) + prettyPrint(msg, "json", os.Stdout, os.Stderr) // Output: // { // "result": { @@ -65,8 +64,8 @@ func ExampleRespTxHash_json() { func ExampleRespTxHash_json_withError() { err := errors.New("an error") - msg := display.WrapMsg(display.RespTxHash("1024"), err) - display.PrettyPrint(msg, "json", os.Stdout, os.Stderr) + msg := wrapMsg(RespTxHash("1024"), err) + prettyPrint(msg, "json", os.Stdout, os.Stderr) // Output: // { // "result": "", diff --git a/cmd/common/generate/cobra.go b/cmd/common/generate/cobra.go new file mode 100644 index 000000000..05e062569 --- /dev/null +++ b/cmd/common/generate/cobra.go @@ -0,0 +1,126 @@ +// Copyright 2013-2023 The Cobra Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package generate + +// this code is copied from github.com/spf13/cobra/doc +// it has slight modifications for Kwil's codebase + +import ( + "bytes" + "fmt" + "io" + "sort" + "strings" + + "github.com/spf13/cobra" +) + +func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { + flags := cmd.NonInheritedFlags() + flags.SetOutput(buf) + if flags.HasAvailableFlags() { + buf.WriteString("### Options\n\n```\n") + flags.PrintDefaults() + buf.WriteString("```\n\n") + } + + parentFlags := cmd.InheritedFlags() + parentFlags.SetOutput(buf) + if parentFlags.HasAvailableFlags() { + buf.WriteString("### Options inherited from parent commands\n\n```\n") + parentFlags.PrintDefaults() + buf.WriteString("```\n\n") + } + return nil +} + +// genMarkdownCustom creates custom markdown output. +func genMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { + cmd.InitDefaultHelpCmd() + cmd.InitDefaultHelpFlag() + + buf := new(bytes.Buffer) + name := cmd.CommandPath() + + if len(cmd.Long) > 0 { + buf.WriteString(cmd.Long + "\n\n") + } + + if cmd.Runnable() { + buf.WriteString("### Usage\n\n") + buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine())) + } + + if len(cmd.Example) > 0 { + buf.WriteString("### Example\n\n") + buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example)) + } + + if err := printOptions(buf, cmd, name); err != nil { + return err + } + if hasSeeAlso(cmd) { + buf.WriteString("### Subqueries\n\n") + // if cmd.HasParent() { + // parent := cmd.Parent() + // pname := parent.CommandPath() + // link := pname + ".md" + // link = strings.ReplaceAll(link, " ", "_") + // buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short)) + // cmd.VisitParents(func(c *cobra.Command) { + // if c.DisableAutoGenTag { + // cmd.DisableAutoGenTag = c.DisableAutoGenTag + // } + // }) + // } + + children := cmd.Commands() + sort.Sort(byName(children)) + + for _, child := range children { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { + continue + } + cname := name + " " + child.Name() + link := cname + ".md" + link = strings.ReplaceAll(link, " ", "_") + buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short)) + } + buf.WriteString("\n") + } + _, err := buf.WriteTo(w) + return err +} + +// Test to see if we have a reason to print See Also information in docs +// Basically this is a test for a parent command or a subcommand which is +// both not deprecated and not the autogenerated help command. +func hasSeeAlso(cmd *cobra.Command) bool { + // if cmd.HasParent() { + // return true + // } + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { + continue + } + return true + } + return false +} + +type byName []*cobra.Command + +func (s byName) Len() int { return len(s) } +func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } diff --git a/cmd/common/generate/generate.go b/cmd/common/generate/generate.go new file mode 100644 index 000000000..e960b18b4 --- /dev/null +++ b/cmd/common/generate/generate.go @@ -0,0 +1,160 @@ +package generate + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/spf13/cobra" +) + +type writeFunc func(string) (*os.File, error) + +func WriteDocs(cmd *cobra.Command, dir string) error { + return writeCmd(cmd, ".", 0, func(s string) (*os.File, error) { + fullPath := filepath.Join(dir, s) + err := os.MkdirAll(filepath.Dir(fullPath), 0755) + if err != nil { + return nil, err + } + + return os.Create(fullPath) + }) +} + +func writeCmd(cmd *cobra.Command, dir string, idx int, write writeFunc) error { + subCommands := cmd.Commands() + if len(subCommands) == 0 { + return createCmdFile(cmd, dir, idx, write) + } + + err := createIndexFile(cmd, dir, write) + if err != nil { + return err + } + + subDir := dir + "/" + cmd.Name() + for i, subCmd := range subCommands { + err := writeCmd(subCmd, subDir, i+1, write) + if err != nil { + return err + } + } + + return nil +} + +// createIndexFile creates a file for a command that has subcommands. +func createIndexFile(cmd *cobra.Command, dir string, write writeFunc) error { + dir = dir + "/" + cmd.Name() + + header := docusaursHeader{ + sidebar_position: 0, + sidebar_label: cmd.Name(), + id: strings.ReplaceAll(cmd.CommandPath(), " ", "-"), + title: cmd.CommandPath(), + description: cmd.Short, + } + + file, err := write(dir + "/index.md") + if err != nil { + return err + } + + file.WriteString(header.String() + "\n\n") + + err = genMarkdownCustom(cmd, file, linkHandler(dir)) + if err != nil { + return err + } + + return nil +} + +// createCmdFile creates a file for the command, and writes the command's documentation to it. +// it does not call subcommands. +func createCmdFile(cmd *cobra.Command, dir string, idx int, write writeFunc) error { + file, err := write(dir + "/" + cmd.Name() + ".mdx") + if err != nil { + return err + } + + header := docusaursHeader{ + sidebar_position: idx, + sidebar_label: cmd.Name(), + id: strings.ReplaceAll(cmd.CommandPath(), " ", "-"), + title: cmd.CommandPath(), + description: cmd.Short, + } + + file.WriteString(header.String() + "\n\n") + + err = genMarkdownCustom(cmd, file, linkHandler(dir)) + if err != nil { + return err + } + + return nil +} + +// linkHandler creates the relative file path for links +// the value passed to the return func (the link) is passed as root-cmd_sub-cmd_sub-sub-cmd +// dir is passed as ./root-cmd/sub-cmd/sub-sub-cmd +// if the link is shorter than the dir, such as root-cmd_sub-cmd and dir is root-cmd/sub-cmd/sub-sub-cmd +// then the result should be ../ (since it is relative to the current directory) +// If the link is longer than the dir, such as root-cmd_sub-cmd_sub-sub-cmd and dir is root-cmd/sub-cmd +// then the result should be ./sub-sub-cmd +// If the link is the same as the dir, such as root-cmd_sub-cmd_sub-sub-cmd and dir is root-cmd/sub-cmd/sub-sub-cmd +// then the result should be . +func linkHandler(dir string) func(string) string { + return func(s string) string { + s = strings.Trim(s, ".md") + s = strings.ReplaceAll(s, "_", "/") + + currentDir := strings.Split(dir, "/") + linkDir := strings.Split(s, "/") + + if len(currentDir) > 0 && currentDir[0] == "." { + currentDir = currentDir[1:] + } + + // if the link is shorter than the dir, such as root-cmd_sub-cmd and dir is root-cmd/sub-cmd/sub-sub-cmd + // then the result should be ../ (since it is relative to the current directory) + if len(linkDir) < len(currentDir) { + return strings.Repeat("../", len(currentDir)-len(linkDir)) + } + + // If the link is longer than the dir, such as root-cmd_sub-cmd_sub-sub-cmd and dir is root-cmd/sub-cmd + // then the result should be ./sub-sub-cmd/ + if len(linkDir) > len(currentDir) { + return "./" + strings.Join(linkDir[len(currentDir):], "/") + } + + // If the link is the same as the dir, such as root-cmd_sub-cmd_sub-sub-cmd and dir is root-cmd/sub-cmd/sub-sub-cmd + // then the result should be . + return "." + } +} + +// docusaurusHeader is a page header for a doc page in a docusaurus site. +type docusaursHeader struct { + sidebar_position int + sidebar_label string + id string + title string + description string +} + +// String returns the header as a string. +func (d *docusaursHeader) String() string { + return fmt.Sprintf(headerString, d.sidebar_position, d.sidebar_label, d.id, d.title, d.description) +} + +var headerString = `--- +sidebar_position: %d +sidebar_label: "%s" +id: "%s" +title: "%s" +description: "%s" +---` diff --git a/cmd/common/generate/generate_test.go b/cmd/common/generate/generate_test.go new file mode 100644 index 000000000..b7f87d436 --- /dev/null +++ b/cmd/common/generate/generate_test.go @@ -0,0 +1,43 @@ +package generate + +import "testing" + +func Test_Links(t *testing.T) { + type testcase struct { + currentDir string + link string + expected string + } + + testcases := []testcase{ + { + currentDir: "cli/cmd1/cmd2", + link: "cli_cmd1_cmd2", + expected: ".", + }, + { + currentDir: "cli/cmd1/cmd2", + link: "cli_cmd1_cmd2_cmd3", + expected: "./cmd3", + }, + { + currentDir: "cli/cmd1/cmd2", + link: "cli_cmd1", + expected: "../", + }, + { + currentDir: "./kwil-cli/utils", + link: "kwil-cli_utils_query-tx.md", + expected: "./query-tx", + }, + } + + for _, tc := range testcases { + t.Run(tc.currentDir+"_"+tc.link, func(t *testing.T) { + link := linkHandler(tc.currentDir)(tc.link) + if link != tc.expected { + t.Errorf("expected %s, got %s", tc.expected, link) + } + }) + } +} diff --git a/cmd/kwil-cli/cmds/system/version.go b/cmd/common/version/version.go similarity index 88% rename from cmd/kwil-cli/cmds/system/version.go rename to cmd/common/version/version.go index c537804dc..0afacbca7 100644 --- a/cmd/kwil-cli/cmds/system/version.go +++ b/cmd/common/version/version.go @@ -1,4 +1,4 @@ -package system +package version import ( "bytes" @@ -9,8 +9,7 @@ import ( "text/template" "time" - "github.com/kwilteam/kwil-db/cmd/internal/display" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/internal/version" "github.com/spf13/cobra" "github.com/tonistiigi/go-rosetta" @@ -69,15 +68,15 @@ func (v *respVersionInfo) MarshalText() ([]byte, error) { func NewVersionCmd() *cobra.Command { var cmd = &cobra.Command{ - Use: "version [OPTIONS]", - Short: "Show the kwil-cli version information", + Use: "version", + Short: "Displays the cli version information.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { resp := &respVersionInfo{ Info: &versionInfo{ Version: version.KwilVersion, - APIVersion: "", GitCommit: version.Build.Revision, + APIVersion: "", GoVersion: runtime.Version(), Os: runtime.GOOS, Arch: arch(), @@ -85,7 +84,7 @@ func NewVersionCmd() *cobra.Command { }, } - return display.Print(resp, nil, config.GetOutputFormat()) + return display.Print(resp, nil, "text") }, } diff --git a/cmd/kwil-cli/cmds/system/version_test.go b/cmd/common/version/version_test.go similarity index 94% rename from cmd/kwil-cli/cmds/system/version_test.go rename to cmd/common/version/version_test.go index abff92cd3..c0d1a7077 100644 --- a/cmd/kwil-cli/cmds/system/version_test.go +++ b/cmd/common/version/version_test.go @@ -1,7 +1,7 @@ -package system +package version import ( - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" ) func Example_versionInfo_text() { diff --git a/cmd/internal/display/format.go b/cmd/internal/display/format.go deleted file mode 100644 index 18a68e250..000000000 --- a/cmd/internal/display/format.go +++ /dev/null @@ -1,98 +0,0 @@ -// Package display provides interfaces and functions to format the command -// line output and print. -package display - -import ( - "encoding" - "encoding/json" - "fmt" - "io" - "os" - - "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" -) - -// emptyResult is used as a placeholder for when the result is empty. -type emptyResult struct{} - -func (e *emptyResult) MarshalText() ([]byte, error) { - return []byte(""), nil -} - -func (e *emptyResult) MarshalJSON() ([]byte, error) { - return []byte(`""`), nil -} - -type msgFormatter interface { - json.Marshaler - encoding.TextMarshaler -} - -type msgPrinter interface { - printJson(stdout io.Writer, stderr io.Writer) error - printText(stdout io.Writer, stderr io.Writer) error -} - -type wrappedMsg struct { - Result msgFormatter `json:"result"` - Error string `json:"error"` -} - -// printJson prints the wrappedMsg in json format. It prints to stdout. -func (w *wrappedMsg) printJson(stdout io.Writer, _ io.Writer) error { - msg, err := json.MarshalIndent(w, "", " ") - if err != nil { - return err - } - - fmt.Fprintln(stdout, string(msg)) - return nil -} - -// printText prints the wrappedMsg in text format. It prints to stdout if -// `w.Error` is empty, otherwise it prints to stderr. -func (w *wrappedMsg) printText(stdout io.Writer, stderr io.Writer) error { - if w.Error != "" { - fmt.Fprintln(stderr, w.Error) - return nil - } - - msg, err := w.Result.MarshalText() - if err != nil { - return err - } - - fmt.Fprintln(stdout, string(msg)) - return nil -} - -// WrapMsg wraps response and error in a wrappedMsg struct. -func WrapMsg(msg msgFormatter, err error) *wrappedMsg { - if err != nil { - return &wrappedMsg{ - Result: &emptyResult{}, - Error: err.Error(), - } - } - - return &wrappedMsg{ - Result: msg, - Error: "", - } -} - -func PrettyPrint(pt msgPrinter, format string, stdout io.Writer, stderr io.Writer) error { - switch format { - case config.OutputFormatJSON.String(): - return pt.printJson(stdout, stderr) - default: - return pt.printText(stdout, stderr) - - } -} - -// Print is a helper function to wrap and print message in given format. -func Print(msg msgFormatter, err error, format string) error { - wrappedMsg := WrapMsg(msg, err) - return PrettyPrint(wrappedMsg, format, os.Stdout, os.Stderr) -} diff --git a/cmd/internal/display/message.go b/cmd/internal/display/message.go deleted file mode 100644 index 8053a2233..000000000 --- a/cmd/internal/display/message.go +++ /dev/null @@ -1,27 +0,0 @@ -package display - -import ( - "encoding/hex" - "encoding/json" - "fmt" -) - -// RespTxHash is used to represent a transaction hash in cli -// NOTE: it's different from transactions.TxHash, this is for display purpose. -type RespTxHash []byte - -func (h RespTxHash) Hex() string { - return hex.EncodeToString(h) -} - -func (h RespTxHash) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - TxHash string `json:"tx_hash"` - }{ - TxHash: h.Hex(), - }) -} - -func (h RespTxHash) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("TxHash: %s", h.Hex())), nil -} diff --git a/cmd/kwil-admin/args.go b/cmd/kwil-admin/args.go deleted file mode 100644 index 70b91f60e..000000000 --- a/cmd/kwil-admin/args.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "encoding" - "encoding/hex" -) - -// These types are defined to provide custom parsing logic to go-arg, which -// recognizes and uses the encoding.TextUnmarshaler interface to process -// arguments and flags. - -// HexArg is used to decode hexadecimal text into a byte slice. -type HexArg []byte - -// UnmarshalText satisfies the encoding.TextUnmarshaler interface. -func (ka *HexArg) UnmarshalText(b []byte) error { - key, err := hex.DecodeString(string(b)) - if err != nil { - return err - } - *ka = key - return nil -} - -var _ encoding.TextUnmarshaler = (*HexArg)(nil) diff --git a/cmd/kwil-admin/cmds/common/paths.go b/cmd/kwil-admin/cmds/common/paths.go new file mode 100644 index 000000000..7070b8d12 --- /dev/null +++ b/cmd/kwil-admin/cmds/common/paths.go @@ -0,0 +1,16 @@ +package common + +import ( + "os" + "path/filepath" +) + +func DefaultKwilAdminRoot() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".kwil-admin") +} + +func DefaultKwildRoot() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".kwild") +} diff --git a/cmd/kwil-admin/cmds/common/rpc.go b/cmd/kwil-admin/cmds/common/rpc.go new file mode 100644 index 000000000..47c5b7fca --- /dev/null +++ b/cmd/kwil-admin/cmds/common/rpc.go @@ -0,0 +1,165 @@ +package common + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/kwilteam/kwil-db/core/adminclient" + "github.com/spf13/cobra" +) + +// BindRPCFlags binds the RPC flags to the given command. +// This includes an rpcserver flag, and the TLS flags. +// These flags can be used to create an admin service client. +// The flags will be bound to all subcommands of the given command. +func BindRPCFlags(cmd *cobra.Command) { + cmd.PersistentFlags().StringP("rpcserver", "s", "unix:///tmp/kwil_admin.sock", "admin RPC server address (either unix or tcp) [default: unix:///tmp/kwil_admin.sock]") + + cmd.PersistentFlags().String("authrpc-cert", "", "kwild's TLS certificate") + cmd.PersistentFlags().String("tlskey", "auth.key", "kwil-admin's TLS key file to establish a mTLS (authenticated) connection [default: auth.key]") + cmd.PersistentFlags().String("tlscert", "auth.cert", "kwil-admin's TLS certificate file for server to authenticate us [default: auth.cert]") +} + +// GetRPCServerFlag returns the RPC flag from the given command. +func GetRPCServerFlag(cmd *cobra.Command) (string, error) { + return cmd.Flags().GetString("rpcserver") +} + +// GetAdminSvcClient will return an admin service client based on the flags. +// The flags should be bound using the BindRPCFlags function. +func GetAdminSvcClient(ctx context.Context, cmd *cobra.Command) (*adminclient.AdminClient, error) { + dialOpt := []adminclient.AdminClientOpt{} + + rpcServer, err := GetRPCServerFlag(cmd) + if err != nil { + return nil, err + } + + // get the tls files + // if one is specified, all must be specified + // if none are specified, then we do not use tls + if cmd.Flags().Changed("authrpc-cert") || cmd.Flags().Changed("tlskey") || cmd.Flags().Changed("tlscert") { + kwildTLSCertFile, clientTLSKeyFile, clientTLSCertFile, err := getTLSFlags(cmd) + if err != nil { + return nil, err + } + + dialOpt = append(dialOpt, adminclient.WithTLS(kwildTLSCertFile, clientTLSKeyFile, clientTLSCertFile)) + } + + return adminclient.New(ctx, rpcServer, dialOpt...) +} + +const ( + // kwildTLSCertFileName is the default file name for kwild's TLS certificate + // when we look in the .kwild folder for it (when kwild is on this machine). + kwildTLSCertFileName = config.DefaultTLSCertFile + + // capturedKwildTLSCertFileName is the name of the kwild TLS certificate when + // we look in the .kwil-admin folder for it. + capturedKwildTLSCertFileName = "kwild.cert" +) + +// getTLSFlags returns the TLS flags from the given command. +func getTLSFlags(cmd *cobra.Command) (kwildTLSCertFile, clientTLSKeyFile, clientTLSCertFile string, err error) { + kwildTLSCertFile, err = cmd.Flags().GetString("authrpc-cert") + if err != nil { + return "", "", "", err + } + + clientTLSKeyFile, err = cmd.Flags().GetString("tlskey") + if err != nil { + return "", "", "", err + } + + clientTLSCertFile, err = cmd.Flags().GetString("tlscert") + if err != nil { + return "", "", "", err + } + + cert := nodeCert{ + KwildTLSCertFile: kwildTLSCertFile, + ClientTLSKeyFile: clientTLSKeyFile, + ClientTLSCertFile: clientTLSCertFile, + } + + return cert.tlsFiles() +} + +// nodeCert is the struct that holds the TLS certificate and key files for +// kwil-admin to use when connecting to the remote node. +type nodeCert struct { + KwildTLSCertFile string + ClientTLSKeyFile string // default: auth.key + ClientTLSCertFile string // default: auth.cert +} + +// tlsFiles loads the remote nodes TLS certificate, which the client uses to +// authenticate the server during the connection handshake, and our TLS key +// pair, which allows the server to authenticate the client. The server's TLS +// certificate would be obtained from the node machine and specified with the +// --authrpc-cert flag, this will search for it in known paths. The client key +// pair (ours) should first be generated with the `node gen-auth-key` command. +func (nc *nodeCert) tlsFiles() (nodeCert, ourKey, ourCert string, err error) { + // Look for kwild's TLS certificate in: + // 1. any path provided via --authrpc-cert + // 2. ~/.kwil-admin/kwild.cert + // 3. ~/.kwild/rpc.cert + nodeCert = nc.KwildTLSCertFile + if nodeCert != "" { // --authrpc-cert + nodeCert = fullPath(nodeCert) + } else { // search the two fallback paths + nodeCert = filepath.Join(DefaultKwilAdminRoot(), capturedKwildTLSCertFileName) + if !fileExists(nodeCert) { + nodeCert = filepath.Join(DefaultKwildRoot(), kwildTLSCertFileName) + } + } + if nodeCert == "" || !fileExists(nodeCert) { + err = fmt.Errorf("kwild cert file not found, checked %v", nodeCert) + return + } + ourKey, ourCert = fullPath(nc.ClientTLSKeyFile), fullPath(nc.ClientTLSCertFile) + if ourKey == "" || ourCert == "" { + err = errors.New("our TLS key/cert not found") + return // leave the existence check until we load the files + } + + return +} + +// fullPath gets the full path to a file, searching in the following order: +// 1. the path itself, if it is absolute +// 2. the current directory +// 3. ~/.kwil-admin +func fullPath(path string) string { + // If an absolute path is specified, do nothing. + if filepath.IsAbs(path) { + return path + } + + // First check relative to the current directory. + fullPath, err := filepath.Abs(path) + if err != nil { + return "" + } + if fileExists(fullPath) { + return fullPath + } + + // Check for the file name in ~/.kwil-admin + fullPath = filepath.Join(DefaultKwilAdminRoot(), path) + if fileExists(fullPath) { + return fullPath + } + + return "" +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) +} diff --git a/cmd/kwil-admin/cmds/key/cmd.go b/cmd/kwil-admin/cmds/key/cmd.go new file mode 100644 index 000000000..e4a839748 --- /dev/null +++ b/cmd/kwil-admin/cmds/key/cmd.go @@ -0,0 +1,23 @@ +package key + +import "github.com/spf13/cobra" + +const keyExplain = "The `key` command provides subcommands for private key generation and inspection." + +var keyCmd = &cobra.Command{ + Use: "key", + Short: keyExplain, + Long: "The `key` command provides subcommands for private key generation and inspection. These are the private keys that identify the node on the network and provide validator transaction signing capability.", +} + +func NewKeyCmd() *cobra.Command { + cmd := keyCmd + + // Add subcommands + cmd.AddCommand( + genCmd(), + infoCmd(), + ) + + return cmd +} diff --git a/cmd/kwil-admin/cmds/key/gen.go b/cmd/kwil-admin/cmds/key/gen.go new file mode 100644 index 000000000..fc41a0344 --- /dev/null +++ b/cmd/kwil-admin/cmds/key/gen.go @@ -0,0 +1,53 @@ +package key + +import ( + "encoding/hex" + "os" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/internal/abci" + "github.com/spf13/cobra" +) + +var ( + genExample = `# Generate a new key and save it to ./priv_key +kwil-admin key gen --key-file ./priv_key + +# Generate a raw private key +kwil-admin key gen --raw` +) + +func genCmd() *cobra.Command { + var raw bool // if true, output hex private key only + var out string + + cmd := &cobra.Command{ + Use: "gen", + Short: "Generate ed25519 keys for usage in validators.", + Long: "Generate ed25519 keys for usage in validators.", + Example: genExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + privKey := abci.GeneratePrivateKey() + if out == "" { + if raw { + return display.PrintCmd(cmd, display.RespString(hex.EncodeToString(privKey))) + } else { + return display.PrintCmd(cmd, abci.PrivKeyInfo(privKey)) + } + } + + err := os.WriteFile(out, []byte(hex.EncodeToString(privKey[:])), 0600) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespString("Private key written to "+out)) + }, + } + + cmd.Flags().BoolVarP(&raw, "raw", "R", false, "just print the private key hex without other encodings, public key, or node ID") + cmd.Flags().StringVarP(&out, "key-file", "o", "", "file to which the new private key is written (stdout by default)") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/key/info.go b/cmd/kwil-admin/cmds/key/info.go new file mode 100644 index 000000000..b0442d446 --- /dev/null +++ b/cmd/kwil-admin/cmds/key/info.go @@ -0,0 +1,53 @@ +package key + +import ( + "errors" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/internal/abci" + "github.com/spf13/cobra" +) + +var ( + infoLong = `Display information about a private key. + +The private key can either be passed as a key file path, or as a hex-encoded string.` + + infoExample = `# Using a key file +kwil-admin key info --key-file ~/.kwild/private_key + +# Using a hex-encoded string +kwil-admin key info 381d28cf348c9efbf7d26ea54b647e2cb646d3b98cdeec0f1053a5ff599a036a0aa381bd4aad1670a39977d5416bfac7bd060765adc58a4bb16bbbafeefbae34` +) + +func infoCmd() *cobra.Command { + var privkeyFile string + + cmd := &cobra.Command{ + Use: "info", + Short: "Display information about a private key.", + Long: infoLong, + Example: infoExample, + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + // if len(args) == 1, then the private key is passed as a hex string + // otherwise, it is passed as a file path + if len(args) == 1 { + return display.PrintCmd(cmd, abci.PrivKeyInfo([]byte(args[0]))) + } else if privkeyFile != "" { + key, err := abci.ReadKeyFile(privkeyFile) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, abci.PrivKeyInfo(key)) + } else { + return display.PrintErr(cmd, errors.New("must provide with the private key file or hex string")) + } + }, + } + + cmd.Flags().StringVarP(&privkeyFile, "key-file", "o", "", "file containing the private key to display") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/node/cmd.go b/cmd/kwil-admin/cmds/node/cmd.go new file mode 100644 index 000000000..2428d0c7d --- /dev/null +++ b/cmd/kwil-admin/cmds/node/cmd.go @@ -0,0 +1,25 @@ +package node + +import ( + "github.com/spf13/cobra" +) + +const nodeExplain = "The `node` command is used to get information about a running Kwil node." + +var nodeCmd = &cobra.Command{ + Use: "node", + Short: nodeExplain, + Long: nodeExplain, +} + +func NewNodeCmd() *cobra.Command { + nodeCmd.AddCommand( + + versionCmd(), + statusCmd(), + peersCmd(), + genAuthKeyCmd(), + ) + + return nodeCmd +} diff --git a/cmd/kwil-admin/cmds/node/gen-auth-key.go b/cmd/kwil-admin/cmds/node/gen-auth-key.go new file mode 100644 index 000000000..aea851c12 --- /dev/null +++ b/cmd/kwil-admin/cmds/node/gen-auth-key.go @@ -0,0 +1,68 @@ +package node + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/core/rpc/transport" + "github.com/spf13/cobra" +) + +var ( + genAuthKeyLong = `Generate a new key pair for use in the node's validator set. + +The key pair is generated and stored in the node's configuration directory, in the files auth.key and auth.cert. The key pair is used to authenticate the admin tool to the node.` + genAuthKeyExample = `# Generate a new TLS key pair to talk to the node +kwil-admin node gen-auth-key --authrpc-cert "~/.kwild/rpc.cert"` +) + +func genAuthKeyCmd() *cobra.Command { + var keyFile, certFile string + + cmd := &cobra.Command{ + Use: "gen-auth-key", + Short: "Generate a new key pair for use in the node's validator set.", + Long: genAuthKeyLong, + Example: genAuthKeyExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + rootDir := common.DefaultKwilAdminRoot() + + if !filepath.IsAbs(keyFile) { + keyFile = filepath.Join(rootDir, keyFile) + } + if fileExists(keyFile) { + return display.PrintErr(cmd, fmt.Errorf("key file exists: %v", keyFile)) + } + if err := os.MkdirAll(filepath.Dir(keyFile), 0755); err != nil { + return display.PrintErr(cmd, fmt.Errorf("failed to create key file dir: %v", err)) + } + + if !filepath.IsAbs(certFile) { + certFile = filepath.Join(rootDir, certFile) + } + if fileExists(certFile) { + return display.PrintErr(cmd, fmt.Errorf("cert file exists: %v", certFile)) + } + if err := os.MkdirAll(filepath.Dir(certFile), 0755); err != nil { + + return display.PrintErr(cmd, fmt.Errorf("failed to create key file dir: %v", err)) + } + + return transport.GenTLSKeyPair(certFile, keyFile, "kwild CA", nil) + }, + } + + cmd.Flags().StringVar(&keyFile, "tlskey", "auth.key", "output path for the node's TLS key file [default: auth.key]") + cmd.Flags().StringVar(&certFile, "tlscert", "auth.cert", "output path for the node's TLS certificate file [default: auth.cert]") + + return cmd +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) +} diff --git a/cmd/kwil-admin/cmds/node/peers.go b/cmd/kwil-admin/cmds/node/peers.go new file mode 100644 index 000000000..d38941221 --- /dev/null +++ b/cmd/kwil-admin/cmds/node/peers.go @@ -0,0 +1,61 @@ +package node + +import ( + "context" + "encoding/json" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + types "github.com/kwilteam/kwil-db/core/types/admin" + "github.com/spf13/cobra" +) + +var ( + peersLong = `Print a list of the node's peers, with their public information.` + + peersExample = `# Print a list of the node's peers +kwil-admin node peers --rpcserver localhost:50151 --authrpc-cert "~/.kwild/rpc.cert"` +) + +func peersCmd() *cobra.Command { + var cmd = &cobra.Command{ + Use: "peers", + Short: "Print a list of the node's peers, with their public information.", + Long: peersLong, + Example: peersExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + peers, err := client.Peers(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &peersMsg{peers: peers}) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} + +// peersMsg is a wrapper around the []*types.PeerInfo type that +// implements the MsgFormatter interface. +type peersMsg struct { + peers []*types.PeerInfo +} + +var _ display.MsgFormatter = (*peersMsg)(nil) + +func (p *peersMsg) MarshalJSON() ([]byte, error) { + return json.Marshal(p.peers) +} + +func (p *peersMsg) MarshalText() ([]byte, error) { + return json.MarshalIndent(p.peers, "", " ") +} diff --git a/cmd/kwil-admin/cmds/node/status.go b/cmd/kwil-admin/cmds/node/status.go new file mode 100644 index 000000000..3183c4e23 --- /dev/null +++ b/cmd/kwil-admin/cmds/node/status.go @@ -0,0 +1,61 @@ +package node + +import ( + "context" + "encoding/json" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + types "github.com/kwilteam/kwil-db/core/types/admin" + "github.com/spf13/cobra" +) + +var ( + statusLong = `Print the node's status information.` + + statusExample = `# Print the node's status information +kwil-admin node status --rpcserver localhost:50151 --authrpc-cert "~/.kwild/rpc.cert"` +) + +func statusCmd() *cobra.Command { + var cmd = &cobra.Command{ + Use: "status", + Short: "Print the node's status information.", + Long: statusLong, + Example: statusExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + status, err := client.Status(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &statusMsg{status: status}) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} + +// statusMsg is a wrapper around the Status type that +// implements the MsgFormatter interface. +type statusMsg struct { + status *types.Status +} + +var _ display.MsgFormatter = (*statusMsg)(nil) + +func (s *statusMsg) MarshalJSON() ([]byte, error) { + return json.Marshal(s.status) +} + +func (s *statusMsg) MarshalText() ([]byte, error) { + return json.MarshalIndent(s.status, "", " ") +} diff --git a/cmd/kwil-admin/cmds/node/version.go b/cmd/kwil-admin/cmds/node/version.go new file mode 100644 index 000000000..16deb4e7e --- /dev/null +++ b/cmd/kwil-admin/cmds/node/version.go @@ -0,0 +1,43 @@ +package node + +import ( + "context" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + versionLong = `Print the node's version information. The version is the Kwil's version string, set at compile time.` + + versionExample = `# Print the node's version information +kwil-admin node version --rpcserver localhost:50151 --authrpc-cert "~/.kwild/rpc.cert"` +) + +func versionCmd() *cobra.Command { + var cmd = &cobra.Command{ + Use: "version", + Short: "Print the node's version information.", + Long: versionLong, + Example: versionExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + version, err := client.Version(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespString(version)) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} diff --git a/cmd/kwil-admin/cmds/root.go b/cmd/kwil-admin/cmds/root.go new file mode 100644 index 000000000..7922f38d9 --- /dev/null +++ b/cmd/kwil-admin/cmds/root.go @@ -0,0 +1,36 @@ +package cmds + +import ( + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/common/version" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/key" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/node" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/setup" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/utils" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/validators" + "github.com/spf13/cobra" +) + +func NewRootCmd() *cobra.Command { + rootCmd.AddCommand( + version.NewVersionCmd(), + key.NewKeyCmd(), + node.NewNodeCmd(), + setup.NewSetupCmd(), + validators.NewValidatorsCmd(), + utils.NewUtilsCmd(), + ) + + display.BindOutputFormatFlag(rootCmd) + display.BindSilenceFlag(rootCmd) + + return rootCmd +} + +var rootCmd = &cobra.Command{ + Use: "kwil-admin", + Short: "The Kwil node admin tool.", + Long: `The Kwil node admin tool.`, + SilenceUsage: true, + DisableAutoGenTag: true, +} diff --git a/cmd/kwil-admin/cmds/setup/cmd.go b/cmd/kwil-admin/cmds/setup/cmd.go new file mode 100644 index 000000000..ec7402a60 --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/cmd.go @@ -0,0 +1,44 @@ +package setup + +import ( + "os" + "path/filepath" + "strings" + + "github.com/spf13/cobra" +) + +const setupLong = `The ` + "`" + `setup` + "`" + ` command provides functions for creating and managing node configuration and data, including: + - performing quick setup of a standalone Kwil node (init) and Kwil test networks (testnet) + - updating genesis config with initial SQLite files (genesis-hash) + - resetting node state and all data files (reset)` + +var setupCmd = &cobra.Command{ + Use: "setup", + Short: "The `setup` command provides functions for creating and managing node configuration and data.", + Long: setupLong, +} + +func NewSetupCmd() *cobra.Command { + setupCmd.AddCommand( + initCmd(), + resetCmd(), + testnetCmd(), + genesisHashCmd(), + resetStateCmd(), + peerCmd(), + ) + + return setupCmd +} + +func expandPath(path string) (string, error) { + if strings.HasPrefix(path, "~") { + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + path = filepath.Join(home, path[2:]) + } + return filepath.Abs(path) +} diff --git a/cmd/kwil-admin/cmds/setup/genesis-hash.go b/cmd/kwil-admin/cmds/setup/genesis-hash.go new file mode 100644 index 000000000..0e6790cea --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/genesis-hash.go @@ -0,0 +1,49 @@ +package setup + +import ( + "encoding/hex" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/spf13/cobra" +) + +var ( + genesisHashLong = `Compute genesis hash from SQLite files, and optionally update ` + "`" + `genesis.json` + "`" + `. +It takes one argument, which is the path containing the SQLite files to be included in the genesis hash. + +By default, it will print the genesis hash to stdout. To specify a genesis file to update as well, use the ` + "`" + `--genesis` + "`" + ` flag.` + + genesisHashExample = `# Compute genesis hash from SQLite files, and add it to a genesis file +kwil-admin setup genesis-hash "~/.kwild/data/kwil.db" --genesis "~/.kwild/abci/config/genesis.json"` +) + +func genesisHashCmd() *cobra.Command { + + var genesisFile string + + cmd := &cobra.Command{ + Use: "genesis-hash", + Short: "Compute genesis hash from SQLite files, and optionally update `genesis.json`.", + Long: genesisHashLong, + Example: genesisHashExample, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + expandedPath, err := expandPath(args[0]) + if err != nil { + return display.PrintErr(cmd, err) + } + + appHash, err := config.PatchGenesisAppHash(expandedPath, genesisFile) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespString(hex.EncodeToString(appHash))) + }, + } + + cmd.Flags().StringVarP(&genesisFile, "genesis", "g", "", "optional path to the genesis file to patch with the computed app hash") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/setup/init.go b/cmd/kwil-admin/cmds/setup/init.go new file mode 100644 index 000000000..70b6217ae --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/init.go @@ -0,0 +1,63 @@ +package setup + +import ( + "time" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/nodecfg" + "github.com/spf13/cobra" +) + +var ( + initLong = `The ` + "`" + `init` + "`" + ` command facilitates quick setup of an isolated Kwil node on a fresh network in which that node is the single validator. +This permits rapid prototyping and evaluation of Kwil functionality. An output directory can be specified using the ` + "`" + `--output-dir` + "`" + `" flag. +If no output directory is specified, the node will be initialized ` + "`" + `./testnet` + "`" + `.` + + initExample = `# Initialize a node, with a new network, in the directory ~/.kwil-new +kwil-admin setup init -o ~/.kwild-new` +) + +func initCmd() *cobra.Command { + var out, chainId string + var blockInterval time.Duration + var joinExpiry int64 // block height + var withoutNonces bool + + cmd := &cobra.Command{ + Use: "init", + Short: "The `init` command facilitates quick setup of an isolated Kwil node.", + Long: initLong, + Example: initExample, + RunE: func(cmd *cobra.Command, args []string) error { + expandedDir, err := expandPath(out) + if err != nil { + return display.PrintErr(cmd, err) + } + + genCfg := &nodecfg.NodeGenerateConfig{ + ChainID: chainId, + BlockInterval: blockInterval, + OutputDir: expandedDir, + JoinExpiry: joinExpiry, + WithoutGasCosts: true, // gas disabled by setup init + WithoutNonces: withoutNonces, + } + + // GenerateNodeConfig fmt.Printlns, but do we want this printed to display pkg? + err = nodecfg.GenerateNodeConfig(genCfg) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespString("Initialized node in "+expandedDir)) + }, + } + + cmd.Flags().StringVarP(&out, "output-dir", "o", "./testnet", "generated node parent directory [default: ./testnet]") + cmd.Flags().StringVar(&chainId, "chain-id", "", "chain ID to use for the genesis file (default: random)") + cmd.Flags().DurationVarP(&blockInterval, "block-interval", "i", 6*time.Second, "shortest block interval in seconds (timeout_commit) [default: 6s]") + cmd.Flags().Int64Var(&joinExpiry, "join-expiry", 14400, "number of blocks before a join request expires [default: 14400]") + cmd.Flags().BoolVar(&withoutNonces, "without-nonces", false, "disable account nonces") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/setup/peer.go b/cmd/kwil-admin/cmds/setup/peer.go new file mode 100644 index 000000000..d3a508dcc --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/peer.go @@ -0,0 +1,84 @@ +package setup + +import ( + "os" + "path/filepath" + "strings" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/nodecfg" + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/kwilteam/kwil-db/internal/abci/cometbft" + "github.com/spf13/cobra" +) + +var ( + peerLong = `The ` + "`" + `peer` + "`" + ` command facilitates quick setup of a Kwil node as a peer to an existing node. +It will automatically generate required directories and keypairs, and can be given a genesis file and peer list for an existing network.` + + peerExample = `# Initialize a node as a peer to an existing network +` // TODO: add example +) + +func peerCmd() *cobra.Command { + var out, genesisPath string + var peers []string + + cmd := &cobra.Command{ + Use: "peer", + Short: "The `peer` command facilitates quick setup of a Kwil node as a peer to an existing node.", + Long: peerLong, + Example: peerExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + expandedDir, err := expandPath(out) + if err != nil { + return display.PrintErr(cmd, err) + } + + err = os.MkdirAll(expandedDir, 0755) + if err != nil { + return display.PrintErr(cmd, err) + } + + // if genesis path is given, copy it to the node directory + if genesisPath != "" { + genesisPath, err = expandPath(genesisPath) + if err != nil { + return display.PrintErr(cmd, err) + } + + file, err := os.ReadFile(genesisPath) + if err != nil { + return display.PrintErr(cmd, err) + } + + err = os.WriteFile(filepath.Join(expandedDir, cometbft.GenesisJSONName), file, 0644) + if err != nil { + return display.PrintErr(cmd, err) + } + } + + cleanedPeers := make([]string, 0) + for _, peer := range peers { + cleanedPeers = append(cleanedPeers, strings.TrimSpace(peer)) + } + + cfg := config.EmptyConfig() + cfg.ChainCfg.P2P.PersistentPeers = strings.Join(cleanedPeers, ",") + + _, err = nodecfg.GenerateNodeFiles(expandedDir, cfg) + if err != nil { + return display.PrintErr(cmd, err) + } + + return nil + }, + } + + cmd.Flags().StringVarP(&out, "output-dir", "o", "./kwild-node", "generated node parent directory [default: ./kwild-node]") + cmd.Flags().StringVarP(&genesisPath, "genesis", "g", "", "path to genesis file") + cmd.Flags().StringSliceVarP(&peers, "peer", "p", nil, "peer to connect to (may be given multiple times, or as a comma-separated list)") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/setup/reset-state.go b/cmd/kwil-admin/cmds/setup/reset-state.go new file mode 100644 index 000000000..94a59dc69 --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/reset-state.go @@ -0,0 +1,54 @@ +package setup + +import ( + "errors" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/spf13/cobra" +) + +var ( + resetStateLong = `Delete blockchain state files.` + + resetStateExample = `# Delete blockchain state files +kwil-admin setup reset-state --root-dir "~/.kwild"` +) + +func resetStateCmd() *cobra.Command { + var rootDir string + var force bool + + cmd := &cobra.Command{ + Use: "reset-state", + Short: "Delete blockchain state files.", + Long: resetStateLong, + Example: resetStateExample, + RunE: func(cmd *cobra.Command, args []string) error { + if rootDir == "" { + if !force { + return display.PrintErr(cmd, errors.New("not removing default home directory without --force or --root-dir")) + } + rootDir = common.DefaultKwildRoot() + } + + expandedDir, err := expandPath(rootDir) + if err != nil { + return display.PrintErr(cmd, err) + } + + err = config.ResetChainState(expandedDir) + if err != nil { + return display.PrintErr(cmd, err) + } + + return nil + }, + } + + cmd.Flags().StringVarP(&rootDir, "root-dir", "r", "", "root directory of the kwild node") + cmd.Flags().BoolVarP(&force, "force", "f", false, "force removal of default home directory") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/setup/reset.go b/cmd/kwil-admin/cmds/setup/reset.go new file mode 100644 index 000000000..99ff66e21 --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/reset.go @@ -0,0 +1,75 @@ +package setup + +import ( + "errors" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/spf13/cobra" +) + +var ( + resetLong = `To delete all of a Kwil node's data files, use the ` + "`" + `reset` + "`" + ` command. If directories are not specified, the node's default directories will be used. + +WARNING: This command should not be used on production systems. This should only be used to reset disposable test nodes.` + + resetExample = `# Delete all of a Kwil node's data files +kwil-admin setup reset --root-dir "~/.kwild" --sqlpath "~/.kwild/data/kwil.db"` +) + +func resetCmd() *cobra.Command { + var rootDir, sqlPath, snapPath string + var force bool + + cmd := &cobra.Command{ + Use: "reset", + Short: "To delete all of a Kwil node's data files, use the `reset` command.", + Long: resetLong, + Example: resetExample, + RunE: func(cmd *cobra.Command, args []string) error { + if rootDir == "" { + if !force { + return display.PrintErr(cmd, errors.New("not removing default home directory without --force or --root-dir")) + } + rootDir = common.DefaultKwildRoot() + } + + if sqlPath == "" { + sqlPath = config.DefaultSQLitePath + } + if snapPath == "" { + snapPath = config.DefaultSnapshotsDir + } + + expandedRoot, err := expandPath(rootDir) + if err != nil { + return display.PrintErr(cmd, err) + } + + expandedSQL, err := expandPath(sqlPath) + if err != nil { + return display.PrintErr(cmd, err) + } + + expandedSnap, err := expandPath(snapPath) + if err != nil { + return display.PrintErr(cmd, err) + } + + err = config.ResetAll(expandedRoot, expandedSQL, expandedSnap) + if err != nil { + return display.PrintErr(cmd, err) + } + + return nil + }, + } + + cmd.Flags().StringVarP(&rootDir, "root-dir", "r", "", "root directory of the kwild node") + cmd.Flags().StringVarP(&sqlPath, "sqlpath", "s", "", "path to the SQLite database") + cmd.Flags().StringVarP(&snapPath, "snappath", "p", "", "path to the snapshot directory") + cmd.Flags().BoolVarP(&force, "force", "f", false, "force removal of default home directory") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/setup/testnet.go b/cmd/kwil-admin/cmds/setup/testnet.go new file mode 100644 index 000000000..195b07d77 --- /dev/null +++ b/cmd/kwil-admin/cmds/setup/testnet.go @@ -0,0 +1,93 @@ +package setup + +import ( + "time" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/nodecfg" + "github.com/spf13/cobra" +) + +var ( + testnetLong = `The ` + "`" + `testnet` + "`" + ` command is used to create multiple node configurations, all with the same genesis config, +and pre-configured to connect to each other. It will generate a directory for each node, with the necessary files to run each node. + +The config files for each of the nodes will specify all of the other nodes as persistent peers so that they will connect to each other on startup. +This is generally only practical for small test networks with fewer than 12 nodes. + +The testnet command creates "v + n" node root directories and populates +each with necessary files to start the new network. The genesis file includes list of v validators under the validators section. + +NOTE: strict routability for addresses is turned off in the config file so that +the test network of nodes can run on a LAN.` + + testnetExample = `# Generate a network with 4 validators and 4 non-validators with the IPs +# 192.168.10.{2,...,9} +kwil-admin setup testnet --validators 4 --non-validators 4 --output-dir ~/.kwild-testnet + +# Same as above but only 2 additional (non-validator) nodes +kwil-admin setup testnet -v 4 -n 2 --o ./output --starting-ip 192.168.10.2 + +# Manually specify hostnames for the nodes +kwil-admin setup testnet -v 4 -o ./output --hostnames 192.168.10.2 192.168.10.3 ...` +) + +func testnetCmd() *cobra.Command { + var chainId, configFile, outputDir, hostnamePrefix, hostnameSuffix, startingIPAddress, nodeDirPrefix string + var hostnames []string + var blockInterval time.Duration + var joinExpiry int64 + var validatorAmount, nonValidatorAmount, p2pPort int + var withoutNonces bool + + cmd := &cobra.Command{ + Use: "testnet", + Short: "The `testnet` command is used to create multiple node configurations, all with the same genesis config, and pre-configured to connect to each other.", + Long: testnetLong, + Example: testnetExample, + RunE: func(cmd *cobra.Command, args []string) error { + err := nodecfg.GenerateTestnetConfig(&nodecfg.TestnetGenerateConfig{ + ChainID: chainId, + BlockInterval: blockInterval, + NValidators: validatorAmount, + NNonValidators: nonValidatorAmount, + ConfigFile: configFile, + OutputDir: outputDir, + NodeDirPrefix: nodeDirPrefix, + PopulatePersistentPeers: true, + HostnamePrefix: hostnamePrefix, + HostnameSuffix: hostnameSuffix, + StartingIPAddress: startingIPAddress, + Hostnames: hostnames, + P2pPort: p2pPort, + JoinExpiry: joinExpiry, + WithoutGasCosts: true, // gas disabled by setup init + WithoutNonces: withoutNonces, + }, &nodecfg.ConfigOpts{ + UniquePorts: true, + }) + if err != nil { + return display.PrintErr(cmd, err) + } + + return nil + }, + } + + cmd.Flags().StringVarP(&outputDir, "output-dir", "o", "./testnet", "parent directory for all of generated node folders [default: ./testnet]") + cmd.Flags().StringVar(&configFile, "config", "", "path to a config file to use as a template for all nodes") + cmd.Flags().StringVar(&chainId, "chain-id", "", "chain ID to use for the genesis file (default: random)") + cmd.Flags().StringVar(&hostnamePrefix, "hostname-prefix", "", "prefix for hostnames of nodes") + cmd.Flags().StringVar(&hostnameSuffix, "hostname-suffix", "", "suffix for hostnames of nodes") + cmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "", "prefix for the node directories (node results in node0, node1, ...)") + cmd.Flags().StringVar(&startingIPAddress, "starting-ip", "172.10.100.2", "starting IP address for nodes") + cmd.Flags().StringSliceVar(&hostnames, "hostnames", []string{}, "override all hostnames of the nodes (list of hostnames must be the same length as the number of nodes)") + cmd.Flags().IntVarP(&p2pPort, "p2p-port", "p", 26656, "p2p port for nodes") + cmd.Flags().DurationVarP(&blockInterval, "block-interval", "i", 6*time.Second, "shortest block interval in seconds (timeout_commit) [default: 6s]") + cmd.Flags().Int64Var(&joinExpiry, "join-expiry", 14400, "number of blocks before a join request expires [default: 14400]") + cmd.Flags().IntVarP(&validatorAmount, "validators", "v", 1, "number of validators to generate") + cmd.Flags().IntVarP(&nonValidatorAmount, "non-validators", "n", 0, "number of non-validators to generate [defaukt: 3]") + cmd.Flags().BoolVar(&withoutNonces, "without-nonces", false, "disable account nonces") + + return cmd +} diff --git a/cmd/kwil-admin/cmds/utils/cmd.go b/cmd/kwil-admin/cmds/utils/cmd.go new file mode 100644 index 000000000..b95330f4a --- /dev/null +++ b/cmd/kwil-admin/cmds/utils/cmd.go @@ -0,0 +1,21 @@ +package utils + +import "github.com/spf13/cobra" + +const utilsCmdShort = "The `utils` command is used to get information about a running Kwil node." +const utilsCmdLong = "The `utils` command is used to get information about a running Kwil node." + +var utilsCmd = &cobra.Command{ + Use: "utils", + Short: utilsCmdShort, + Long: utilsCmdLong, +} + +func NewUtilsCmd() *cobra.Command { + utilsCmd.AddCommand( + pingCmd(), + queryTxCmd(), + ) + + return utilsCmd +} diff --git a/cmd/kwil-admin/cmds/utils/ping.go b/cmd/kwil-admin/cmds/utils/ping.go new file mode 100644 index 000000000..193164cec --- /dev/null +++ b/cmd/kwil-admin/cmds/utils/ping.go @@ -0,0 +1,43 @@ +package utils + +import ( + "context" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + pingLong = `Check connectivity with the node's admin RPC interface. If successful, returns 'pong'.` + + pingExample = `# Ping the node's admin RPC interface +kwil-admin node ping --rpcserver localhost:50151 --authrpc-cert "~/.kwild/rpc.cert"` +) + +func pingCmd() *cobra.Command { + var cmd = &cobra.Command{ + Use: "ping", + Short: "Check connectivity with the node's admin RPC interface.", + Long: pingLong, + Example: pingExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + pong, err := client.Ping(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespString(pong)) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} diff --git a/cmd/kwil-admin/cmds/utils/query-tx.go b/cmd/kwil-admin/cmds/utils/query-tx.go new file mode 100644 index 000000000..5e244a3c8 --- /dev/null +++ b/cmd/kwil-admin/cmds/utils/query-tx.go @@ -0,0 +1,85 @@ +package utils + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/core/types/transactions" + "github.com/spf13/cobra" +) + +func queryTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "query-tx", + Short: "Query a transaction's status by hash.", + Long: "Query a transaction's status by hash. The hash should be passed as a hex-encoded string.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + txHash, err := hex.DecodeString(args[0]) + if err != nil { + return display.PrintErr(cmd, err) + } + + res, err := client.TxQuery(ctx, txHash) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &respTxQuery{Msg: res}) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} + +// respTxQuery is used to represent a transaction response in cli +type respTxQuery struct { + Msg *transactions.TcTxQueryResponse +} + +func (r *respTxQuery) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Hash string `json:"hash"` // HEX + Height int64 `json:"height"` + Tx transactions.Transaction `json:"tx"` + TxResult transactions.TransactionResult `json:"tx_result"` + }{ + Hash: hex.EncodeToString(r.Msg.Hash), + Height: r.Msg.Height, + Tx: r.Msg.Tx, + TxResult: r.Msg.TxResult, + }) +} + +func (r *respTxQuery) MarshalText() ([]byte, error) { + status := "failed" + if r.Msg.Height == -1 { + status = "pending" + } else if r.Msg.TxResult.Code == transactions.CodeOk.Uint32() { + status = "success" + } + + msg := fmt.Sprintf(`Transaction ID: %s +Status: %s +Height: %d +Log: %s`, + hex.EncodeToString(r.Msg.Hash), + status, + r.Msg.Height, + r.Msg.TxResult.Log, + ) + + return []byte(msg), nil +} diff --git a/cmd/kwil-admin/cmds/validators/approve.go b/cmd/kwil-admin/cmds/validators/approve.go new file mode 100644 index 000000000..9aeaa0daf --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/approve.go @@ -0,0 +1,49 @@ +package validators + +import ( + "context" + "encoding/hex" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + approveLong = "A current validator may approve an active join request for a candidate validator using the `approve` subcommand. If enough validators approve the join request, the candidate validator will be added to the validator set." + + approveExample = `# Approve a join request for a candidate validator +kwil-admin validators approve 6ecaca8e9394c939a858c2c7b47acb1db26a96d7ab38bd702fa3820c5034e9d0` +) + +func approveCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "approve ", + Short: "A current validator may approve an active join request for a candidate validator using the `approve` subcommand.", + Long: approveLong, + Example: approveExample, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + joinerBts, err := hex.DecodeString(args[0]) + if err != nil { + return display.PrintErr(cmd, err) + } + + txHash, err := clt.Approve(ctx, joinerBts) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespTxHash(txHash)) + }, + } + + return cmd +} diff --git a/cmd/kwil-admin/cmds/validators/cmd.go b/cmd/kwil-admin/cmds/validators/cmd.go new file mode 100644 index 000000000..5d400f1e1 --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/cmd.go @@ -0,0 +1,31 @@ +package validators + +import ( + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +const validatorsShort = "The `validators` command provides functions for creating and broadcasting validator-related transactions." +const validatorsLong = "The `validators` command provides functions for creating and broadcasting validator-related transactions (join/approve/leave), and retrieving information on the current validators and join requests." + +var validatorsCmd = &cobra.Command{ + Use: "validators", + Short: validatorsShort, + Long: validatorsLong, +} + +func NewValidatorsCmd() *cobra.Command { + validatorsCmd.AddCommand( + joinCmd(), + joinStatusCmd(), + listCmd(), + approveCmd(), + removeCmd(), + leaveCmd(), + listJoinRequestsCmd(), + ) + + common.BindRPCFlags(validatorsCmd) + + return validatorsCmd +} diff --git a/cmd/kwil-admin/cmds/validators/join-status.go b/cmd/kwil-admin/cmds/validators/join-status.go new file mode 100644 index 000000000..453506004 --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/join-status.go @@ -0,0 +1,115 @@ +package validators + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "math" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/internal/validators" + "github.com/spf13/cobra" +) + +var ( + joinStatusLong = `Query the status of a pending validator join request.` + joinStatusExample = `# Query the status of a pending validator join request, by hex public key +kwil-admin validators join-status 6ecaca8e9394c939a858c2c7b47acb1db26a96d7ab38bd702fa3820c5034e9d0` +) + +func joinStatusCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "join-status ", + Short: "Query the status of a pending validator join request.", + Long: joinStatusLong, + Example: joinStatusExample, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + pubkeyBts, err := hex.DecodeString(args[0]) + if err != nil { + return display.PrintErr(cmd, err) + } + + data, err := clt.JoinStatus(ctx, pubkeyBts) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + return display.PrintErr(cmd, errors.New("no active join request for that validator")) + } + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &respValJoinStatus{Data: data}) + }, + } + + return cmd +} + +// respValJoinStatus represent the status of a validator join request in cli +type respValJoinStatus struct { + Data *validators.JoinRequest +} + +// respValJoinRequest is customized json format for respValJoinStatus +type respValJoinRequest struct { + Candidate string `json:"candidate"` + Power int64 `json:"power"` + Board []string `json:"board"` + Approved []bool `json:"approved"` +} + +func (r *respValJoinStatus) MarshalJSON() ([]byte, error) { + joinReq := &respValJoinRequest{ + Candidate: fmt.Sprintf("%x", r.Data.Candidate), + Power: r.Data.Power, + Board: make([]string, len(r.Data.Board)), + Approved: r.Data.Approved, + } + for i := range r.Data.Board { + joinReq.Board[i] = fmt.Sprintf("%x", r.Data.Board[i]) + } + + return json.Marshal(joinReq) +} + +func (r *respValJoinStatus) MarshalText() ([]byte, error) { + approved := 0 + for _, a := range r.Data.Approved { + if a { + approved++ + } + } + + needed := int(math.Ceil(float64(len(r.Data.Board)) * 2 / 3)) + + var msg bytes.Buffer + msg.WriteString(fmt.Sprintf("Candidate: %x\n", r.Data.Candidate)) + msg.WriteString(fmt.Sprintf("Requested Power: %d\n", r.Data.Power)) + msg.WriteString(fmt.Sprintf("Expiration Height: %d\n", r.Data.ExpiresAt)) + + msg.WriteString(fmt.Sprintf("%d Approvals Received (%d needed):\n", approved, needed)) + + for i := range r.Data.Board { + approvedTerm := "approved" + if !r.Data.Approved[i] { + approvedTerm = "not approved" + } + + msg.WriteString(fmt.Sprintf(" Validator %x, %s\n", + r.Data.Board[i], approvedTerm)) + } + + return msg.Bytes(), nil +} diff --git a/cmd/kwil-admin/cmds/validators/join.go b/cmd/kwil-admin/cmds/validators/join.go new file mode 100644 index 000000000..678be7187 --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/join.go @@ -0,0 +1,43 @@ +package validators + +import ( + "context" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + joinLong = "A node may request to join the validator set by submitting a join request using the `join` command. The key used to sign the join request will be the treated as the node request to join the validator set. The node will be added to the validator set if the join request is approved by the current validator set. The status of a join request can be queried using the `join-status` command." + + joinExample = `# Request to join the validator set +kwil-admin validators join` +) + +func joinCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "join", + Short: "A node may request to join the validator set by submitting a join request using the `join` command.", + Long: joinLong, + Example: joinExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + txHash, err := clt.Join(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespTxHash(txHash)) + }, + } + + return cmd +} diff --git a/cmd/kwil-admin/cmds/validators/leave.go b/cmd/kwil-admin/cmds/validators/leave.go new file mode 100644 index 000000000..a3a704d2c --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/leave.go @@ -0,0 +1,43 @@ +package validators + +import ( + "context" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + leaveLong = "A current validator may leave the validator set using the `leave` command." + + leaveExample = `# Leave the validator set +kwil-admin validators leave` +) + +func leaveCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "leave", + Short: "A current validator may leave the validator set using the `leave` command.", + Long: leaveLong, + Example: leaveExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + txHash, err := clt.Leave(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespTxHash(txHash)) + }, + } + + return cmd +} diff --git a/cmd/kwil-admin/cmds/validators/list-join-requests.go b/cmd/kwil-admin/cmds/validators/list-join-requests.go new file mode 100644 index 000000000..d37377002 --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/list-join-requests.go @@ -0,0 +1,90 @@ +package validators + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "fmt" + "math" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/core/types" + "github.com/spf13/cobra" +) + +var ( + listJoinRequestsLong = `Command ` + "`" + `list-join-requests` + "`" + ` lists all pending join requests. + +Join requests are created when a validator wants to join the validator set. The validator must be approved by 2/3 of the current validator set to be added to the validator set.` + + listJoinRequestsExample = `# List all pending join requests +kwil-admin validators list-join-requests` +) + +func listJoinRequestsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-join-requests", + Short: "List all pending join requests.", + Long: listJoinRequestsLong, + Example: listJoinRequestsExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + pending, err := clt.ListPendingJoins(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &respJoinList{Joins: pending}) + }, + } + return cmd +} + +type respJoinList struct { + Joins []*types.JoinRequest +} + +func (r *respJoinList) MarshalJSON() ([]byte, error) { + return json.Marshal(r.Joins) +} + +func (r *respJoinList) MarshalText() ([]byte, error) { + var msg bytes.Buffer + + if len(r.Joins) == 0 { + msg.WriteString("No pending join requests") + return msg.Bytes(), nil + } + + needed := int(math.Ceil(float64(len(r.Joins[0].Board)) * 2 / 3)) + + approvalTerm := "approvals" + if needed == 1 { + approvalTerm = "approval" + } + + // could be ideal to use the SQL table formatting here + msg.WriteString(fmt.Sprintf("Pending join requests (%d %s needed):\n", needed, approvalTerm)) + msg.WriteString(" Candidate | Power | Approvals | Expiration Height") + //ref spacing: 22cbbb666c26b2c1f42502df72c32de4d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100 + for _, j := range r.Joins { + approvals := 0 + for _, a := range j.Approved { + if a { + approvals++ + } + } + + msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", hex.EncodeToString(j.Candidate), j.Power, approvals, j.ExpiresAt)) + } + + return msg.Bytes(), nil +} diff --git a/cmd/kwil-admin/cmds/validators/list.go b/cmd/kwil-admin/cmds/validators/list.go new file mode 100644 index 000000000..e76b8ff85 --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/list.go @@ -0,0 +1,82 @@ +package validators + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/internal/validators" + "github.com/spf13/cobra" +) + +var ( + listLong = `List the current validator set of the network.` + + listExample = `# List the current validator set of the network +kwild validators list-validators` +) + +func listCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-validators", + Short: "List the current validator set of the network.", + Long: listLong, + Example: listExample, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + data, err := clt.ListValidators(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &respValSets{Data: data}) + }, + } + + return cmd +} + +// respValSets represent current validator set in cli +type respValSets struct { + Data []*validators.Validator +} + +type valInfo struct { + PubKey string `json:"pubkey"` + Power int64 `json:"power"` +} + +func (r *respValSets) MarshalJSON() ([]byte, error) { + valInfos := make([]valInfo, len(r.Data)) + for i, v := range r.Data { + valInfos[i] = valInfo{ + PubKey: fmt.Sprintf("%x", v.PubKey), + Power: v.Power, + } + } + + return json.Marshal(valInfos) +} + +func (r *respValSets) MarshalText() ([]byte, error) { + var msg bytes.Buffer + msg.WriteString("Current validator set:\n") + for i, v := range r.Data { + msg.WriteString(fmt.Sprintf("% 3d. %s", i, v)) + if i != len(r.Data)-1 { + msg.WriteString("\n") + } + } + + return msg.Bytes(), nil +} diff --git a/cmd/kwil-admin/cmds/validators/remove.go b/cmd/kwil-admin/cmds/validators/remove.go new file mode 100644 index 000000000..77d143c9f --- /dev/null +++ b/cmd/kwil-admin/cmds/validators/remove.go @@ -0,0 +1,49 @@ +package validators + +import ( + "context" + "encoding/hex" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/spf13/cobra" +) + +var ( + removeLong = "Command `remove` votes to remove a validator from the validator set. If enough validators vote to remove the validator, the validator will be removed from the validator set." + + removeExample = `# Remove a validator from the validator set, by hex public key +kwil-admin validators remove e16141e4def3a7f2dfc5bbf40d50619b4d7bc9c9f670fcad98327b0d3d7b97b6` +) + +func removeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "remove ", + Short: "Command `remove` votes to remove a validator from the validator set.", + Long: removeLong, + Example: removeExample, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + clt, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + validatorBts, err := hex.DecodeString(args[0]) + if err != nil { + return display.PrintErr(cmd, err) + } + + txHash, err := clt.Remove(ctx, validatorBts) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, display.RespTxHash(txHash)) + }, + } + + return cmd +} diff --git a/cmd/kwil-admin/generate/generate.go b/cmd/kwil-admin/generate/generate.go new file mode 100644 index 000000000..c3c6126d2 --- /dev/null +++ b/cmd/kwil-admin/generate/generate.go @@ -0,0 +1,23 @@ +package main + +import ( + "flag" + + "github.com/kwilteam/kwil-db/cmd/common/generate" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds" +) + +var ( + out string +) + +func main() { + flag.StringVar(&out, "out", "./dist", "output directory") + + flag.Parse() + + err := generate.WriteDocs(cmds.NewRootCmd(), out) + if err != nil { + panic(err) + } +} diff --git a/cmd/kwil-admin/key.go b/cmd/kwil-admin/key.go deleted file mode 100644 index eff03a6bb..000000000 --- a/cmd/kwil-admin/key.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "context" - "encoding/hex" - "errors" - "fmt" - "os" - - "github.com/kwilteam/kwil-db/internal/abci" - - "github.com/alexflint/go-arg" -) - -// kwil-admin key info -// kwil-admin key gen - -type KeyCmd struct { - Info *KeyInfoCmd `arg:"subcommand:info" help:"Display info about a node private key."` - Gen *KeyGenCmd `arg:"subcommand:gen" help:"Generate a node private key."` -} - -type KeyInfoCmd struct { - PrivKey HexArg `arg:"positional" help:"Private key (hexadecimal string)"` - - PrivKeyFile string `arg:"-k,--key-file" help:"file containing the private key"` -} - -type KeyGenCmd struct { - PrivKeyFile string `arg:"-o,--key-file" help:"file to which the new private key is written (stdout by default)"` - Raw bool `arg:"-R,--raw" help:"just print the private key hex without other encodings, public key, or node ID"` -} - -func keyFromBytesOrFile(key []byte, keyFile string) ([]byte, error) { - if len(key) > 0 { - return key, nil - } - if keyFile == "" { - return nil, errors.New("must provide with the private key file or hex string") - } - return abci.ReadKeyFile(keyFile) -} - -func (kc *KeyCmd) run(ctx context.Context) error { - switch { - case kc.Info != nil: - privKey, err := keyFromBytesOrFile(kc.Info.PrivKey, kc.Info.PrivKeyFile) - if err != nil { - return err - } - abci.PrintPrivKeyInfo(privKey) - return nil - - case kc.Gen != nil: - privKey := abci.GeneratePrivateKey() - if kc.Gen.PrivKeyFile == "" { - if kc.Gen.Raw { - fmt.Println(hex.EncodeToString(privKey)) - } else { - abci.PrintPrivKeyInfo(privKey) - } - return nil - } - keyHex := hex.EncodeToString(privKey[:]) - return os.WriteFile(kc.Gen.PrivKeyFile, []byte(keyHex), 0600) - - default: - return arg.ErrHelp - } -} diff --git a/cmd/kwil-admin/main.go b/cmd/kwil-admin/main.go index 5ad4a7c21..17f87cf23 100644 --- a/cmd/kwil-admin/main.go +++ b/cmd/kwil-admin/main.go @@ -1,126 +1,15 @@ package main import ( - "context" - "errors" "fmt" "os" - "os/signal" - "path/filepath" - "syscall" - "github.com/kwilteam/kwil-db/internal/version" - - "github.com/alexflint/go-arg" -) - -const ( - exitSuccess = iota - exitAppError - exitBadArgs + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds" ) -type args struct { - Key *KeyCmd `arg:"subcommand:key" help:"commands for managing node private keys"` - Setup *SetupCmd `arg:"subcommand:setup" help:"commands for setting up a standalone node or testnet configuration"` - Vals *ValidatorsCmd `arg:"subcommand:validators" help:"commands for managing validators"` - Node *NodeCmd `arg:"subcommand:node" help:"commands for controlling a running node on the authenticated RPC service"` - - Help *HelpCmd `arg:"subcommand:help"` - Ver *VerCmd `arg:"subcommand:version"` -} - -func defaultKwildRoot() string { - home, _ := os.UserHomeDir() - return filepath.Join(home, ".kwild") -} - -func defaultKwilAdminRoot() string { - home, _ := os.UserHomeDir() - return filepath.Join(home, ".kwil-admin") -} - -// HelpCmd and VerCmd are defined to emulate -h,--help and --version. -type HelpCmd struct { - Which []string `arg:"positional"` -} -type VerCmd struct{} - -func (*args) Version() string { - return "kwil-admin version " + version.KwilVersion -} - -func (*args) Description() string { - return "kwil-admin: The Kwil node admin tool\n" -} - -func (*args) Epilogue() string { - return "For more information visit https://docs.kwil.com/" -} - -// runner may be implemented by any subcommand to be a directly-runnable -// subcommand that receives the full args struct rather than using the full -// cascade of switches through the subcommands. EXPERIMENT. -type runner interface { - run(context.Context, *args) error -} - -// run is a fallback dispatcher if the subcommand is not a runner. -func (a *args) run(ctx context.Context) error { - // All of the Node and Vals subcommands are runners, and as such the - // commands to not provide a basic run function in this switch. - switch { - case a.Key != nil: - return a.Key.run(ctx) - case a.Setup != nil: - return a.Setup.run(ctx) - case a.Ver != nil: - fmt.Fprintln(os.Stdout, a.Version()) // emulate --version - return nil - default: - return arg.ErrHelp - } -} - func main() { - a := &args{} - p := arg.MustParse(a) // parse and maybe show help or version and exit - if p.Subcommand() == nil { - p.WriteHelp(os.Stderr) - fmt.Println("no command given") - os.Exit(exitBadArgs) - } - if helpCmd, isHelp := p.Subcommand().(*HelpCmd); isHelp { - p.WriteHelpForSubcommand(os.Stdout, helpCmd.Which...) // emulate -h,--help - os.Exit(exitSuccess) + if err := cmds.NewRootCmd().Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) } - - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) - ctx, cancel := context.WithCancel(context.Background()) - - go func() { - <-signalChan - cancel() - }() - - // EXPERIMENT: directly-runnable subcommands to reduce boilerplate switches - var err error - r, ok := p.Subcommand().(runner) - if ok { - err = r.run(ctx, a) - } else { - // not a runnable subcommand, use switch to dispatch - err = a.run(ctx) - } - if errors.Is(err, arg.ErrHelp) { - p.WriteHelpForSubcommand(os.Stderr, p.SubcommandNames()...) - os.Exit(exitBadArgs) - } - if err != nil { - p.FailSubcommand(err.Error(), p.SubcommandNames()...) - os.Exit(exitAppError) - } - - os.Exit(exitSuccess) } diff --git a/cmd/kwil-admin/message.go b/cmd/kwil-admin/message.go deleted file mode 100644 index 6c0814b28..000000000 --- a/cmd/kwil-admin/message.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - - "github.com/kwilteam/kwil-db/internal/validators" -) - -// respValSets represent current validator set in cli -type respValSets struct { - Data []*validators.Validator -} - -type valInfo struct { - PubKey string `json:"pubkey"` - Power int64 `json:"power"` -} - -func (r *respValSets) MarshalJSON() ([]byte, error) { - valInfos := make([]valInfo, len(r.Data)) - for i, v := range r.Data { - valInfos[i] = valInfo{ - PubKey: fmt.Sprintf("%x", v.PubKey), - Power: v.Power, - } - } - - return json.Marshal(valInfos) -} - -func (r *respValSets) MarshalText() ([]byte, error) { - var msg bytes.Buffer - msg.WriteString("Current validator set:\n") - for i, v := range r.Data { - msg.WriteString(fmt.Sprintf("% 3d. %s\n", i, v)) - } - - return msg.Bytes(), nil -} - -// respValJoinStatus represent the status of a validator join request in cli -type respValJoinStatus struct { - Data *validators.JoinRequest -} - -// respValJoinRequest is customized json format for respValJoinStatus -type respValJoinRequest struct { - Candidate string `json:"candidate"` - Power int64 `json:"power"` - Board []string - Approved []bool -} - -func (r *respValJoinStatus) MarshalJSON() ([]byte, error) { - joinReq := &respValJoinRequest{ - Candidate: fmt.Sprintf("%x", r.Data.Candidate), - Power: r.Data.Power, - Board: make([]string, len(r.Data.Board)), - Approved: r.Data.Approved, - } - for i := range r.Data.Board { - joinReq.Board[i] = fmt.Sprintf("%x", r.Data.Board[i]) - } - - return json.Marshal(joinReq) -} - -func (r *respValJoinStatus) MarshalText() ([]byte, error) { - var msg bytes.Buffer - msg.WriteString(fmt.Sprintf("Candidate: %x (want power %d)\n", - r.Data.Candidate, r.Data.Power)) - for i := range r.Data.Board { - msg.WriteString(fmt.Sprintf(" Validator %x, approved = %v\n", - r.Data.Board[i], r.Data.Approved[i])) - } - - return msg.Bytes(), nil -} diff --git a/cmd/kwil-admin/message_test.go b/cmd/kwil-admin/message_test.go deleted file mode 100644 index 995e052d1..000000000 --- a/cmd/kwil-admin/message_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "github.com/kwilteam/kwil-db/cmd/internal/display" - "github.com/kwilteam/kwil-db/internal/validators" -) - -func Example_respValSets_text() { - display.Print(&respValSets{ - Data: []*validators.Validator{ - {PubKey: []byte("pubkey1"), Power: 100}, - {PubKey: []byte("pubkey2"), Power: 200}, - }, - }, nil, "text") - // Output: - // Current validator set: - // 0. {pubkey = 7075626b657931, power = 100} - // 1. {pubkey = 7075626b657932, power = 200} -} - -func Example_respValSets_json() { - display.Print(&respValSets{ - Data: []*validators.Validator{ - {PubKey: []byte("pubkey1"), Power: 100}, - {PubKey: []byte("pubkey2"), Power: 200}, - }, - }, nil, "json") - // Output: - // { - // "result": [ - // { - // "pubkey": "7075626b657931", - // "power": 100 - // }, - // { - // "pubkey": "7075626b657932", - // "power": 200 - // } - // ], - // "error": "" - // } -} - -func Example_respValJoinStatus_text() { - display.Print(&respValJoinStatus{ - Data: &validators.JoinRequest{ - Candidate: []byte("candidate"), - Power: 100, - Board: [][]byte{[]byte("board1"), []byte("board2")}, - Approved: []bool{true, false}, - }}, - nil, "text") - // Output: - // Candidate: 63616e646964617465 (want power 100) - // Validator 626f61726431, approved = true - // Validator 626f61726432, approved = false -} - -func Example_respValJoinStatus_json() { - display.Print(&respValJoinStatus{ - Data: &validators.JoinRequest{ - Candidate: []byte("candidate"), - Power: 100, - Board: [][]byte{[]byte("board1"), []byte("board2")}, - Approved: []bool{true, false}, - }}, - nil, "json") - // Output: - // { - // "result": { - // "candidate": "63616e646964617465", - // "power": 100, - // "Board": [ - // "626f61726431", - // "626f61726432" - // ], - // "Approved": [ - // true, - // false - // ] - // }, - // "error": "" - // } -} diff --git a/cmd/kwil-admin/node.go b/cmd/kwil-admin/node.go deleted file mode 100644 index 79f9c57ce..000000000 --- a/cmd/kwil-admin/node.go +++ /dev/null @@ -1,208 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/kwilteam/kwil-db/cmd/kwild/config" // relocate or merge with nodecfg - "github.com/kwilteam/kwil-db/core/rpc/transport" - "github.com/kwilteam/kwil-db/internal/admin" -) - -const ( - // kwildTLSCertFileName is the default file name for kwild's TLS certificate - // when we look in the .kwild folder for it (when kwild is on this machine). - kwildTLSCertFileName = config.DefaultTLSCertFile - - // capturedKwildTLSCertFileName is the name of the kwild TLS certificate when - // we look in the .kwil-admin folder for it. - capturedKwildTLSCertFileName = "kwild.cert" -) - -// kwil-admin node ... (running node administration: ping, peer mgmt, sql query, ) - -type NodeCmd struct { - RPCServer string `arg:"-s,--rpcserver" default:"127.0.0.1:50151" help:"admin RPC server address"` - - KwildTLSCertFile string `arg:"--authrpc-cert" help:"kwild's TLS certificate"` - ClientTLSKeyFile string `arg:"--tlskey" default:"auth.key" help:"kwil-admin's TLS key file to establish a mTLS (authenticated) connection"` - ClientTLSCertFile string `arg:"--tlscert" default:"auth.cert" help:"kwil-admin's TLS certificate file for server to authenticate us"` - - Ping *NodePingCmd `arg:"subcommand:ping" help:"Check connectivity with the node's admin RPC interface"` - Version *NodeVerCmd `arg:"subcommand:version" help:"Report the version of the remote node"` - Status *NodeStatusCmd `arg:"subcommand:status" help:"Show detailed node status"` - Peers *NodePeersCmd `arg:"subcommand:peers" help:"Show info on all current peers"` - GenKey *NodeGenAuthKeyCmd `arg:"subcommand:gen-auth-key" help:"Generate a client key pair."` -} - -type NodeGenAuthKeyCmd struct{} - -func (ngkc *NodeGenAuthKeyCmd) run(ctx context.Context, a *args) error { - rootDir := defaultKwilAdminRoot() - - clientKeyFile := a.Node.ClientTLSKeyFile - if !filepath.IsAbs(clientKeyFile) { - clientKeyFile = filepath.Join(rootDir, clientKeyFile) - } - if fileExists(clientKeyFile) { - return fmt.Errorf("key file exists: %v", clientKeyFile) - } - if err := os.MkdirAll(filepath.Dir(clientKeyFile), 0755); err != nil { - return fmt.Errorf("failed to create key file dir: %v", err) - } - - clientCertFile := a.Node.ClientTLSCertFile - if !filepath.IsAbs(clientCertFile) { - clientCertFile = filepath.Join(rootDir, clientCertFile) - } - if fileExists(clientCertFile) { - return fmt.Errorf("cert file exists: %v", clientCertFile) - } - if err := os.MkdirAll(filepath.Dir(clientCertFile), 0755); err != nil { - return fmt.Errorf("failed to create key file dir: %v", err) - } - - return transport.GenTLSKeyPair(clientCertFile, clientKeyFile, "kwild CA", nil) -} - -func fileExists(path string) bool { - _, err := os.Stat(path) - return !os.IsNotExist(err) -} - -func (*NodeCmd) fullPath(path string) string { - // If an absolute path is specified, do nothing. - if filepath.IsAbs(path) { - return path - } - - // First check relative to the current directory. - fullPath, err := filepath.Abs(path) - if err != nil { - return "" - } - if fileExists(fullPath) { - return fullPath - } - - // Check for the file name in ~/.kwil-admin - fullPath = filepath.Join(defaultKwilAdminRoot(), path) - if fileExists(fullPath) { - return fullPath - } - - return "" -} - -// tlsFiles loads the remote nodes TLS certificate, which the client uses to -// authenticate the server during the connection handshake, and our TLS key -// pair, which allows the server to authenticate the client. The server's TLS -// certificate would be obtained from the node machine and specified with the -// --authrpc-cert flag, this will search for it in known paths. The client key -// pair (ours) should first be generated with the `node gen-auth-key` command. -func (nc *NodeCmd) tlsFiles() (nodeCert, ourKey, ourCert string, err error) { - // Look for kwild's TLS certificate in: - // 1. any path provided via --authrpc-cert - // 2. ~/.kwil-admin/kwild.cert - // 3. ~/.kwild/rpc.cert - nodeCert = nc.KwildTLSCertFile - if nodeCert != "" { // --authrpc-cert - nodeCert = nc.fullPath(nodeCert) - } else { // search the two fallback paths - nodeCert = filepath.Join(defaultKwilAdminRoot(), capturedKwildTLSCertFileName) - if !fileExists(nodeCert) { - nodeCert = filepath.Join(defaultKwildRoot(), kwildTLSCertFileName) - } - } - if nodeCert == "" || !fileExists(nodeCert) { - err = fmt.Errorf("kwild cert file not found, checked %v", nodeCert) - return - } - ourKey, ourCert = nc.fullPath(nc.ClientTLSKeyFile), nc.fullPath(nc.ClientTLSCertFile) - if ourKey == "" || ourCert == "" { - err = errors.New("our TLS key/cert not found") - return // leave the existence check until we load the files - } - - return -} - -func (nc *NodeCmd) newClient() (*admin.Client, error) { - kwildCert, ourKey, ourCert, err := nc.tlsFiles() - if err != nil { - return nil, err - } - return admin.New(nc.RPCServer, kwildCert, ourKey, ourCert) -} - -type NodePingCmd struct{} - -func (pc *NodePingCmd) run(ctx context.Context, a *args) error { - client, err := a.Node.newClient() - if err != nil { - return err - } - ping, err := client.Ping(ctx) - if err != nil { - return err - } - fmt.Println(ping) - return nil -} - -type NodeVerCmd struct{} - -func (pc *NodeVerCmd) run(ctx context.Context, a *args) error { - client, err := a.Node.newClient() - if err != nil { - return err - } - ver, err := client.Version(ctx) - if err != nil { - return err - } - fmt.Printf("kwild version %v\n", ver) - return nil -} - -type NodeStatusCmd struct{} - -func (nsc *NodeStatusCmd) run(ctx context.Context, a *args) error { - client, err := a.Node.newClient() - if err != nil { - return err - } - status, err := client.Status(ctx) - if err != nil { - return err - } - statusJSON, err := json.MarshalIndent(status, "", " ") - if err != nil { - return err - } - fmt.Println(string(statusJSON)) - return nil -} - -type NodePeersCmd struct{} - -func (nsc *NodePeersCmd) run(ctx context.Context, a *args) error { - client, err := a.Node.newClient() - if err != nil { - return err - } - peers, err := client.Peers(ctx) - if err != nil { - return err - } - peersJSON, err := json.MarshalIndent(peers, "", " ") - if err != nil { - return err - } - fmt.Println(string(peersJSON)) - return nil -} diff --git a/cmd/kwil-admin/nodecfg/generate.go b/cmd/kwil-admin/nodecfg/generate.go index 986579540..6fc1a4b51 100644 --- a/cmd/kwil-admin/nodecfg/generate.go +++ b/cmd/kwil-admin/nodecfg/generate.go @@ -26,9 +26,8 @@ const ( nodeDirPerm = 0755 chainIDPrefix = "kwil-chain-" - abciDir = config.ABCIDirName - abciConfigDir = cometbft.ConfigDir - abciDataDir = cometbft.DataDir + abciDir = config.ABCIDirName + abciDataDir = cometbft.DataDir ) type NodeGenerateConfig struct { @@ -68,6 +67,12 @@ type ConfigOpts struct { // This is useful for testing multiple nodes on the same machine. // If it is used for generating a single config, it has no effect. UniquePorts bool + + // NoGenesis is a flag to not generate a genesis file. + // This is useful if you are generating a node config for + // a network that already has a genesis file. + // If used with creating a testnet, it will result in an error. + NoGenesis bool } // GenerateNodeConfig is used to generate configuration required for running a @@ -86,50 +91,75 @@ func GenerateNodeConfig(genCfg *NodeGenerateConfig) error { cfg := config.DefaultConfig() cfg.RootDir = rootDir if genCfg.BlockInterval > 0 { - cfg.ChainCfg.Consensus.TimeoutCommit = genCfg.BlockInterval + cfg.ChainCfg.Consensus.TimeoutCommit = config.Duration(genCfg.BlockInterval) } - chainRoot := filepath.Join(rootDir, abciDir) - // NOTE: not the fully re-rooted path since this may run in a container. The - // caller can update PrivateKeyPath if desired. - fullABCIConfigDir := filepath.Join(chainRoot, abciConfigDir) - err = os.MkdirAll(fullABCIConfigDir, nodeDirPerm) + pub, err := GenerateNodeFiles(rootDir, cfg) if err != nil { return err } - err = os.MkdirAll(filepath.Join(chainRoot, abciDataDir), nodeDirPerm) + // Create or update genesis config. + genFile := filepath.Join(rootDir, cometbft.GenesisJSONName) + + _, err = os.Stat(genFile) + if os.IsNotExist(err) { + genesisCfg := config.NewGenesisWithValidator(pub) + genCfg.applyGenesisParams(genesisCfg) + return genesisCfg.SaveAs(genFile) + + } + + return err +} + +// GenerateNodeFiles will generate all generic node files that are not +// dependent on the network configuration (e.g. genesis.json). +// It can optionally be given a config file to merge with the default config. +func GenerateNodeFiles(outputDir string, originalCfg *config.KwildConfig) (publicKey []byte, err error) { + cfg := config.DefaultConfig() + if originalCfg != nil { + err := cfg.Merge(originalCfg) + if err != nil { + return nil, fmt.Errorf("failed to merge config file: %w", err) + } + } + + rootDir, err := config.ExpandPath(outputDir) if err != nil { - return err + return nil, fmt.Errorf("failed to get absolute path for output directory: %w", err) + } + cfg.RootDir = rootDir + + cometbftRoot := filepath.Join(outputDir, abciDir) + + err = os.MkdirAll(cometbftRoot, nodeDirPerm) + if err != nil { + return nil, err + } + + err = os.MkdirAll(filepath.Join(cometbftRoot, abciDataDir), nodeDirPerm) + if err != nil { + return nil, err } cfg.AppCfg.PrivateKeyPath = config.PrivateKeyFileName err = writeConfigFile(filepath.Join(rootDir, config.ConfigFileName), cfg) if err != nil { - return err + return nil, err } // Load or generate private key. fullKeyPath := filepath.Join(rootDir, config.PrivateKeyFileName) _, pubKey, newKey, err := config.ReadOrCreatePrivateKeyFile(fullKeyPath, true) if err != nil { - return fmt.Errorf("cannot read or create private key: %w", err) + return nil, fmt.Errorf("cannot read or create private key: %w", err) } if newKey { fmt.Printf("Generated new private key: %v\n", fullKeyPath) } - // Create or update genesis config. - genFile := filepath.Join(fullABCIConfigDir, cometbft.GenesisJSONName) - - _, err = os.Stat(genFile) - if os.IsNotExist(err) { - genesisCfg := config.NewGenesisWithValidator(pubKey) - genCfg.applyGenesisParams(genesisCfg) - return genesisCfg.SaveAs(genFile) - } - - return err + return pubKey, nil } func (genCfg *NodeGenerateConfig) applyGenesisParams(genesisCfg *config.GenesisConfig) { @@ -147,6 +177,9 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig, opts *ConfigOpts) erro if opts == nil { opts = &ConfigOpts{} } + if opts.NoGenesis { + return fmt.Errorf("cannot use NoGenesis opt with testnet") + } var err error genCfg.OutputDir, err = config.ExpandPath(genCfg.OutputDir) @@ -166,8 +199,14 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig, opts *ConfigOpts) erro // overwrite default config if set and valid cfg := config.DefaultConfig() if genCfg.ConfigFile != "" { - if err = cfg.ParseConfig(genCfg.ConfigFile); err != nil { - return fmt.Errorf("failed to parse config file %s: %w", genCfg.ConfigFile, err) + configFile, err := config.LoadConfigFile(genCfg.ConfigFile) + if err != nil { + return fmt.Errorf("failed to load config file %s: %w", genCfg.ConfigFile, err) + } + + err = cfg.Merge(configFile) + if err != nil { + return fmt.Errorf("failed to merge config file %s: %w", genCfg.ConfigFile, err) } } @@ -179,7 +218,7 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig, opts *ConfigOpts) erro nodeDir := filepath.Join(genCfg.OutputDir, nodeDirName) chainRoot := filepath.Join(nodeDir, abciDir) - err := os.MkdirAll(filepath.Join(chainRoot, abciConfigDir), nodeDirPerm) + err := os.MkdirAll(chainRoot, nodeDirPerm) if err != nil { _ = os.RemoveAll(genCfg.OutputDir) return err @@ -212,8 +251,7 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig, opts *ConfigOpts) erro // write genesis file for i := 0; i < genCfg.NValidators+genCfg.NNonValidators; i++ { nodeDir := filepath.Join(genCfg.OutputDir, fmt.Sprintf("%s%d", genCfg.NodeDirPrefix, i)) - chainRoot := filepath.Join(nodeDir, abciDir) - genFile := cometbft.GenesisPath(chainRoot) // filepath.Join(nodeDir, abciDir, abciConfigDir, "genesis.json") + genFile := filepath.Join(nodeDir, cometbft.GenesisJSONName) err = genConfig.SaveAs(genFile) if err != nil { return fmt.Errorf("failed to write genesis file %v: %w", genFile, err) @@ -228,7 +266,7 @@ func GenerateTestnetConfig(genCfg *TestnetGenerateConfig, opts *ConfigOpts) erro // Overwrite default config if genCfg.BlockInterval > 0 { - cfg.ChainCfg.Consensus.TimeoutCommit = genCfg.BlockInterval + cfg.ChainCfg.Consensus.TimeoutCommit = config.Duration(genCfg.BlockInterval) } cfg.ChainCfg.P2P.AddrBookStrict = false cfg.ChainCfg.P2P.AllowDuplicateIP = true @@ -348,19 +386,22 @@ func incrementPort(incoming string, amt int) (string, error) { return "", err } + if res.Scheme == "unix" { + return incoming, nil + } + // Split the URL into two parts: host (and possibly scheme) and port host, portStr, err := net.SplitHostPort(res.Host) if err != nil { - // Handle the case where there is no scheme (like "localhost:50051") - if strings.Contains(err.Error(), "missing port in address") { - parts := strings.Split(incoming, ":") - if len(parts) != 2 { - return "", fmt.Errorf("invalid URL format") - } - host, portStr = parts[0], parts[1] - } else { + // err will occur if there is no scheme, complaining (incorrectly) that + // there is no port. If res.Opaque is not empty, then + // res.Scheme is actually the host, and + // res.Opaque is the port. + if res.Opaque == "" { return "", err } + host = res.Scheme + portStr = res.Opaque } // Convert the port to an integer and increment it diff --git a/cmd/kwil-admin/nodecfg/toml.go b/cmd/kwil-admin/nodecfg/toml.go index 47a6756fd..125547baa 100644 --- a/cmd/kwil-admin/nodecfg/toml.go +++ b/cmd/kwil-admin/nodecfg/toml.go @@ -6,6 +6,7 @@ import ( "os" "strings" "text/template" + "time" "github.com/kwilteam/kwil-db/cmd/kwild/config" ) @@ -16,6 +17,9 @@ func init() { var err error tmpl := template.New("configFileTemplate").Funcs(template.FuncMap{ "arrayFormatter": arrayFormatter, + "configDuration": func(d config.Duration) time.Duration { + return time.Duration(d) + }, }) if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil { panic(err) @@ -92,13 +96,13 @@ time_format = "{{ .Logging.TimeEncoding }}" # Node's Private key private_key_path = "{{ .AppCfg.PrivateKeyPath }}" -# TCP or UNIX socket address for the KWILD App's GRPC server to listen on +# TCP address for the KWILD App's GRPC server to listen on grpc_listen_addr = "{{ .AppCfg.GrpcListenAddress }}" -# TCP or UNIX socket address for the KWILD App's HTTP server to listen on +# TCP address for the KWILD App's HTTP server to listen on http_listen_addr = "{{ .AppCfg.HTTPListenAddress }}" -# TCP or UNIX socket address for the KWILD App's Admin GRPC server to listen on +# Unix socket or TCP address for the KWILD App's Admin GRPC server to listen on admin_listen_addr = "{{ .AppCfg.AdminListenAddress }}" # List of Extension endpoints to be enabled ex: ["localhost:50052", "169.198.102.34:50053"] @@ -151,18 +155,18 @@ listen_addr = "{{ .ChainCfg.RPC.ListenAddress }}" [chain.consensus] # How long we wait for a proposal block before prevoting nil -timeout_propose = "{{ .ChainCfg.Consensus.TimeoutPropose }}" +timeout_propose = "{{configDuration .ChainCfg.Consensus.TimeoutPropose }}" # How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) -timeout_prevote = "{{ .ChainCfg.Consensus.TimeoutPrevote }}" +timeout_prevote = "{{configDuration .ChainCfg.Consensus.TimeoutPrevote }}" # How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) -timeout_precommit = "{{ .ChainCfg.Consensus.TimeoutPrecommit }}" +timeout_precommit = "{{configDuration .ChainCfg.Consensus.TimeoutPrecommit }}" # How long we wait after committing a block, before starting on the new # height (this gives us a chance to receive some more precommits, even # though we already have +2/3). -timeout_commit = "{{ .ChainCfg.Consensus.TimeoutCommit }}" +timeout_commit = "{{configDuration .ChainCfg.Consensus.TimeoutCommit }}" ####################################################### ### P2P Configuration Options ### @@ -180,6 +184,7 @@ listen_addr = "{{ .ChainCfg.P2P.ListenAddress }}" external_address = "{{ .ChainCfg.P2P.ExternalAddress }}" # Comma separated list of nodes to keep persistent connections to (used for bootstrapping) +# Nodes should be identified as id@host:port, where id is the hex encoded CometBFT address. # Example: "d128266b8b9f64c313de466cf29e0a6182dba54d@172.10.100.2:26656,9440f4a8059cf7ff31454973c4f9c68de65fe526@172.10.100.3:26656" persistent_peers = "{{ .ChainCfg.P2P.PersistentPeers }}" diff --git a/cmd/kwil-admin/nodecfg/toml_test.go b/cmd/kwil-admin/nodecfg/toml_test.go index aab963067..988f064d6 100644 --- a/cmd/kwil-admin/nodecfg/toml_test.go +++ b/cmd/kwil-admin/nodecfg/toml_test.go @@ -20,7 +20,12 @@ func Test_Generate_TOML(t *testing.T) { defer os.Remove("test.toml") updatedcfg := config.DefaultConfig() - err := updatedcfg.ParseConfig("test.toml") + tomlCfg, err := config.LoadConfigFile("test.toml") + assert.NoError(t, err) + + err = updatedcfg.Merge(tomlCfg) + assert.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, cfg.AppCfg.SqliteFilePath, updatedcfg.AppCfg.SqliteFilePath) assert.Equal(t, cfg.AppCfg.GrpcListenAddress, updatedcfg.AppCfg.GrpcListenAddress) diff --git a/cmd/kwil-admin/setup.go b/cmd/kwil-admin/setup.go deleted file mode 100644 index 21c78ac36..000000000 --- a/cmd/kwil-admin/setup.go +++ /dev/null @@ -1,189 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/kwilteam/kwil-db/cmd/kwil-admin/nodecfg" - "github.com/kwilteam/kwil-db/cmd/kwild/config" - - "github.com/alexflint/go-arg" -) - -// kwil-admin setup init -o DIR ... -// kwil-admin setup testnet -v X -n Y ... -// kwil-admin setup genesis-hash DBDIR --genesis=<../genesis.json> -// kwil-admin setup reset -// kwil-admin setup reset-state - -type SetupCmd struct { - Init *SetupInitCmd `arg:"subcommand:init" help:"Initialize the files required for a single Kwil node."` - Testnet *SetupTestnetCmd `arg:"subcommand:testnet" help:"Initialize the files required for a Kwil test network."` - GenesisHash *SetupGenesisHashCmd `arg:"subcommand:genesis-hash" help:"Compute genesis hash from SQLite files, and optionally update genesis.json"` - Reset *SetupResetCmd `arg:"subcommand:reset" help:"Delete all Kwil data folders, including datasets and blockchain data"` - ResetState *SetupResetStateCmd `arg:"subcommand:reset-state" help:"Delete blockchain state files"` -} - -func (cc *SetupCmd) run(ctx context.Context) error { - switch { - case cc.Init != nil: - genCfg := &nodecfg.NodeGenerateConfig{ - ChainID: cc.Init.ChainID, - BlockInterval: cc.Init.BlockInterval, - OutputDir: cc.Init.OutputDir, - JoinExpiry: cc.Init.JoinExpiry, - WithoutGasCosts: true, // gas disabled by setup init - WithoutNonces: cc.Init.WithoutNonces, - } - return nodecfg.GenerateNodeConfig(genCfg) - case cc.Testnet != nil: - cc.Testnet.WithoutGasCosts = true // gas disabled by setup testnet - genCfg := nodecfg.TestnetGenerateConfig(*cc.Testnet) - genCfg.PopulatePersistentPeers = true // temporary workaround without changing nodecfg - return nodecfg.GenerateTestnetConfig(&genCfg, &nodecfg.ConfigOpts{ - UniquePorts: true, - }) - case cc.GenesisHash != nil: - dbDir, genesisFile := cc.GenesisHash.DBDir, cc.GenesisHash.GenesisFile - appHash, err := config.PatchGenesisAppHash(dbDir, genesisFile) - if err != nil { - fmt.Printf("App hash written: %x", appHash) - return nil - } - return err - case cc.Reset != nil: - return cc.Reset.run(ctx) - case cc.ResetState != nil: - return cc.ResetState.run(ctx) - default: - return arg.ErrHelp - } -} - -type SetupInitCmd struct { - ChainID string `arg:"--chain-id" help:"override the chain ID"` - BlockInterval time.Duration `arg:"-i,--block-interval" default:"6s" help:"Shortest block interval in seconds (timeout_commit)" placeholder:"DURATION"` - OutputDir string `arg:"-o,--output-dir" default:".testnet" help:"parent directory for all of generated node folders" placeholder:"DIR"` - JoinExpiry int64 `arg:"--join-expiry" default:"14400" help:"number of blocks before a join request expires"` - WithoutNonces bool `arg:"--without-nonces" help:"disable nonces"` - - // WithoutGasCosts is not an available flag since Kwil users have no way to - // get funded with the external chain syncer gone. - // WithoutGasCosts bool `arg:"--without-gas-costs" default:"true" help:"disable gas costs"` -} - -// SetupTestnetCmd exactly matches nodecfg.TestnetGenerateConfig in field name, -// type, and layout so that it may be converted directly. -type SetupTestnetCmd struct { - ChainID string `arg:"--chain-id" help:"override the chain ID"` - BlockInterval time.Duration `arg:"-i,--block-interval" default:"6s" help:"Shortest block interval in seconds (timeout_commit)" placeholder:"DURATION"` - NValidators int `arg:"-v,--validators" default:"3" help:"number of validators" placeholder:"V"` - NNonValidators int `arg:"-n,--non-validators" default:"0" help:"number of non-validators" placeholder:"N"` - ConfigFile string `arg:"--config" help:"template config file to use, default is none" placeholder:"FILE"` - OutputDir string `arg:"-o,--output-dir" default:".testnet" help:"parent directory for all of generated node folders" placeholder:"DIR"` - NodeDirPrefix string `arg:"--node-dir-prefix" default:"node" help:"prefix for the node directories (node results in node0, node1, ...)" placeholder:"PRE"` - PopulatePersistentPeers bool `arg:"-"` // `arg:"--populate-persistent-peers" help:"update config of each node with the list of persistent peers build using either hostname-prefix or starting-ip-address"` - HostnamePrefix string `arg:"--hostname-prefix" default:"kwil-" help:"prefix for node host names e.g. node results in node0, node1, etc." placeholder:"PRE"` - HostnameSuffix string `arg:"--hostname-suffix" help:"suffix for node host names e.g. .example.com results in node0.example.com, node1.example.com, etc." placeholder:"SUF"` - StartingIPAddress string `arg:"--starting-ip" default:"172.10.100.2" help:"starting IP address of the first network node" placeholder:"IP"` - Hostnames []string `arg:"--hostnames" help:"override all hostnames of the nodes (list of hostnames must be the same length as the number of nodes)" placeholder:"HOST"` - P2pPort int `arg:"-p,--p2p-port" help:"P2P port" default:"26656" placeholder:"PORT"` - JoinExpiry int64 `arg:"--join-expiry" default:"14400" help:"number of blocks before a join request expires"` - WithoutGasCosts bool `arg:"-"` // we force true since kwild doesn't work with gas for this release. - WithoutNonces bool `arg:"--without-nonces" help:"disable nonces"` -} - -// TODO: customize the parser to recognize a detailer subcommand and print -// extended details after auto-generated usage. Presently this is not shown by -// WriteHelpForSubcommand. -func (*SetupTestnetCmd) Details() string { - return `The testnet command creates "v + n" node root directories and populates -each with necessary files to start the new network. - -The genesis file includes list of v validators under the validators section. - -NOTE: strict routability for addresses is turned off in the config file so that -the test network of nodes can run on a LAN. - -Optionally, it will fill in the persistent_peers list in the config file using -either hostnames or IPs. - -Examples: - - # Generate a network with 4 validators and 4 non-validators with the IPs - # 192.168.10.{2,...,9} - kwil-admin setup testnet -v 4 -o ./output --starting-ip 192.168.10.2 - - # Same as above but only 2 additional (non-validator) nodes - kwil-admin setup testnet -v 4 -n 2 --o ./output --starting-ip 192.168.10.2 - - # Manually specify hostnames for the nodes - kwil-admin setup testnet -v 4 -o ./output --hostnames 192.168.10.2 192.168.10.3 ... -` -} - -type SetupGenesisHashCmd struct { - DBDir string `arg:"positional" help:"directory containing all of kwild's .sqlite files to be hashed"` - GenesisFile string `arg:"-g,--genesis" help:"optional path to the genesis file to patch with the computed app hash"` -} - -func (*SetupGenesisHashCmd) Details() string { - return `Generate the genesis hash of the sqlite DBs and if a genesis file is provided, -update the app_hash in the genesis file. If genesis file is not provided, only -print the the genesis hash to stdout.` -} - -type resetDirCmd struct { - RootDir string `arg:"--root_dir,-r" help:"Kwil server root directory" placeholder:"DIR"` - Force bool `arg:"-f,--force" help:"remove the default home without explicit specification"` - // KeepAddrBook bool `arg:"-k,--keep-addrbook" help:"keep the address book intact"` -} - -// rootDir gets the root directory from the RootDir field first, and if it is -// not set AND Force is true, then it will use the default root of ~/.kwild. -func (rdc *resetDirCmd) rootDir() (string, error) { - rootDir := rdc.RootDir - if rootDir == "" { - if !rdc.Force { - return "", errors.New("not removing default home directory without --force or --root_dir") - } - rootDir = defaultKwildRoot() - } - return rootDir, nil -} - -type SetupResetStateCmd struct { - resetDirCmd -} - -func (src *SetupResetStateCmd) run(_ context.Context) error { - rootDir, err := src.rootDir() - if err != nil { - return err - } - return config.ResetChainState(rootDir) -} - -type SetupResetCmd struct { - resetDirCmd - - SQLitePath string `arg:"--sqlpath" placeholder:"DIR" help:"Path to the SQLite files"` - SnapshotDir string `arg:"--snappath" placeholder:"DIR" help:"Path to the snapshots"` -} - -func (src *SetupResetCmd) run(_ context.Context) error { - rootDir, err := src.rootDir() - if err != nil { - return err - } - sqlitePath, snapshotDir := src.SQLitePath, src.SnapshotDir - if sqlitePath == "" { - sqlitePath = config.DefaultSQLitePath - } - if snapshotDir == "" { - snapshotDir = config.DefaultSnapshotsDir - } - return config.ResetAll(rootDir, sqlitePath, snapshotDir) -} diff --git a/cmd/kwil-admin/validator.go b/cmd/kwil-admin/validator.go deleted file mode 100644 index 7eea797f2..000000000 --- a/cmd/kwil-admin/validator.go +++ /dev/null @@ -1,203 +0,0 @@ -package main - -import ( - "context" - "errors" - - "github.com/kwilteam/kwil-db/cmd/internal/display" - "github.com/kwilteam/kwil-db/core/client" - "github.com/kwilteam/kwil-db/core/crypto" - "github.com/kwilteam/kwil-db/core/crypto/auth" -) - -// kwil-admin validators list -// kwil-admin validators join-status -// kwil-admin validators join -// kwil-admin validators approve -// kwil-admin validators leave -// kwil-admin validators remove - -type ValidatorsCmd struct { - List *ValListCmd `arg:"subcommand:list"` - JoinStatus *ValJoinStatusCmd `arg:"subcommand:join-status"` - Join *ValJoinCmd `arg:"subcommand:join"` - Approve *ValApproveCmd `arg:"subcommand:approve"` - Leave *ValLeaveCmd `arg:"subcommand:leave"` - Remove *ValRemoveCmd `arg:"subcommand:remove"` - - RPCServer string `arg:"-s,--rpcserver" default:"127.0.0.1:50051" help:"RPC server address"` - ChainID string `arg:"-c,--chain" default:"" help:"The Kwil network's chain ID to use for transactions"` - OutputFormat string `arg:"-o,--output" default:"text" help:"Output format (text|json)"` -} - -// NOTE: each of the validator subcommands satisfies the runner interface to be -// directly callable by main rather than through switches. - -type ValListCmd struct{} - -var _ runner = (*ValListCmd)(nil) - -func (vlc *ValListCmd) run(ctx context.Context, a *args) error { - var resp respValSets - err := func() error { - rpcAddr := a.Vals.RPCServer - options := []client.Option{client.WithTLSCert("")} // TODO: handle cert - clt, err := client.Dial(ctx, rpcAddr, options...) - if err != nil { - return err - } - - resp.Data, err = clt.CurrentValidators(ctx) - return err - }() - - return display.Print(&resp, err, a.Vals.OutputFormat) -} - -type ValJoinStatusCmd struct { - Joiner HexArg `arg:"positional,required" help:"Public hey (hex) of the candidate validator to check for an active join request."` -} - -var _ runner = (*ValJoinStatusCmd)(nil) - -func (vjsc *ValJoinStatusCmd) run(ctx context.Context, a *args) error { - var resp respValJoinStatus - err := func() error { - rpcAddr := a.Vals.RPCServer - options := []client.Option{client.WithTLSCert("")} // TODO: handle cert - clt, err := client.Dial(ctx, rpcAddr, options...) - if err != nil { - return err - } - - resp.Data, err = clt.ValidatorJoinStatus(ctx, vjsc.Joiner) - if err != nil { - if errors.Is(err, client.ErrNotFound) { - return errors.New("no active join request for that validator") - } - return err - } - return nil - }() - - return display.Print(&resp, err, a.Vals.OutputFormat) -} - -// edSigningClient makes a client using the provided private key as an ed25519 -// Signer. -func edSigningClient(ctx context.Context, rpcAddr, chainID string, privKey []byte) (*client.Client, error) { - edPrivKey, err := crypto.Ed25519PrivateKeyFromBytes(privKey) - if err != nil { - return nil, err - } - - signer := auth.Ed25519Signer{Ed25519PrivateKey: *edPrivKey} - - options := []client.Option{ - client.WithSigner(&signer, chainID), - client.WithTLSCert(""), - } - return client.Dial(ctx, rpcAddr, options...) -} - -// valSignedCmd is meant to be embedded in commands that want a private key in -// either a positional arg or a text file. -type valSignedCmd struct { - PrivKey HexArg `arg:"positional" help:"(Optional) Private key (hexadecimal) of the validator. Mutually exclusive with --key-file."` - - PrivKeyFile string `arg:"-k,--key-file" help:"File containing the private key of the validator."` -} - -func (vsc *valSignedCmd) client(ctx context.Context, rpcAddr, chainID string) (*client.Client, error) { - privKey, err := keyFromBytesOrFile(vsc.PrivKey, vsc.PrivKeyFile) - if err != nil { - return nil, err - } - return edSigningClient(ctx, rpcAddr, chainID, privKey) -} - -type ValJoinCmd struct { - valSignedCmd -} - -var _ runner = (*ValJoinCmd)(nil) - -func (vjc *ValJoinCmd) run(ctx context.Context, a *args) error { - var txHash []byte - err := func() error { - rpcAddr, chainID := a.Vals.RPCServer, a.Vals.ChainID - clt, err := vjc.client(ctx, rpcAddr, chainID) - if err != nil { - return err - } - txHash, err = clt.ValidatorJoin(ctx) - return err - }() - - return display.Print(display.RespTxHash(txHash), err, a.Vals.OutputFormat) -} - -type ValApproveCmd struct { - Joiner HexArg `arg:"positional,required" help:"Public key of the candidate node with an active join request to approve."` - valSignedCmd -} - -var _ runner = (*ValApproveCmd)(nil) - -func (vac *ValApproveCmd) run(ctx context.Context, a *args) error { - var txHash []byte - err := func() error { - rpcAddr, chainID := a.Vals.RPCServer, a.Vals.ChainID - clt, err := vac.client(ctx, rpcAddr, chainID) - if err != nil { - return err - } - txHash, err = clt.ApproveValidator(ctx, vac.Joiner) - return err - }() - - return display.Print(display.RespTxHash(txHash), err, a.Vals.OutputFormat) -} - -type ValRemoveCmd struct { - Target HexArg `arg:"positional,required" help:"Public key of the validator to propose to remove."` - valSignedCmd -} - -var _ runner = (*ValRemoveCmd)(nil) - -func (vac *ValRemoveCmd) run(ctx context.Context, a *args) error { - var txHash []byte - err := func() error { - rpcAddr, chainID := a.Vals.RPCServer, a.Vals.ChainID - clt, err := vac.client(ctx, rpcAddr, chainID) - if err != nil { - return err - } - txHash, err = clt.RemoveValidator(ctx, vac.Target) - return err - }() - - return display.Print(display.RespTxHash(txHash), err, a.Vals.OutputFormat) -} - -type ValLeaveCmd struct { - valSignedCmd -} - -var _ runner = (*ValLeaveCmd)(nil) - -func (vjc *ValLeaveCmd) run(ctx context.Context, a *args) error { - var txHash []byte - err := func() error { - rpcAddr, chainID := a.Vals.RPCServer, a.Vals.ChainID - clt, err := vjc.client(ctx, rpcAddr, chainID) - if err != nil { - return err - } - txHash, err = clt.ValidatorLeave(ctx) - return err - }() - - return display.Print(display.RespTxHash(txHash), err, a.Vals.OutputFormat) -} diff --git a/cmd/kwil-cli/cmds/common/authinfo.go b/cmd/kwil-cli/cmds/common/authinfo.go index e72f0f349..fcc96dd5a 100644 --- a/cmd/kwil-cli/cmds/common/authinfo.go +++ b/cmd/kwil-cli/cmds/common/authinfo.go @@ -1,11 +1,11 @@ package common import ( + "encoding/base64" "encoding/json" "fmt" "net/http" "path/filepath" - "strings" "time" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" @@ -13,9 +13,10 @@ import ( ) const ( - kgwAuthTokenFileName = "kgw_auth.json" + kgwAuthTokenFileName = "auth.json" ) +// KGWAuthTokenFilePath returns the path to the file that stores the Gateway Auth cookies. func KGWAuthTokenFilePath() string { return filepath.Join(config.DefaultConfigDir, kgwAuthTokenFileName) } @@ -41,7 +42,7 @@ type cookie struct { Unparsed []string `json:"unparsed,omitempty"` // Raw text of unparsed attribute-value pairs } -func ConvertToCookie(c *http.Cookie) cookie { +func convertToCookie(c *http.Cookie) cookie { return cookie{ Name: c.Name, Value: c.Value, @@ -58,7 +59,7 @@ func ConvertToCookie(c *http.Cookie) cookie { } } -func ConvertToHttpCookie(c cookie) *http.Cookie { +func convertToHttpCookie(c cookie) *http.Cookie { return &http.Cookie{ Name: c.Name, Value: c.Value, @@ -75,18 +76,15 @@ func ConvertToHttpCookie(c cookie) *http.Cookie { } } -// KGWAuthInfo represents the KGW authentication info for a wallet address -type KGWAuthInfo struct { - Address string `json:"address"` - Cookie cookie `json:"cookie"` -} - -type LocalKGWAuthInfo []*KGWAuthInfo +// PersistedCookies is a set of Gateway Auth cookies that can be saved to a file. +// It maps a base64 user identifier to a cookie, ensuring only one cookie per wallet. +// It uses a custom cookie type that is json serializable. +type PersistedCookies map[string]cookie -// LoadKGWAuthInfo loads the address KGW authentication info from the given file. -// If the address is not authenticated(local), it returns nil. -func LoadKGWAuthInfo(authFile string, address string) (*KGWAuthInfo, error) { - address = strings.ToLower(address) +// LoadPersistedCookie loads a persisted cookie from the auth file. +// It will look up the cookie for the given user identifier. +// If nothing is found, it returns nil, nil. +func LoadPersistedCookie(authFile string, userIdentifier []byte) (*http.Cookie, error) { if !utils.FileExists(authFile) { return nil, nil } @@ -96,63 +94,73 @@ func LoadKGWAuthInfo(authFile string, address string) (*KGWAuthInfo, error) { return nil, fmt.Errorf("open kgw auth file: %w", err) } - var aInfo LocalKGWAuthInfo + var aInfo PersistedCookies err = json.NewDecoder(file).Decode(&aInfo) if err != nil { return nil, fmt.Errorf("unmarshal kgw auth file: %w", err) } - // always overwrite if the address already exists - for _, a := range aInfo { - if a.Address == address { - return a, nil - } - } + b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) + cookie := aInfo[b64Identifier] - return nil, nil + return convertToHttpCookie(cookie), nil } -// SaveAuthInfo saves the cookie to auth file. -func SaveAuthInfo(authFile string, address string, originCookie *http.Cookie) error { - address = strings.ToLower(address) - cookie := ConvertToCookie(originCookie) +// SaveCookie saves the cookie to auth file. +// It will overwrite the cookie if the address already exists. +func SaveCookie(authFile string, userIdentifier []byte, originCookie *http.Cookie) error { + cookie := convertToCookie(originCookie) authInfoBytes, err := utils.ReadOrCreateFile(authFile) if err != nil { return fmt.Errorf("read kgw auth file: %w", err) } - var aInfo LocalKGWAuthInfo + b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) - if len(authInfoBytes) != 0 { - // if the file is not empty, load the content + var aInfo PersistedCookies + if len(authInfoBytes) == 0 { + aInfo = make(PersistedCookies) + } else { err = json.Unmarshal(authInfoBytes, &aInfo) if err != nil { return fmt.Errorf("unmarshal kgw auth file: %w", err) } + } + aInfo[b64Identifier] = cookie - exists := false - // always overwrite if the address already exists - for _, a := range aInfo { - if a.Address == address { - a.Cookie = cookie - exists = true - break - } - } + jsonBytes, err := json.MarshalIndent(&aInfo, "", " ") + if err != nil { + return fmt.Errorf("marshal kgw auth info: %w", err) + } - if !exists { - aInfo = append(aInfo, &KGWAuthInfo{ - Address: address, - Cookie: cookie, - }) - } + err = utils.WriteFile(authFile, jsonBytes) + if err != nil { + return fmt.Errorf("write kgw auth file: %w", err) + } + return nil +} + +// DeleteCookie will delete a cookie that exists for a given user identifier. +// If no cookie exists for the user identifier, it will do nothing. +func DeleteCookie(authFile string, userIdentifier []byte) error { + authInfoBytes, err := utils.ReadOrCreateFile(authFile) + if err != nil { + return fmt.Errorf("read kgw auth file: %w", err) + } + + b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) + + var aInfo PersistedCookies + if len(authInfoBytes) == 0 { + aInfo = make(PersistedCookies) } else { - aInfo = append(aInfo, &KGWAuthInfo{ - Address: address, - Cookie: cookie, - }) + err = json.Unmarshal(authInfoBytes, &aInfo) + if err != nil { + return fmt.Errorf("unmarshal kgw auth file: %w", err) + } } + delete(aInfo, b64Identifier) jsonBytes, err := json.MarshalIndent(&aInfo, "", " ") if err != nil { diff --git a/cmd/kwil-cli/cmds/common/authinfo_test.go b/cmd/kwil-cli/cmds/common/authinfo_test.go index 8038221c1..57060cfcd 100644 --- a/cmd/kwil-cli/cmds/common/authinfo_test.go +++ b/cmd/kwil-cli/cmds/common/authinfo_test.go @@ -24,16 +24,15 @@ func TestLoadKGWAuthInfo(t *testing.T) { Raw: "", Unparsed: nil, } - expectCk := ConvertToCookie(&ck) var err error authFile := filepath.Join(t.TempDir(), "auth.json") - err = SaveAuthInfo(authFile, "0x123", &ck) + err = SaveCookie(authFile, []byte("0x123"), &ck) assert.NoError(t, err) - got, err := LoadKGWAuthInfo(authFile, "0x123") + got, err := LoadPersistedCookie(authFile, []byte("0x123")) assert.NoError(t, err) - assert.EqualValues(t, expectCk, got.Cookie) + assert.EqualValues(t, &ck, got) } diff --git a/cmd/kwil-cli/cmds/common/flags.go b/cmd/kwil-cli/cmds/common/flags.go new file mode 100644 index 000000000..bcd296945 --- /dev/null +++ b/cmd/kwil-cli/cmds/common/flags.go @@ -0,0 +1,16 @@ +package common + +import "github.com/spf13/cobra" + +// this file can be used to define flags that should be globally accessible / shared between commands + +// BindAssumeYesFlag binds the assume yes flag to the passed command +// If bound, the command will assume yes for all prompts +func BindAssumeYesFlag(cmd *cobra.Command) { + cmd.Flags().BoolP("assume-yes", "Y", false, "Assume yes for all prompts") +} + +// GetAssumeYesFlag returns the value of the assume yes flag +func GetAssumeYesFlag(cmd *cobra.Command) (bool, error) { + return cmd.Flags().GetBool("assume-yes") +} diff --git a/cmd/kwil-cli/cmds/common/roundtripper.go b/cmd/kwil-cli/cmds/common/roundtripper.go index de5f4e52d..3adc5086f 100644 --- a/cmd/kwil-cli/cmds/common/roundtripper.go +++ b/cmd/kwil-cli/cmds/common/roundtripper.go @@ -2,81 +2,148 @@ package common import ( "context" + "encoding/hex" "fmt" + "time" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/client" "github.com/kwilteam/kwil-db/core/crypto/auth" - "github.com/kwilteam/kwil-db/core/log" - httpRPC "github.com/kwilteam/kwil-db/core/rpc/client/user/http" + "github.com/kwilteam/kwil-db/core/gatewayclient" + "github.com/kwilteam/kwil-db/core/types" + "github.com/kwilteam/kwil-db/core/types/transactions" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" ) const ( - // WithoutPrivateKey is a flag that can be passed to DialClient to indicate that the client should not use the private key in the config - // this is a weird flag + // WithoutPrivateKey is a flag that can be passed to DialClient to indicate that the client does not need to use the private key. WithoutPrivateKey uint8 = 1 << iota + + // UsingGateway is a flag that can be passed to DialClient to indicate that the client is talking to a gateway. + // Since very few commands use the gateway, we bind this to specific commands instead of making it a global flag. + UsingGateway ) -type RoundTripper func(ctx context.Context, client *client.Client, conf *config.KwilCliConfig) error +type RoundTripper func(ctx context.Context, client Client, conf *config.KwilCliConfig) error -func DialClient(ctx context.Context, flags uint8, fn RoundTripper) error { +// DialClient dials a kwil node and calls the passed function with the client. +// It includes the command that is being run, so that it can read global flags. +func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTripper) error { conf, err := config.LoadCliConfig() if err != nil { return err } - options := []client.Option{ - client.WithLogger(log.New(log.Config{ - Level: "error", // TODO: the log package should change this to take an enum instead of a string - })), - client.WithTLSCert(conf.TLSCertFile), + if conf.GrpcURL == "" { + return fmt.Errorf("kwil provider url is required") } - // right now the session/cookie check is only done in few APIs in KGW, not ideal - // we won't all APIs until we have a rate limiter on KGW - // NOTE: with KGW auth, we kind of always need cookie, hence user's wallet address - // Store user's wallet address in config file? not sure + clientConfig := client.ClientOptions{} + if conf.PrivateKey != nil { + clientConfig.Signer = &auth.EthPersonalSigner{Key: *conf.PrivateKey} + clientConfig.ChainID = conf.ChainID + } else if flags&WithoutPrivateKey == 0 { + return fmt.Errorf("private key not provided") + } - if flags&WithoutPrivateKey == 0 { - // this means it needs to use the private key - if conf.PrivateKey == nil { - return fmt.Errorf("private key not provided") + // if not using the gateway, then we can simply create a regular client and return + if flags&UsingGateway == 0 { + client, err := client.Dial(ctx, conf.GrpcURL, &clientConfig) + if err != nil { + return err } - signer := auth.EthPersonalSigner{Key: *conf.PrivateKey} - options = append(options, client.WithSigner(&signer, conf.ChainID)) + return fn(ctx, client, conf) + } - // try load kgw auth token from file, if exist - // Kwild HTTP API doesn't care about KGW cookie, so not harm to load it - address, err := auth.EthSecp256k1Authenticator{}.Identifier(signer.Identity()) - if err != nil { - return fmt.Errorf("get address: %w", err) - } + // if we reach here, we are talking to a gateway - kgwAuthInfo, err := LoadKGWAuthInfo(KGWAuthTokenFilePath(), address) - if err == nil && kgwAuthInfo != nil { - // here create http client to config cookie - // put cookie options in core/client/client.go seems not a good idea - cookie := ConvertToHttpCookie(kgwAuthInfo.Cookie) - hc, err := httpRPC.DialOptions(conf.GrpcURL, httpRPC.WithCookie(cookie)) + client, err := gatewayclient.NewGatewayClient(ctx, conf.GrpcURL, &gatewayclient.GatewayOptions{ + ClientOptions: clientConfig, + AuthSignFunc: func(message string, signer auth.Signer) (*auth.Signature, error) { + assumeYes, err := GetAssumeYesFlag(cmd) if err != nil { - return err + return nil, err + } + + if !assumeYes { + err := promptMessage(message) + if err != nil { + return nil, err + } + } + + sig, err := signer.Sign([]byte(message)) + if err != nil { + return nil, err + } + + return sig, nil + }, + }) + if err != nil { + return err + } + + if clientConfig.Signer == nil { + return fn(ctx, client, conf) + } + + cookie, err := LoadPersistedCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity()) + if err == nil && cookie != nil { + // if setting fails, then don't do fail usage- failure likely means that the client has + // switched providers, and the cookie is no longer valid. The gatewayclient will re-authenticate. + // delete the cookie if it is invalid + err = client.SetAuthCookie(cookie) + if err != nil { + err2 := DeleteCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity()) + if err2 != nil { + return fmt.Errorf("failed to delete cookie: %w", err2) } - options = append(options, client.WithRPCClient(hc)) + + display.PrintCmd(cmd, display.RespString(fmt.Sprintf("deleted invalid persisted cookie for user %s", hex.EncodeToString(clientConfig.Signer.Identity())))) + } } - if conf.GrpcURL == "" { - // the grpc url is required - // this is somewhat redundant since the config marks it as required, but in case the config is changed - return fmt.Errorf("kwil grpc url is required") + return fn(ctx, client, conf) +} + +// Client is a client that can be used to talk to a kwil node +type Client interface { + CallAction(ctx context.Context, dbid string, action string, inputs []any) (*client.Records, error) + ChainID() string + ChainInfo(ctx context.Context) (*types.ChainInfo, error) + DeployDatabase(ctx context.Context, payload *transactions.Schema, opts ...client.TxOpt) (transactions.TxHash, error) + DropDatabase(ctx context.Context, name string, opts ...client.TxOpt) (transactions.TxHash, error) + DropDatabaseID(ctx context.Context, dbid string, opts ...client.TxOpt) (transactions.TxHash, error) + ExecuteAction(ctx context.Context, dbid string, action string, tuples [][]any, opts ...client.TxOpt) (transactions.TxHash, error) + GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) + GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) + ListDatabases(ctx context.Context, owner []byte) ([]string, error) + Ping(ctx context.Context) (string, error) + Query(ctx context.Context, dbid string, query string) (*client.Records, error) + TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) + WaitTx(ctx context.Context, txHash []byte, interval time.Duration) (*transactions.TcTxQueryResponse, error) +} + +// promptMessage prompts the user to sign a message. Return an error if user +// declines to sign. +func promptMessage(msg string) error { + // display the message to user + fmt.Println(msg) + + prompt := promptui.Prompt{ + Label: "Do you want to sign this message?", + IsConfirm: true, } - clt, err := client.Dial(ctx, conf.GrpcURL, options...) + _, err := prompt.Run() if err != nil { - return err + return fmt.Errorf("you declined to sign") } - defer clt.Close() - return fn(ctx, clt, conf) + return nil } diff --git a/cmd/kwil-cli/cmds/configure/configure.go b/cmd/kwil-cli/cmds/configure/configure.go index ccd5fb013..8b057094e 100644 --- a/cmd/kwil-cli/cmds/configure/configure.go +++ b/cmd/kwil-cli/cmds/configure/configure.go @@ -3,6 +3,7 @@ package configure import ( "fmt" + "github.com/kwilteam/kwil-db/cmd/common/display" common "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common/prompt" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/crypto" @@ -10,15 +11,31 @@ import ( "github.com/spf13/cobra" ) +var configureLong = `Configure the Kwil CLI with persistent global settings. + +This command will prompt you for the following settings: + +- Kwil RPC URL: the gRPC URL of the Kwil node you wish to connect to. +- Kwil Chain ID: the chain ID of the Kwil node you wish to connect to. If left empty, the Kwil node will provide this value. +- Kwil RPC TLS certificate path: the path to the TLS certificate of the Kwil node you wish to connect to. This is only required if the Kwil node is using TLS. +- Private Key: the private key to use for signing transactions. If left empty, the Kwil CLI will not sign transactions.` + +var configureExample = `kwil-cli configure` + func NewCmdConfigure() *cobra.Command { var cmd = &cobra.Command{ - Use: "configure", - Short: "Configure your client", - Long: "", + Use: "configure", + Short: "Configure the Kwil CLI with persistent global settings.", + Long: configureLong, + Example: configureExample, RunE: func(cmd *cobra.Command, args []string) error { + if display.ShouldSilence(cmd) { + return display.PrintErr(cmd, fmt.Errorf("cannot configure run in silence mode")) + } + conf, err := config.LoadPersistedConfig() if err != nil { - return err + return display.PrintErr(cmd, err) } err = runErrs(conf, @@ -28,7 +45,7 @@ func NewCmdConfigure() *cobra.Command { promptTLSCertFile, ) if err != nil { - return err + return display.PrintErr(cmd, err) } return config.PersistConfig(conf) diff --git a/cmd/kwil-cli/cmds/database/batch.go b/cmd/kwil-cli/cmds/database/batch.go index 128eb3c05..031d81dca 100644 --- a/cmd/kwil-cli/cmds/database/batch.go +++ b/cmd/kwil-cli/cmds/database/batch.go @@ -6,7 +6,7 @@ import ( "os" "strings" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/cmd/kwil-cli/csv" @@ -20,6 +20,30 @@ var ( supportedBatchFileTypes = []string{"csv"} ) +var ( + batchLong = `Batch executes an action on a database using inputs from a CSV file. + +To map a CSV column name to an action input, use the ` + "`" + `--map-inputs` + "`" + ` flag. +The format is ` + "`" + `--map-inputs :` + "`" + `. If the ` + "`" + `--map-inputs` + "`" + ` flag is not passed, +the CSV column name will be used as the action input name. + +You can also specify the input values directly using the ` + "`" + `--values` + "`" + ` flag, delimited by a colon. +These values will apply to all inserted rows, and will override the CSV column mappings. + +You can either specify the database to execute this against with the ` + "`" + `--name` + "`" + ` and ` + "`" + `--owner` + "`" + ` +flags, or you can specify the database by passing the database id with the ` + "`" + `--dbid` + "`" + ` flag. If a ` + "`" + `--name` + "`" + ` +flag is passed and no ` + "`" + `--owner` + "`" + ` flag is passed, the owner will be inferred from your configured wallet.` + + batchExample = `# Given a CSV file with the following contents: +# id,name,age +# 1,john,25 +# 2,jane,30 +# 3,jack,35 + +# Executing the ` + "`" + `create_user($user_id, $username, $user_age, $created_at)` + "`" + ` action on the "mydb" database +kwil-cli database batch --path ./users.csv --action create_user --name mydb --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 --map-inputs id:user_id name:username age:user_age --values created_at:$(date +%s)` +) + // batch is used for batch operations on databases func batchCmd() *cobra.Command { var filePath string @@ -28,65 +52,60 @@ func batchCmd() *cobra.Command { var action string cmd := &cobra.Command{ - Use: "batch", - Short: "Batch executes an action", - Long: `The batch command is used to batch execute an action on a database. It -reads in a file from the specified directory, and executes the action in bulk. -The execution is treated as a single transaction, and will either succeed or fail.`, - Args: cobra.ExactArgs(0), + Use: "batch", + Short: "Batch execute an action using inputs from a CSV file.", + Long: batchLong, + Example: batchExample, + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - var resp []byte - - err := common.DialClient(cmd.Context(), 0, func(ctx context.Context, cl *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, 0, func(ctx context.Context, cl common.Client, conf *config.KwilCliConfig) error { dbid, err := getSelectedDbid(cmd, conf) if err != nil { - return err + return display.PrintErr(cmd, err) } fileType, err := getFileType(filePath) if err != nil { - return fmt.Errorf("error getting file type: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error getting file type: %w", err)) } if !isSupportedBatchFileType(fileType) { - return fmt.Errorf("unsupported file type: %s", fileType) + return display.PrintErr(cmd, fmt.Errorf("unsupported file type: %s", fileType)) } file, err := os.Open(filePath) if err != nil { - return fmt.Errorf("error opening file: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error opening file: %w", err)) } inputs, err := buildInputs(file, fileType, csvColumnMappings, inputValueMappings) if err != nil { - return fmt.Errorf("error building inputs: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error building inputs: %w", err)) } actionStructure, err := getAction(ctx, cl, dbid, action) if err != nil { - return fmt.Errorf("error getting action: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error getting action: %w", err)) } tuples, err := createActionInputs(inputs, actionStructure) if err != nil { - return fmt.Errorf("error creating action inputs: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error creating action inputs: %w", err)) } - resp, err = cl.ExecuteAction(ctx, dbid, strings.ToLower(action), tuples, client.WithNonce(nonceOverride)) + resp, err := cl.ExecuteAction(ctx, dbid, strings.ToLower(action), tuples, client.WithNonce(nonceOverride)) if err != nil { - return fmt.Errorf("error executing action: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error executing action: %w", err)) } - return nil + return display.PrintCmd(cmd, display.RespTxHash(resp)) }) - - return display.Print(display.RespTxHash(resp), err, config.GetOutputFormat()) }, } - cmd.Flags().StringSliceVarP(&csvColumnMappings, "map-input", "m", []string{}, "the variables mappings to the action inputs (e.g. id:$id, name:$name, age:$age)") - cmd.Flags().StringSliceVarP(&inputValueMappings, "value", "v", []string{}, "the variables mappings to the action inputs (e.g. id:123, name:john, age:25). These will apply to all rows, and will override the csv column mappings") - cmd.Flags().StringVarP(&filePath, "path", "p", "", "the path to the file to read in (e.g. /home/user/file.csv)") + cmd.Flags().StringSliceVarP(&csvColumnMappings, "map-inputs", "m", []string{}, "csv column to action parameter mappings (e.g. csv_id:user_id, csv_name:user_name)") + cmd.Flags().StringSliceVarP(&inputValueMappings, "values", "v", []string{}, "action parameter mappings applied to all executions (e.g. id:123, name:john)") + cmd.Flags().StringVarP(&filePath, "path", "p", "", "path to the CSV file to use") cmd.Flags().StringVarP(&action, "action", "a", "", "the action to execute") cmd.Flags().StringP(nameFlag, "n", "", "the database name") cmd.Flags().StringP(ownerFlag, "o", "", "the database owner") @@ -97,7 +116,7 @@ The execution is treated as a single transaction, and will either succeed or fai return cmd } -func getAction(ctx context.Context, c *client.Client, dbid, action string) (*transactions.Action, error) { +func getAction(ctx context.Context, c common.Client, dbid, action string) (*transactions.Action, error) { schema, err := c.GetSchema(context.Background(), dbid) if err != nil { return nil, fmt.Errorf("error getting schema: %w", err) diff --git a/cmd/kwil-cli/cmds/database/call.go b/cmd/kwil-cli/cmds/database/call.go index 7f36e21ab..d70906037 100644 --- a/cmd/kwil-cli/cmds/database/call.go +++ b/cmd/kwil-cli/cmds/database/call.go @@ -5,88 +5,96 @@ import ( "fmt" "strings" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) -func callCmd() *cobra.Command { - var action string - authenticate := new(bool) +var ( + callLong = `Call a ` + "`" + `view` + "`" + ` action, returning the result. + +` + "`" + `view` + "`" + ` actions are read-only actions that do not require gas to execute. They are +the primary way to query the state of a database. The ` + "`" + `call` + "`" + ` command is used to call +a ` + "`" + `view` + "`" + ` action on a database. It takes the action name as a required flag, and the +action inputs as arguments. - cmd := &cobra.Command{ - Use: "call", - Short: "Call an 'view' action", - Long: `call an 'view' action that is a read-only action. -The query name is specified as a required "--action" flag, and the query parameters as arguments. -In order to specify an parameter, you first need to specify the parameter name, then the parameter value, delimited by a colon. +To specify an action input, you first need to specify the input name, then the input value, delimited by a colon. +For example, for action ` + "`" + `get_user($username)` + "`" + `, you would specify the action as follows: -For example, if I have a query name "create_user" that takes two arguments: name and age. -I would specify the query as follows: +` + "`" + `username:satoshi` + "`" + ` --action=get_user -'name:satoshi' 'age:32' --action=create_user +You can either specify the database to execute this against with the ` + "`" + `--name` + "`" + ` and ` + "`" + `--owner` + "`" + ` +flags, or you can specify the database by passing the database id with the ` + "`" + `--dbid` + "`" + ` flag. If a ` + "`" + `--name` + "`" + ` +flag is passed and no ` + "`" + `--owner` + "`" + ` flag is passed, the owner will be inferred from your configured wallet. -You specify the database to execute this against with the --name flag, and -the owner with the --owner flag. +If you are interacting with a Kwil gateway, you can also pass the ` + "`" + `--authenticate` + "`" + ` flag to authenticate the call with your private key.` -You can also specify the database by passing the database id with the --dbid flag. + callExample = `# Calling the ` + "`" + `get_user($username)` + "`" + ` action on the "mydb" database +kwil-cli database call --action get_user --name mydb --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 username:satoshi -For example: - -'name:satoshi' 'age:32' --action=create_user --name mydb --owner 0xAfFDC06cF34aFD7D5801A13d48C92AD39609901D +# Calling the ` + "`" + `get_user($username)` + "`" + ` action on a database using a dbid, authenticating with a private key +kwil-cli database call --action get_user --dbid 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 username:satoshi --authenticate` +) -OR +func callCmd() *cobra.Command { + var action string + var authenticate bool -'name:satoshi' 'age:32' --dbid=x1234 --action=create_user `, + cmd := &cobra.Command{ + Use: "call ...", + Short: "Call a 'view' action, returning the result.", + Long: callLong, + Example: callExample, RunE: func(cmd *cobra.Command, args []string) error { - var resp respRelations + dialFlags := common.WithoutPrivateKey + if authenticate { + // overwrite the WithoutPrivateKey flag, and add the UsingGateway flag + dialFlags = common.UsingGateway + } - err := common.DialClient(cmd.Context(), 0, func(ctx context.Context, clnt *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, dialFlags, func(ctx context.Context, clnt common.Client, conf *config.KwilCliConfig) error { dbid, err := getSelectedDbid(cmd, conf) if err != nil { - return fmt.Errorf("target database not properly specified: %w", err) + display.PrintErr(cmd, fmt.Errorf("target database not properly specified: %w", err)) } lowerName := strings.ToLower(action) inputs, err := parseInputs(args) if err != nil { - return fmt.Errorf("error getting inputs: %w", err) + display.PrintErr(cmd, fmt.Errorf("error getting inputs: %w", err)) } actionStructure, err := getAction(ctx, clnt, dbid, lowerName) if err != nil { - return fmt.Errorf("error getting action: %w", err) + display.PrintErr(cmd, fmt.Errorf("error getting action: %w", err)) } tuples, err := createActionInputs(inputs, actionStructure) if err != nil { - return fmt.Errorf("error creating action inputs: %w", err) + display.PrintErr(cmd, fmt.Errorf("error creating action inputs: %w", err)) } if len(tuples) == 0 { tuples = append(tuples, []any{}) } - resp.Data, err = clnt.CallAction(ctx, dbid, lowerName, tuples[0], client.Authenticated(*authenticate)) + data, err := clnt.CallAction(ctx, dbid, lowerName, tuples[0]) if err != nil { - return fmt.Errorf("error calling action: %w", err) + display.PrintErr(cmd, fmt.Errorf("error calling action: %w", err)) } - return nil + return display.PrintCmd(cmd, &respRelations{Data: data}) }) - - return display.Print(&resp, err, config.GetOutputFormat()) }, } - cmd.Flags().StringP(nameFlag, "n", "", "the database name") - cmd.Flags().StringP(ownerFlag, "o", "", "the database owner") - cmd.Flags().StringP(dbidFlag, "i", "", "the database id") - cmd.Flags().StringVarP(&action, actionNameFlag, "a", "", "the action name (required)") - authenticate = cmd.Flags().Bool("authenticate", false, "whether to authenticate the action call") + cmd.Flags().StringP(nameFlag, "n", "", "the target database schema name") + cmd.Flags().StringP(ownerFlag, "o", "", "the target database schema owner") + cmd.Flags().StringP(dbidFlag, "i", "", "the target database id") + cmd.Flags().StringVarP(&action, actionNameFlag, "a", "", "the target action name (required)") + cmd.Flags().BoolVar(&authenticate, "authenticate", false, "authenticate signals that the call is being made to a gateway and should be authenticated with the private key") cmd.MarkFlagRequired(actionNameFlag) return cmd diff --git a/cmd/kwil-cli/cmds/database/cmd.go b/cmd/kwil-cli/cmds/database/cmd.go index eabc8db40..743b0027d 100644 --- a/cmd/kwil-cli/cmds/database/cmd.go +++ b/cmd/kwil-cli/cmds/database/cmd.go @@ -8,8 +8,8 @@ var ( dbCmd = &cobra.Command{ Use: "database", Aliases: []string{"db"}, - Short: "manage databases", - Long: "Database is a command that contains subcommands for interacting with databases", + Short: "The database command is a parent command containing subcommands for interacting with databases.", + Long: "The database command is a parent command containing subcommands for interacting with databases.", } nonceOverride int64 diff --git a/cmd/kwil-cli/cmds/database/deploy.go b/cmd/kwil-cli/cmds/database/deploy.go index 2d5354953..3fd1a01fc 100644 --- a/cmd/kwil-cli/cmds/database/deploy.go +++ b/cmd/kwil-cli/cmds/database/deploy.go @@ -8,7 +8,7 @@ import ( "os" "github.com/kwilteam/kuneiform/kfparser" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/client" @@ -16,21 +16,32 @@ import ( "github.com/spf13/cobra" ) +var ( + deployLong = `Deploy a database schema to the target Kwil node. +A path to a file containing the database schema must be provided using the --path flag. + +Either a Kuneiform or a JSON file can be provided. The file type is determined by the --type flag. +By default, the file type is kf (Kuneiform). Pass --type json to deploy a JSON file.` + + deployExample = `# Deploy a database schema to the target Kwil node +kwil-cli database deploy --path ./schema.kf` +) + func deployCmd() *cobra.Command { var filePath string var fileType string cmd := &cobra.Command{ - Use: "deploy", - Short: "Deploy databases", - Args: cobra.NoArgs, + Use: "deploy", + Short: "Deploy a database schema to the target Kwil node.", + Long: deployLong, + Example: deployExample, + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - var txHash []byte - - err := common.DialClient(cmd.Context(), 0, func(ctx context.Context, cl *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, 0, func(ctx context.Context, cl common.Client, conf *config.KwilCliConfig) error { // read in the file file, err := os.Open(filePath) if err != nil { - return fmt.Errorf("failed to read file: %w", err) + return display.PrintErr(cmd, fmt.Errorf("failed to read file: %w", err)) } defer file.Close() @@ -40,22 +51,24 @@ func deployCmd() *cobra.Command { } else if fileType == "json" { db, err = UnmarshalJson(file) } else { - return fmt.Errorf("invalid file type: %s", fileType) + return display.PrintErr(cmd, fmt.Errorf("invalid file type: %s", fileType)) } if err != nil { - return fmt.Errorf("failed to unmarshal file: %w", err) + return display.PrintErr(cmd, fmt.Errorf("failed to unmarshal file: %w", err)) } - txHash, err = cl.DeployDatabase(ctx, db, client.WithNonce(nonceOverride)) - return err - }) + txHash, err := cl.DeployDatabase(ctx, db, client.WithNonce(nonceOverride)) + if err != nil { + return display.PrintErr(cmd, fmt.Errorf("failed to deploy database: %w", err)) + } - return display.Print(display.RespTxHash(txHash), err, config.GetOutputFormat()) + return display.PrintCmd(cmd, display.RespTxHash(txHash)) + }) }, } - cmd.Flags().StringVarP(&filePath, "path", "p", "", "Path to the database definition file (required)") - cmd.Flags().StringVarP(&fileType, "type", "t", "kf", "File type of the database definition file (kf or json). defaults to kf (kuneiform).") + cmd.Flags().StringVarP(&filePath, "path", "p", "", "path to the database definition file (required)") + cmd.Flags().StringVarP(&fileType, "type", "t", "kf", "file type of the database definition file (kf or json) - defaults to kf") cmd.MarkFlagRequired("path") return cmd } diff --git a/cmd/kwil-cli/cmds/database/drop.go b/cmd/kwil-cli/cmds/database/drop.go index 4a3b36fb9..8a9baa4eb 100644 --- a/cmd/kwil-cli/cmds/database/drop.go +++ b/cmd/kwil-cli/cmds/database/drop.go @@ -4,33 +4,42 @@ import ( "context" "fmt" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) +var ( + dropLong = `Drops a database from the connected network. + +The drop coommand will drop a database schema, and all of its data, from the connected network. +This will only work if the wallet address that signs the transaction is the owner of the database. + +Drop takes one argument: the name of the database to drop.` + + dropExample = `# Drop a database deployed by the current wallet named "mydb" +kwil-cli database drop mydb` +) + func dropCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "drop DB_NAME", - Short: "Drops a database", - Long: "Drops a database. Requires 1 argument: the name of the database to drop", - Args: cobra.ExactArgs(1), + Use: "drop ", + Short: "Drops a database from the connected network.", + Long: dropLong, + Example: dropExample, + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - var resp []byte - - err := common.DialClient(cmd.Context(), 0, func(ctx context.Context, cl *client.Client, conf *config.KwilCliConfig) error { - var _err error - resp, _err = cl.DropDatabase(ctx, args[0], client.WithNonce(nonceOverride)) - if _err != nil { - return fmt.Errorf("error dropping database: %w", _err) + return common.DialClient(cmd.Context(), cmd, 0, func(ctx context.Context, cl common.Client, conf *config.KwilCliConfig) error { + var err error + resp, err := cl.DropDatabase(ctx, args[0], client.WithNonce(nonceOverride)) + if err != nil { + return display.PrintErr(cmd, fmt.Errorf("error dropping database: %w", err)) } - return nil + return display.PrintCmd(cmd, display.RespTxHash(resp)) }) - - return display.Print(display.RespTxHash(resp), err, config.GetOutputFormat()) }, } return cmd diff --git a/cmd/kwil-cli/cmds/database/execute.go b/cmd/kwil-cli/cmds/database/execute.go index 8b9f1863d..788399e1b 100644 --- a/cmd/kwil-cli/cmds/database/execute.go +++ b/cmd/kwil-cli/cmds/database/execute.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/client" @@ -13,73 +13,70 @@ import ( "github.com/spf13/cobra" ) -func executeCmd() *cobra.Command { - var actionName string - - cmd := &cobra.Command{ - Use: "execute", - Short: "Execute a query", - Long: `Execute executes a query against the specified database. The query name is -specified as a required "--action" flag, and the query parameters as arguments. -In order to specify an parameter, you first need to specify the parameter name, then the parameter value, delimited by a colon. - -For example, if I have a query name "create_user" that takes two arguments: name and age. -I would specify the query as follows: +var ( + executeLong = `Execute an action against a database. -'name:satoshi' 'age:32' --action=create_user +The action name is specified as a required "--action" flag, and the action parameters as arguments. +In order to specify an action parameter, you first need to specify the parameter name, then the parameter value, delimited by a colon. -You specify the database to execute this against with the --name flag, and -the owner with the --owner flag. +For example, for action ` + "`" + `get_user($username)` + "`" + `, you would specify the action as follows: +` + "`" + `username:satoshi` + "`" + ` --action=get_user -You can also specify the database by passing the database id with the --dbid flag. +You can either specify the database to execute this against with the ` + "`" + `--name` + "`" + ` and ` + "`" + `--owner` + "`" + ` +flags, or you can specify the database by passing the database id with the ` + "`" + `--dbid` + "`" + ` flag. If a ` + "`" + `--name` + "`" + ` +flag is passed and no ` + "`" + `--owner` + "`" + ` flag is passed, the owner will be inferred from your configured wallet.` -For example: + executeExample = `# Executing the ` + "`" + `create_user($username, $age)` + "`" + ` action on the "mydb" database +kwil-cli database execute username:satoshi age:32 --action create_user --name mydb --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 -'name:satoshi' 'age:32' --action=create_user --name mydb --owner 0xAfFDC06cF34aFD7D5801A13d48C92AD39609901D +# Executing the ` + "`" + `create_user($username, $age)` + "`" + ` action on a database using a dbid +kwil-cli database execute username:satoshi age:32 --action create_user --dbid 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64` +) -OR +func executeCmd() *cobra.Command { + var actionName string -'name:satoshi' 'age:32' --dbid=x1234 --action=create_user `, + cmd := &cobra.Command{ + Use: "execute ...", + Short: "Execute an action against a database.", + Long: executeLong, + Example: executeExample, RunE: func(cmd *cobra.Command, args []string) error { - var resp []byte - - err := common.DialClient(cmd.Context(), 0, func(ctx context.Context, cl *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, 0, func(ctx context.Context, cl common.Client, conf *config.KwilCliConfig) error { dbId, err := getSelectedDbid(cmd, conf) if err != nil { - return fmt.Errorf("target database not properly specified: %w", err) + return display.PrintErr(cmd, fmt.Errorf("target database not properly specified: %w", err)) } lowerName := strings.ToLower(actionName) actionStructure, err := getAction(ctx, cl, dbId, lowerName) if err != nil { - return fmt.Errorf("error getting action: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error getting action: %w", err)) } inputs, err := GetInputs(args, actionStructure) if err != nil { - return fmt.Errorf("error getting inputs: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error getting inputs: %w", err)) } // Could actually just directly pass nonce to the client method, // but those methods don't need tx details in the inputs. - resp, err = cl.ExecuteAction(ctx, dbId, lowerName, inputs, client.WithNonce(nonceOverride)) + resp, err := cl.ExecuteAction(ctx, dbId, lowerName, inputs, client.WithNonce(nonceOverride)) if err != nil { - return fmt.Errorf("error executing database: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error executing database: %w", err)) } - return nil + return display.PrintCmd(cmd, display.RespTxHash(resp)) }) - - return display.Print(display.RespTxHash(resp), err, config.GetOutputFormat()) }, } - cmd.Flags().StringP(nameFlag, "n", "", "the database name") - cmd.Flags().StringP(ownerFlag, "o", "", "the database owner") - cmd.Flags().StringP(dbidFlag, "i", "", "the database id") + cmd.Flags().StringP(nameFlag, "n", "", "the target database name") + cmd.Flags().StringP(ownerFlag, "o", "", "the target database owner") + cmd.Flags().StringP(dbidFlag, "i", "", "the target database id") - cmd.Flags().StringVarP(&actionName, actionNameFlag, "a", "", "the action name (required)") + cmd.Flags().StringVarP(&actionName, actionNameFlag, "a", "", "the target action name (required)") cmd.MarkFlagRequired(actionNameFlag) return cmd diff --git a/cmd/kwil-cli/cmds/database/list.go b/cmd/kwil-cli/cmds/database/list.go index 4e55b8a8f..8df7898e3 100644 --- a/cmd/kwil-cli/cmds/database/list.go +++ b/cmd/kwil-cli/cmds/database/list.go @@ -3,43 +3,47 @@ package database import ( "context" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) +var ( + listLong = `List databases owned by a wallet. + +An owner can be specified with the --owner flag. If no owner is specified, the locally configured wallet is used.` + listExample = `# list databases owned by the wallet "0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64" +kwil-cli database list --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64` +) + func listCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "list", - Short: "List databases", - Long: `"List" lists the databases owned by a wallet. -A wallet can be specified with the --owner flag, otherwise the default wallet is used.`, + Use: "list", + Short: "List databases owned by a wallet.", + Long: listLong, + Example: listExample, Args: cobra.NoArgs, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - var resp *respDBList - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, func(ctx context.Context, client *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, conf *config.KwilCliConfig) error { owner, err := getSelectedOwner(cmd, conf) if err != nil { - return err + return display.PrintErr(cmd, err) } dbs, err := client.ListDatabases(ctx, owner) if err != nil { - return err + return display.PrintErr(cmd, err) } - resp = &respDBList{ + resp := &respDBList{ Databases: dbs, Owner: owner, } - return nil + return display.PrintCmd(cmd, resp) }) - - return display.Print(resp, err, config.GetOutputFormat()) }, } diff --git a/cmd/kwil-cli/cmds/database/message_test.go b/cmd/kwil-cli/cmds/database/message_test.go index 1d7cfc858..24f1e6a4c 100644 --- a/cmd/kwil-cli/cmds/database/message_test.go +++ b/cmd/kwil-cli/cmds/database/message_test.go @@ -1,7 +1,7 @@ package database import ( - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/core/client" "github.com/kwilteam/kwil-db/core/types/transactions" ) diff --git a/cmd/kwil-cli/cmds/database/query.go b/cmd/kwil-cli/cmds/database/query.go index b353549b1..6333b33ef 100644 --- a/cmd/kwil-cli/cmds/database/query.go +++ b/cmd/kwil-cli/cmds/database/query.go @@ -4,43 +4,52 @@ import ( "context" "fmt" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) +var ( + queryLong = `Query a database using an ad-hoc SQL SELECT statement. + +Requires a SQL SELECT statement as an argument. + +You can either specify the database to execute this against with the ` + "`" + `--name` + "`" + ` and ` + "`" + `--owner` + "`" + ` +flags, or you can specify the database by passing the database id with the ` + "`" + `--dbid` + "`" + ` flag. If a ` + "`" + `--name` + "`" + ` +flag is passed and no ` + "`" + `--owner` + "`" + ` flag is passed, the owner will be inferred from your configured wallet.` + + queryExample = `# Querying the "users" table in the "mydb" database +kwil-cli database query "SELECT * FROM users WHERE age > 25" --name mydb --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64` +) + func queryCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "query QUERY_TEXT", - Short: "Queries a database", - Long: "Queries a database. Requires 1 argument: the query text.", - Args: cobra.ExactArgs(1), + Use: `query `, + Short: "Query a database using an ad-hoc SQL SELECT statement.", + Long: queryLong, + Example: queryExample, + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - var resp respRelations - - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, - func(ctx context.Context, client *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, + func(ctx context.Context, client common.Client, conf *config.KwilCliConfig) error { dbid, err := getSelectedDbid(cmd, conf) if err != nil { - return fmt.Errorf("target database not properly specified: %w", err) + return display.PrintErr(cmd, fmt.Errorf("target database not properly specified: %w", err)) } - resp.Data, err = client.Query(ctx, dbid, args[0]) + data, err := client.Query(ctx, dbid, args[0]) if err != nil { - return fmt.Errorf("error querying database: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error querying database: %w", err)) } - return nil + return display.PrintCmd(cmd, &respRelations{Data: data}) }) - - return display.Print(&resp, err, config.GetOutputFormat()) }, } - cmd.Flags().StringP(nameFlag, "n", "", "the database name") - cmd.Flags().StringP(ownerFlag, "o", "", "the database owner") - cmd.Flags().StringP(dbidFlag, "i", "", "the database id") + cmd.Flags().StringP(nameFlag, "n", "", "the target database name") + cmd.Flags().StringP(ownerFlag, "o", "", "the target database owner") + cmd.Flags().StringP(dbidFlag, "i", "", "the target database id") return cmd } diff --git a/cmd/kwil-cli/cmds/database/read_schema.go b/cmd/kwil-cli/cmds/database/read_schema.go index b1859976f..a3392b75c 100644 --- a/cmd/kwil-cli/cmds/database/read_schema.go +++ b/cmd/kwil-cli/cmds/database/read_schema.go @@ -4,41 +4,52 @@ import ( "context" "fmt" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) // TODO: @brennan: make the way this prints out the metadata more readable +var ( + readSchemaLong = `Read schema is used to view the details of a deployed database schema. + + You can either specify the database to execute this against with the ` + "`" + `--name` + "`" + ` and ` + "`" + `--owner` + "`" + ` + flags, or you can specify the database by passing the database id with the ` + "`" + `--dbid` + "`" + ` flag. If a ` + "`" + `--name` + "`" + ` + flag is passed and no ` + "`" + `--owner` + "`" + ` flag is passed, the owner will be inferred from your configured wallet.` + + readSchemaExample = `# Reading the schema of the "mydb" database, owned by 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 +kwil-cli database read-schema --name mydb --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64` +) + func readSchemaCmd() *cobra.Command { var cmd = &cobra.Command{ - Use: "read-schema", - Short: "Read schema is used to view the details of a database. It requires a database name", - Long: "", - Args: cobra.NoArgs, + Use: "read-schema", + Short: "Read schema is used to view the details of a deployed database schema.", + Long: readSchemaLong, + Example: readSchemaExample, + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - var resp respSchema - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, func(ctx context.Context, client *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, conf *config.KwilCliConfig) error { dbid, err := getSelectedDbid(cmd, conf) if err != nil { - return fmt.Errorf("you must specify either a database name with the --name, or a database id with the --dbid flag") + + return display.PrintErr(cmd, fmt.Errorf("you must specify either a database name with the --name, or a database id with the --dbid flag")) } - resp.Schema, err = client.GetSchema(ctx, dbid) + schema, err := client.GetSchema(ctx, dbid) if err != nil { - return fmt.Errorf("error getting schema: %w", err) + + return display.PrintErr(cmd, fmt.Errorf("error getting schema: %w", err)) } - return err - }) - return display.Print(&resp, err, config.GetOutputFormat()) + return display.PrintCmd(cmd, &respSchema{Schema: schema}) + }) }, } - cmd.Flags().StringP(nameFlag, "n", "", "The name of the database to view") - cmd.Flags().StringP(ownerFlag, "o", "", "The owner of the database to view(optional, defaults to the your account)") - cmd.Flags().StringP(dbidFlag, "i", "", "The database id of the database to view(optional, defaults to the your account)") + cmd.Flags().StringP(nameFlag, "n", "", "the target database name") + cmd.Flags().StringP(ownerFlag, "o", "", "the target database owner") + cmd.Flags().StringP(dbidFlag, "i", "", "the target database id") return cmd } diff --git a/cmd/kwil-cli/cmds/root.go b/cmd/kwil-cli/cmds/root.go new file mode 100644 index 000000000..acf55e54c --- /dev/null +++ b/cmd/kwil-cli/cmds/root.go @@ -0,0 +1,41 @@ +package cmds + +import ( + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/common/version" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/configure" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/database" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/utils" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" + "github.com/spf13/cobra" +) + +func NewRootCmd() *cobra.Command { + config.BindGlobalFlags(rootCmd.PersistentFlags()) + display.BindOutputFormatFlag(rootCmd) + display.BindSilenceFlag(rootCmd) + common.BindAssumeYesFlag(rootCmd) + + rootCmd.AddCommand( + configure.NewCmdConfigure(), + database.NewCmdDatabase(), + utils.NewCmdUtils(), + version.NewVersionCmd(), + ) + + return rootCmd +} + +var rootCmd = &cobra.Command{ + Use: "kwil-cli", + Short: "Command line interface for using Kwil databases.", + Long: `Command line interface for using Kwil databases. + +The Kwil CLI is a command line interface for interacting with Kwil databases. It can be used to deploy, update, and query databases. It can also be used to generate documentation for Kwil databases. + +The Kwil CLI can be configured with a persistent configuration file. This file can be configured with the 'kwil-cli configure' command. The Kwil CLI will look for a configuration file at ` + "`" + `$HOME/.kwil-cli/config.json` + "`" + `. + `, + SilenceUsage: true, + DisableAutoGenTag: true, +} diff --git a/cmd/kwil-cli/cmds/utils/auth.go b/cmd/kwil-cli/cmds/utils/auth.go index 993ef7346..bd37a17f8 100644 --- a/cmd/kwil-cli/cmds/utils/auth.go +++ b/cmd/kwil-cli/cmds/utils/auth.go @@ -4,82 +4,67 @@ import ( "context" "fmt" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" - "github.com/kwilteam/kwil-db/core/crypto/auth" - "github.com/manifoldco/promptui" + "github.com/kwilteam/kwil-db/core/gatewayclient" "github.com/spf13/cobra" ) -var authCmdDesc = `KGW provider provides ways to protect data privacy, by using cookie authentication. -This command will prompt for a signature and return a authenticated cookie for -future API calls. -KGW authentication is not part of Kwild API. +var authCmdDesc = `Authenticate with a Kwil Gateway using a private key. + +The ` + `"` + `authenticate` + `"` + ` command will prompt you to sign a challenge from the Kwil Gateway. It +will store the returned auth cookie in ` + `"` + `~/.kwil-cli/auth` + `"` + ` for future use. + +The Kwil CLI automatically handles authentication and re-authentication, however this tool +can be used to manually authenticate to a Kwil Gateway. ` +var authCmdExample = `# Authenticate to a Kwil Gateway + +kwil-cli utils authenticate` + // kgwAuthnCmd is the command to authenticate to a KGW provider. // This is not part of Kwil API. func kgwAuthnCmd() *cobra.Command { var cmd = &cobra.Command{ - Use: "kgw-authn", - Short: "kgw-authn is used to do authentication with a KGW provider", // or sass provider? - Long: authCmdDesc, + Use: "authenticate", + Short: "Authenticate with a Kwil Gateway using a private key.", + Long: authCmdDesc, + Example: authCmdExample, + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - err := common.DialClient(cmd.Context(), 0, - func(ctx context.Context, client *client.Client, - cfg *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, common.UsingGateway, + func(ctx context.Context, client common.Client, cfg *config.KwilCliConfig) error { if cfg.PrivateKey == nil { - return fmt.Errorf("private key not provided") + return display.PrintErr(cmd, fmt.Errorf("private key not provided")) } - signer := auth.EthPersonalSigner{Key: *cfg.PrivateKey} - if cfg.GrpcURL == "" { - return fmt.Errorf("provider url not provided") + gatewayClient, ok := client.(*gatewayclient.GatewayClient) + if !ok { + return display.PrintErr(cmd, fmt.Errorf("client is not a gateway client. this is an internal bug")) } - address, err := auth.EthSecp256k1Authenticator{}.Identifier(signer.Identity()) + err := gatewayClient.Authenticate(ctx) if err != nil { - return fmt.Errorf("get address: %w", err) + return display.PrintErr(cmd, fmt.Errorf("authentication failed: %w", err)) } - cookie, err := client.GatewayAuthenticate(ctx, promptMessage) - if err != nil { - return fmt.Errorf("KGW authenticate: %w", err) + // retrieve the cookie and persist it + cookie, found := gatewayClient.GetAuthCookie() + if !found { + return display.PrintErr(cmd, fmt.Errorf("authentication failed: cookie could not be found")) } - err = common.SaveAuthInfo(common.KGWAuthTokenFilePath(), - address, cookie) + err = common.SaveCookie(common.KGWAuthTokenFilePath(), gatewayClient.Signer.Identity(), cookie) if err != nil { - return fmt.Errorf("save auth token: %w", err) + return display.PrintErr(cmd, fmt.Errorf("save cookie: %w", err)) } - return nil + return display.PrintCmd(cmd, display.RespString("Success")) }) - - return display.Print(respStr("Success"), err, config.GetOutputFormat()) }, } return cmd } - -// promptMessage prompts the user to sign a message. Return an error if user -// declines to sign. -func promptMessage(msg string) error { - // display the message to user - fmt.Println(msg) - - prompt := promptui.Prompt{ - Label: "Do you want to sign this message?", - IsConfirm: true, - } - - _, err := prompt.Run() - if err != nil { - return fmt.Errorf("you declined to sign") - } - - return nil -} diff --git a/cmd/kwil-cli/cmds/utils/chain_id.go b/cmd/kwil-cli/cmds/utils/chain_id.go index c9d2442af..ddfdcd0dd 100644 --- a/cmd/kwil-cli/cmds/utils/chain_id.go +++ b/cmd/kwil-cli/cmds/utils/chain_id.go @@ -3,28 +3,30 @@ package utils import ( "context" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" - "github.com/kwilteam/kwil-db/core/types" "github.com/spf13/cobra" ) +var ( + chainInfoLong = `Display information about the connected Kwil network.` +) + func chainInfoCmd() *cobra.Command { var cmd = &cobra.Command{ Use: "chain-info", - Short: "chain-info is used to query the kwil provider info", - Long: "", + Short: chainInfoLong, + Long: chainInfoLong, RunE: func(cmd *cobra.Command, args []string) error { - var chainInfo *types.ChainInfo - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, func(ctx context.Context, client *client.Client, cfg *config.KwilCliConfig) error { - var err error - chainInfo, err = client.ChainInfo(ctx) - return err - }) + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, cfg *config.KwilCliConfig) error { + chainInfo, err := client.ChainInfo(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } - return display.Print(&respChainInfo{chainInfo}, err, config.GetOutputFormat()) + return display.PrintCmd(cmd, &respChainInfo{Info: chainInfo}) + }) }, } diff --git a/cmd/kwil-cli/cmds/utils/message.go b/cmd/kwil-cli/cmds/utils/message.go index 622123305..c0ccd30d2 100644 --- a/cmd/kwil-cli/cmds/utils/message.go +++ b/cmd/kwil-cli/cmds/utils/message.go @@ -12,35 +12,12 @@ import ( "github.com/kwilteam/kwil-db/core/types/transactions" ) -// respStr represents a string in cli -type respStr string - -func (s respStr) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Message string `json:"message"` - }{ - Message: string(s), - }) -} - -func (s respStr) MarshalText() ([]byte, error) { - return []byte(s), nil -} - type respChainInfo struct { Info *types.ChainInfo } func (r *respChainInfo) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - ChainID string `json:"chain_id"` - BlockHeight uint64 `json:"block_height"` - BlockHash string `json:"block_hash"` - }{ - ChainID: r.Info.ChainID, - BlockHeight: r.Info.BlockHeight, - BlockHash: r.Info.BlockHash, - }) + return json.Marshal(r.Info) } func (r *respChainInfo) MarshalText() ([]byte, error) { @@ -86,8 +63,7 @@ func (r *respTxQuery) MarshalText() ([]byte, error) { msg := fmt.Sprintf(`Transaction ID: %s Status: %s Height: %d -Log: %s -`, +Log: %s`, hex.EncodeToString(r.Msg.Hash), status, r.Msg.Height, diff --git a/cmd/kwil-cli/cmds/utils/message_test.go b/cmd/kwil-cli/cmds/utils/message_test.go index 88088ea97..f86cf221b 100644 --- a/cmd/kwil-cli/cmds/utils/message_test.go +++ b/cmd/kwil-cli/cmds/utils/message_test.go @@ -2,32 +2,16 @@ package utils import ( "encoding/hex" - "errors" "math/big" - "testing" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/kwilteam/kwil-db/core/crypto" "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" - - "github.com/stretchr/testify/assert" ) -func Test_respStr(t *testing.T) { - s := respStr("pong") - - bs, err := s.MarshalText() - assert.NoError(t, err) - assert.Equal(t, "pong", string(bs)) - - sb, err := s.MarshalJSON() - assert.NoError(t, err) - assert.Equal(t, `{"message":"pong"}`, string(sb)) -} - func Example_respChainInfo_text() { display.Print(&respChainInfo{ &types.ChainInfo{ @@ -61,33 +45,6 @@ func Example_respChainInfo_json() { // } } -func Example_respStr_text() { - display.Print(respStr("pong"), nil, "text") - // Output: - // pong -} - -func Example_respStr_json() { - display.Print(respStr("pong"), nil, "json") - // Output: - // { - // "result": { - // "message": "pong" - // }, - // "error": "" - // } -} - -func Example_respStr_json_withError() { - err := errors.New("an error") - display.Print(respStr("pong"), err, "json") - // Output: - // { - // "result": "", - // "error": "an error" - // } -} - func getExampleTxQueryResponse() *transactions.TcTxQueryResponse { secp256k1EpSigHex := "cb3fed7f6ff36e59054c04a831b215e514052753ee353e6fe31d4b4ef736acd6155127db555d3006ba14fcb4c79bbad56c8e63b81a9896319bb053a9e253475800" secp256k1EpSigBytes, _ := hex.DecodeString(secp256k1EpSigHex) diff --git a/cmd/kwil-cli/cmds/utils/ping.go b/cmd/kwil-cli/cmds/utils/ping.go index 36723940d..0a2414ab9 100644 --- a/cmd/kwil-cli/cmds/utils/ping.go +++ b/cmd/kwil-cli/cmds/utils/ping.go @@ -3,27 +3,26 @@ package utils import ( "context" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) func pingCmd() *cobra.Command { var cmd = &cobra.Command{ Use: "ping", - Short: "Ping is used to ping the kwil provider endpoint", - Long: "", + Short: "Ping the kwil provider endpoint. If successful, returns 'pong'.", + Long: "Ping the kwil provider endpoint. If successful, returns 'pong'.", RunE: func(cmd *cobra.Command, args []string) error { - var res string - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, func(ctx context.Context, client *client.Client, cfg *config.KwilCliConfig) error { - var _err error - res, _err = client.Ping(ctx) - return _err - }) + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, cfg *config.KwilCliConfig) error { + res, err := client.Ping(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } - return display.Print(respStr(res), err, config.GetOutputFormat()) + return display.PrintCmd(cmd, display.RespString(res)) + }) }, } diff --git a/cmd/kwil-cli/cmds/utils/printConfig.go b/cmd/kwil-cli/cmds/utils/printConfig.go index b325f46bf..0f3070118 100644 --- a/cmd/kwil-cli/cmds/utils/printConfig.go +++ b/cmd/kwil-cli/cmds/utils/printConfig.go @@ -1,7 +1,7 @@ package utils import ( - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" "github.com/spf13/cobra" ) @@ -9,15 +9,15 @@ import ( func printConfigCmd() *cobra.Command { var cmd = &cobra.Command{ Use: "print-config", - Short: "Print the current configuration", - Long: "", + Short: "Print the current CLI configuration.", + Long: "Print the current CLI configuration.", RunE: func(cmd *cobra.Command, args []string) error { cfg, err := config.LoadCliConfig() if err != nil { - return err + return display.PrintErr(cmd, err) } - return display.Print(&respKwilCliConfig{cfg}, nil, config.GetOutputFormat()) + return display.PrintCmd(cmd, &respKwilCliConfig{cfg: cfg}) }, } diff --git a/cmd/kwil-cli/cmds/utils/tx_query.go b/cmd/kwil-cli/cmds/utils/tx_query.go index 130cbf9e3..53c33ad00 100644 --- a/cmd/kwil-cli/cmds/utils/tx_query.go +++ b/cmd/kwil-cli/cmds/utils/tx_query.go @@ -5,43 +5,34 @@ import ( "encoding/hex" "fmt" - "github.com/kwilteam/kwil-db/cmd/internal/display" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) func txQueryCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "query-tx TX_ID", - Short: "Queries a transaction from the blockchain, TX_ID is hex encoded.", - Long: longTxQueryDesc, + Use: "query-tx ", + Short: "Queries a transaction from the blockchain. Requires 1 argument: the hex encoded transaction id.", + Long: `Queries a transaction from the blockchain. Requires 1 argument: the hex encoded transaction id.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - var resp respTxQuery - err := common.DialClient(cmd.Context(), common.WithoutPrivateKey, func(ctx context.Context, client *client.Client, conf *config.KwilCliConfig) error { + return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, conf *config.KwilCliConfig) error { txHash, err := hex.DecodeString(args[0]) if err != nil { - return fmt.Errorf("error decoding transaction id: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error decoding transaction id: %w", err)) } - resp.Msg, err = client.TxQuery(ctx, txHash) + msg, err := client.TxQuery(ctx, txHash) if err != nil { - return fmt.Errorf("error querying transaction: %w", err) + return display.PrintErr(cmd, fmt.Errorf("error querying transaction: %w", err)) } - return nil + return display.PrintCmd(cmd, &respTxQuery{Msg: msg}) }) - return display.Print(&resp, err, config.GetOutputFormat()) }, } return cmd } - -const longTxQueryDesc = ` -Queries a transaction from the blockchain. Requires 1 argument: the transaction id. - -The transaction id is a hex encoded string. -` diff --git a/cmd/kwil-cli/cmds/utils/utils.go b/cmd/kwil-cli/cmds/utils/utils.go index 6367fc21d..24faf1a34 100644 --- a/cmd/kwil-cli/cmds/utils/utils.go +++ b/cmd/kwil-cli/cmds/utils/utils.go @@ -8,8 +8,8 @@ func NewCmdUtils() *cobra.Command { var cmd = &cobra.Command{ Use: "utils", Aliases: []string{"common"}, - Short: "Various utility commands.", - Long: "", + Short: "Various CLI utility commands.", + Long: "Various CLI utility commands.", } cmd.AddCommand( diff --git a/cmd/kwil-cli/config/flags.go b/cmd/kwil-cli/config/flags.go index 7e399bba8..3bb120828 100644 --- a/cmd/kwil-cli/config/flags.go +++ b/cmd/kwil-cli/config/flags.go @@ -1,7 +1,6 @@ package config import ( - "errors" "os" "path/filepath" @@ -49,55 +48,16 @@ func init() { defaultConfigFile = filepath.Join(configPath, defaultConfigFileName) } -// OutputFormat is the format for command output -// It implements the pflag.Value interface -type OutputFormat string - -// String implements the Stringer interface -// NOTE: cannot use the pointer receiver here -func (o OutputFormat) String() string { - return string(o) -} - -func (o *OutputFormat) Set(s string) error { - switch s { - case "text", "json": - *o = OutputFormat(s) - return nil - default: - return errors.New(`invalid output format, must be either "text" or "json`) - } -} - -func (o *OutputFormat) Type() string { - return "output format" -} - -const ( - OutputFormatText OutputFormat = "text" - OutputFormatJSON OutputFormat = "json" - - DefaultOutputFormat = OutputFormatText -) - -var outputFormat = DefaultOutputFormat - func BindGlobalFlags(fs *pflag.FlagSet) { // Bind flags to environment variables - fs.String(globalPrivateKeyFlag, cliCfg.PrivateKey, "The private key of the wallet that will be used for signing") - fs.String(globalProviderFlag, cliCfg.GrpcURL, "The Kwil provider endpoint") - fs.String(globalChainIDFlag, cliCfg.ChainID, "The expected/intended Kwil Chain ID") - fs.String(globalTlsCertFlag, cliCfg.TLSCertFile, "The path to the TLS certificate, this is required if the kwil provider endpoint is using TLS") - fs.Var(&outputFormat, globalOutputFlag, "the format for command output, either 'text' or 'json'") + fs.String(globalPrivateKeyFlag, cliCfg.PrivateKey, "the private key of the wallet that will be used for signing") + fs.String(globalProviderFlag, cliCfg.GrpcURL, "the Kwil provider gRPC endpoint") + fs.String(globalChainIDFlag, cliCfg.ChainID, "the expected/intended Kwil Chain ID") + fs.String(globalTlsCertFlag, cliCfg.TLSCertFile, "the path to the TLS certificate (if the provider endpoint is using TLS)") // Bind flags to viper, named by the flag name viper.BindPFlag(viperPrivateKeyName, fs.Lookup(globalPrivateKeyFlag)) viper.BindPFlag(viperProviderName, fs.Lookup(globalProviderFlag)) viper.BindPFlag(viperChainID, fs.Lookup(globalChainIDFlag)) viper.BindPFlag(viperTlsCertName, fs.Lookup(globalTlsCertFlag)) - viper.BindPFlag(viperOutputName, fs.Lookup(globalOutputFlag)) -} - -func GetOutputFormat() string { - return outputFormat.String() } diff --git a/cmd/kwil-cli/generate/gen.go b/cmd/kwil-cli/generate/gen.go new file mode 100644 index 000000000..174c7403f --- /dev/null +++ b/cmd/kwil-cli/generate/gen.go @@ -0,0 +1,23 @@ +package main + +import ( + "flag" + + "github.com/kwilteam/kwil-db/cmd/common/generate" + "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds" +) + +var ( + out string +) + +func main() { + flag.StringVar(&out, "out", "./dist", "output directory") + + flag.Parse() + + err := generate.WriteDocs(cmds.NewRootCmd(), out) + if err != nil { + panic(err) + } +} diff --git a/cmd/kwil-cli/main.go b/cmd/kwil-cli/main.go index 35d021154..fa3e08eb1 100755 --- a/cmd/kwil-cli/main.go +++ b/cmd/kwil-cli/main.go @@ -1,39 +1,20 @@ package main import ( + "fmt" "os" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/configure" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/database" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/system" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/utils" - "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" - "github.com/spf13/cobra" + "github.com/kwilteam/kwil-db/cmd/common/display" + root "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds" ) -var rootCmd = &cobra.Command{ - Use: "kwil-cli", - Short: "kwil command line interface", - Long: "kwil-cli allows you to interact with the Kwil", - SilenceUsage: true, - DisableAutoGenTag: true, -} - -func execute() error { - rootCmd.AddCommand( - configure.NewCmdConfigure(), - database.NewCmdDatabase(), - utils.NewCmdUtils(), - system.NewVersionCmd(), - ) - - return rootCmd.Execute() -} - func main() { - config.BindGlobalFlags(rootCmd.PersistentFlags()) - - if err := execute(); err != nil { + root := root.NewRootCmd() + if err := root.Execute(); err != nil { + err2 := display.PrintErr(root, err) + if err2 != nil { + fmt.Println(err2) + } os.Exit(-1) } } diff --git a/cmd/kwild/config/config.go b/cmd/kwild/config/config.go index 8045e421d..72fb4c95e 100644 --- a/cmd/kwild/config/config.go +++ b/cmd/kwild/config/config.go @@ -4,16 +4,22 @@ package config import ( "bytes" + "encoding" "encoding/hex" "fmt" "os" "path/filepath" + "reflect" "strings" "time" "github.com/kwilteam/kwil-db/core/crypto" "github.com/kwilteam/kwil-db/core/log" + "github.com/mitchellh/mapstructure" + toml "github.com/pelletier/go-toml/v2" + merge "dario.cat/mergo" + "github.com/spf13/pflag" "github.com/spf13/viper" ) @@ -95,9 +101,9 @@ type P2PConfig struct { // AllowDuplicateIP permits peers connecting from the same IP. AllowDuplicateIP bool `mapstructure:"allow_duplicate_ip"` // HandshakeTimeout is the peer connection handshake timeout. - HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"` + HandshakeTimeout Duration `mapstructure:"handshake_timeout"` // DialTimeout is the peer connection establishment timeout. - DialTimeout time.Duration `mapstructure:"dial_timeout"` + DialTimeout Duration `mapstructure:"dial_timeout"` } type MempoolConfig struct { @@ -118,25 +124,25 @@ type MempoolConfig struct { type ConsensusConfig struct { // TimeoutPropose is how long to wait for a proposal block before prevoting // nil. - TimeoutPropose time.Duration `mapstructure:"timeout_propose"` + TimeoutPropose Duration `mapstructure:"timeout_propose"` // TimeoutPrevote is how long to wait after receiving +2/3 prevotes for // “anything” (i.e. not a single block or nil). - TimeoutPrevote time.Duration `mapstructure:"timeout_prevote"` + TimeoutPrevote Duration `mapstructure:"timeout_prevote"` // TimeoutPrecommit is how long we wait after receiving +2/3 precommits for // “anything” (i.e. not a single block or nil). - TimeoutPrecommit time.Duration `mapstructure:"timeout_precommit"` + TimeoutPrecommit Duration `mapstructure:"timeout_precommit"` // TimeoutCommit is how long to wait after committing a block, before // starting on the new height (this gives us a chance to receive some more // precommits, even though we already have +2/3). - TimeoutCommit time.Duration `mapstructure:"timeout_commit"` + TimeoutCommit Duration `mapstructure:"timeout_commit"` } type StateSyncConfig struct { - Enable bool `mapstructure:"enable"` - TempDir string `mapstructure:"temp_dir"` - RPCServers []string `mapstructure:"rpc_servers"` - DiscoveryTime time.Duration `mapstructure:"discovery_time"` - ChunkRequestTimeout time.Duration `mapstructure:"chunk_request_timeout"` + Enable bool `mapstructure:"enable"` + TempDir string `mapstructure:"temp_dir"` + RPCServers []string `mapstructure:"rpc_servers"` + DiscoveryTime Duration `mapstructure:"discovery_time"` + ChunkRequestTimeout Duration `mapstructure:"chunk_request_timeout"` } type ChainConfig struct { @@ -150,6 +156,45 @@ type ChainConfig struct { Consensus *ConsensusConfig `mapstructure:"consensus"` } +// toml package does not support time.Duration, since time is not part of TOML spec +// Fix can be found here: https://github.com/pelletier/go-toml/issues/767 +// It implements both the TextUnmarshaler interface and the pflag.Value interface +type Duration time.Duration + +var _ encoding.TextUnmarshaler = (*Duration)(nil) +var _ pflag.Value = (*Duration)(nil) + +func (d *Duration) UnmarshalText(b []byte) error { + x, err := time.ParseDuration(string(b)) + if err != nil { + return err + } + *d = Duration(x) + return nil +} + +func (d *Duration) String() string { + return time.Duration(*d).String() +} + +func (d *Duration) Type() string { + return "duration" +} + +func (d *Duration) Set(s string) error { + x, err := time.ParseDuration(s) + if err != nil { + return err + } + *d = Duration(x) + return nil +} + +// Merge merges b onto a, overwriting any fields in a that are also set in b. +func (a *KwildConfig) Merge(b *KwildConfig) error { + return merge.MergeWithOverwrite(a, b) +} + func defaultMoniker() string { moniker, err := os.Hostname() if err != nil { @@ -158,89 +203,191 @@ func defaultMoniker() string { return moniker } -func (cfg *KwildConfig) LoadKwildConfig() error { - var err error - cfg.RootDir, err = ExpandPath(cfg.RootDir) +// GetCfg gets the kwild config +// It has the following precedence (low to high): +// 1. Default +// 2. Config file +// 3. Env vars +// 4. Command line flags +// It takes one argument, which is the config generated from the command line flags. +func GetCfg(flagCfg *KwildConfig) (*KwildConfig, error) { + /* + the process here is: + 1. identify the root dir. This requires reading in the env and command line flags + to see if they specify a root dir (since they take precedence over the config file). + If no root dir is specified from these, then use the default root dir. + 2. Read in the config file, if it exists, and merge it into the default config. + 3. Merge in the env config. + 4. Merge in the flag config. + */ + + // 1. identify the root dir + cfg := DefaultConfig() + rootDir := cfg.RootDir + + // read in env config + envCfg, err := LoadEnvConfig() if err != nil { - return fmt.Errorf("failed to expand root directory \"%v\": %v", cfg.RootDir, err) + return nil, fmt.Errorf("failed to load env config: %w", err) + } + if envCfg.RootDir != "" { + rootDir = envCfg.RootDir } - fmt.Printf("kwild starting with root directory \"%v\"\n", cfg.RootDir) + if flagCfg.RootDir != "" { + rootDir = flagCfg.RootDir + } - cfgFile := filepath.Join(cfg.RootDir, ConfigFileName) - err = cfg.ParseConfig(cfgFile) // viper magic here + // expand the root dir + rootDir, err = ExpandPath(rootDir) if err != nil { - return fmt.Errorf("failed to parse config file: %v", err) + return nil, fmt.Errorf("failed to expand root directory \"%v\": %v", rootDir, err) + } + + // make sure the root dir exists + err = os.MkdirAll(rootDir, 0755) + if err != nil { + return nil, fmt.Errorf("failed to create root directory \"%v\": %v", rootDir, err) + } + + // 2. Read in the config file + // read in config file and merge into default config + fileCfg, err := LoadConfigFile(filepath.Join(rootDir, ConfigFileName)) + if err == nil { + // merge in config file + err2 := cfg.Merge(fileCfg) + if err2 != nil { + return nil, fmt.Errorf("failed to merge config file: %w", err2) + } + } else if err != ErrConfigFileNotFound { + return nil, fmt.Errorf("failed to load config file: %w", err) } + // 3. Merge in the env config + // merge in env config + err = cfg.Merge(envCfg) + if err != nil { + return nil, fmt.Errorf("failed to merge env config: %w", err) + } + + // 4. Merge in the flag config + // merge in flag config + err = cfg.Merge(flagCfg) + if err != nil { + return nil, fmt.Errorf("failed to merge flag config: %w", err) + } + + cfg.RootDir = rootDir + cfg.sanitizeCfgPaths() cfg.configureCerts() - if cfg.ChainCfg.Moniker == "" { cfg.ChainCfg.Moniker = defaultMoniker() } - return nil + return cfg, nil } -func fileExists(path string) bool { - _, err := os.Stat(path) - return !os.IsNotExist(err) -} +// LoadConfig reads a config.toml at the given path and returns a KwilConfig. +// If the file does not exist, it will return an ErrConfigFileNotFound error. +func LoadConfigFile(configPath string) (*KwildConfig, error) { + cfgFilePath, err := filepath.Abs(configPath) + if err != nil { + return nil, fmt.Errorf("failed to get absolute path of config file: %v due to error: %v", configPath, err) + } -func (cfg *KwildConfig) ParseConfig(cfgFile string) error { - /* - Lots of Viper magic here, but the gist is: - We want to be able to set config values via - - flags - - environment variables - - config file - - default values - - for env variables support: - Requirement is, we need to be able to config from env variables with a prefix "KWILD_" - - It can be done 2 ways: - 1. AutomaticEnv: off mode - - This will not bind env variables to config values automatically - - We need to manually bind env variables to config values (this is what we are doing currently) - - As we bound flags to viper, viper is already aware of the config structure mapping, - so we can explicitly call viper.BindEnv() on all the keys in viper.AllKeys() - - else we would have to reflect on the config structure and bind env variables to config values - - 2. AutomaticEnv: on mode - - This is supposed to automatically bind env variables to config values - (but it doesn't work without doing a bit more work from our side) - - One way to make this work is add default values using either viper.SetDefault() for all the config values - or can do viper.MergeConfig() - - Serializing is really painful as cometbft has a field which is using map though its deprecated. - which prevents us from doing the AutomaticEnv binding - Issues referencing the issues (or) correct usage of AutomaticEnv: https://github.com/spf13/viper/issues/188 - For now, we are going with the first approach - - Note: - The order of preference of various modes of config supported by viper is: - explicit call to Set > flags > env variables > config file > default values - */ - for _, key := range viper.AllKeys() { - envKey := "KWILD_" + strings.ToUpper(strings.ReplaceAll(key, ".", "_")) - viper.BindEnv(key, envKey) + if !fileExists(cfgFilePath) { + return nil, ErrConfigFileNotFound } - if fileExists(cfgFile) { - fmt.Println("Loading config from: ", cfgFile) - viper.SetConfigFile(cfgFile) - if err := viper.ReadInConfig(); err != nil { - return fmt.Errorf("reading config: %v", err) - } - } else { - fmt.Printf("Config file %s not found. Using default settings.\n", cfgFile) + bts, err := os.ReadFile(cfgFilePath) + if err != nil { + return nil, fmt.Errorf("failed to read config file: %v", err) } - if err := viper.Unmarshal(cfg); err != nil { - return fmt.Errorf("decoding config: %v", err) + // unmarshal toml to maps + var cfg map[string]interface{} + err = toml.Unmarshal(bts, &cfg) + if err != nil { + return nil, fmt.Errorf("failed to parse config file: %v", err) } - return nil + + // convert mapstructure toml to KwilConfig + var kwilCfg KwildConfig + + mapDecoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc( + // func to decode string to Duration + func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(Duration(time.Duration(5))) { + return data, nil + } + + // Convert it by parsing + dur, err := time.ParseDuration(data.(string)) + if err != nil { + return nil, err + } + + return Duration(dur), nil + }, + // func to decode string to []string{} if the field is of type []string + // AFAICT this is only used for statesync rpc servers, which while not released, + // we do have some tooling for it + func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + + if t != reflect.TypeOf([]string{}) { + return data, nil + } + + // parse comma separated string to []string + return strings.Split(data.(string), ","), nil + }, + ), + Result: &kwilCfg, + }) + if err != nil { + return nil, fmt.Errorf("failed to create mapstructure decoder: %v", err) + } + + err = mapDecoder.Decode(cfg) + if err != nil { + return nil, fmt.Errorf("failed to convert config file: %v", err) + } + + return &kwilCfg, nil +} + +// LoadEnvConfig loads a config from environment variables. +func LoadEnvConfig() (*KwildConfig, error) { + viper.SetEnvPrefix("KWILD") + viper.AutomaticEnv() + + var cfg KwildConfig + if err := viper.Unmarshal(&cfg); err != nil { + return nil, fmt.Errorf("decoding config: %v", err) + } + + return &cfg, nil +} + +var ErrConfigFileNotFound = fmt.Errorf("config file not found") + +func fileExists(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) } func DefaultConfig() *KwildConfig { @@ -248,7 +395,7 @@ func DefaultConfig() *KwildConfig { AppCfg: &AppConfig{ GrpcListenAddress: "localhost:50051", HTTPListenAddress: "localhost:8080", - AdminListenAddress: "localhost:50151", + AdminListenAddress: "unix:///tmp/kwil_admin.sock", SqliteFilePath: DefaultSQLitePath, // SnapshotConfig: SnapshotConfig{ // Enabled: false, @@ -265,15 +412,15 @@ func DefaultConfig() *KwildConfig { }, ChainCfg: &ChainConfig{ P2P: &P2PConfig{ - ListenAddress: "tcp://0.0.0.0:26656", + ListenAddress: "tcp://127.0.0.1:26656", ExternalAddress: "", AddrBookStrict: false, // override comet MaxNumInboundPeers: 40, MaxNumOutboundPeers: 10, AllowDuplicateIP: true, // override comet PexReactor: false, // override comet - not recommended for validators - HandshakeTimeout: 20 * time.Second, - DialTimeout: 3 * time.Second, + HandshakeTimeout: Duration(20 * time.Second), + DialTimeout: Duration(3 * time.Second), }, RPC: &ChainRPCConfig{ ListenAddress: "tcp://127.0.0.1:26657", @@ -286,16 +433,34 @@ func DefaultConfig() *KwildConfig { }, StateSync: &StateSyncConfig{ Enable: false, - DiscoveryTime: 15 * time.Second, - ChunkRequestTimeout: 10 * time.Second, + DiscoveryTime: Duration(15 * time.Second), + ChunkRequestTimeout: Duration(10 * time.Second), }, Consensus: &ConsensusConfig{ - TimeoutPropose: 3 * time.Second, - TimeoutPrevote: 2 * time.Second, - TimeoutPrecommit: 2 * time.Second, - TimeoutCommit: 6 * time.Second, + TimeoutPropose: Duration(3 * time.Second), + TimeoutPrevote: Duration(2 * time.Second), + TimeoutPrecommit: Duration(2 * time.Second), + TimeoutCommit: Duration(6 * time.Second), + }, + }, + } +} + +func EmptyConfig() *KwildConfig { + return &KwildConfig{ + AppCfg: &AppConfig{ + ExtensionEndpoints: []string{}, + }, + ChainCfg: &ChainConfig{ + P2P: &P2PConfig{}, + RPC: &ChainRPCConfig{}, + Mempool: &MempoolConfig{}, + StateSync: &StateSyncConfig{ + RPCServers: []string{}, }, + Consensus: &ConsensusConfig{}, }, + Logging: &Logging{}, } } diff --git a/cmd/kwild/config/config_test.go b/cmd/kwild/config/config_test.go index cdb194265..130ec07b4 100644 --- a/cmd/kwild/config/config_test.go +++ b/cmd/kwild/config/config_test.go @@ -11,7 +11,11 @@ import ( func Test_Config_Toml(t *testing.T) { cfg := config.DefaultConfig() - err := cfg.ParseConfig(filepath.Join("test_data", config.ConfigFileName)) + + tomlCfg, err := config.LoadConfigFile(filepath.Join("test_data", config.ConfigFileName)) + assert.NoError(t, err) + + err = cfg.Merge(tomlCfg) assert.NoError(t, err) assert.Equal(t, "localhost:50051", cfg.AppCfg.GrpcListenAddress) diff --git a/cmd/kwild/config/default_config.toml b/cmd/kwild/config/default_config.toml index 1e3a0fb08..1edd2d756 100644 --- a/cmd/kwild/config/default_config.toml +++ b/cmd/kwild/config/default_config.toml @@ -35,12 +35,12 @@ # TCP address for the KWILD App's GRPC server to listen on grpc_listen_addr = "localhost:50051" -# TCP address for the KWILD App's admin server to listen on -admin_listen_addr="localhost:50151" - # TCP address for the KWILD App's HTTP server to listen on http_listen_addr = "localhost:8080" +# UNIX socket for KWILD Admin server to listen on +admin_unix_socket = "/tmp/kwil_admin.sock" + # List of Extension endpoints to be enabled ex: ["localhost:50052", "169.198.102.34:50053"] extension_endpoints = [] diff --git a/cmd/kwild/config/genesis.go b/cmd/kwild/config/genesis.go index 12ee296ea..acb88e3ae 100644 --- a/cmd/kwild/config/genesis.go +++ b/cmd/kwild/config/genesis.go @@ -176,8 +176,7 @@ func loadGenesisAndPrivateKey(autoGen bool, privKeyPath, rootDir string) (privKe return nil, nil, fmt.Errorf("invalid private key: %v", err) } - abciCfgDir := filepath.Join(chainRootDir, cometbft.ConfigDir) - genFile := filepath.Join(abciCfgDir, cometbft.GenesisJSONName) // i.e. /abci/config/genesis.json + genFile := filepath.Join(rootDir, cometbft.GenesisJSONName) if fileExists(genFile) { genesisCfg, err = LoadGenesisConfig(genFile) @@ -191,8 +190,8 @@ func loadGenesisAndPrivateKey(autoGen bool, privKeyPath, rootDir string) (privKe return nil, nil, fmt.Errorf("genesis file not found: %s", genFile) } - if err = os.MkdirAll(abciCfgDir, 0755); err != nil { - return nil, nil, fmt.Errorf("error creating abci config dir %s: %v", abciCfgDir, err) + if err = os.MkdirAll(chainRootDir, 0755); err != nil { + return nil, nil, fmt.Errorf("error creating abci config dir %s: %v", chainRootDir, err) } genesisCfg = NewGenesisWithValidator(pub) diff --git a/cmd/kwild/flags.go b/cmd/kwild/flags.go index 68a5dfd3a..5aa50f9b6 100644 --- a/cmd/kwild/flags.go +++ b/cmd/kwild/flags.go @@ -9,74 +9,74 @@ import ( func addKwildFlags(flagSet *pflag.FlagSet, cfg *config.KwildConfig) { flagSet.BoolVarP(&cfg.AutoGen, "autogen", "a", false, "auto generate private key and genesis file if not exist") - flagSet.StringVarP(&cfg.RootDir, "root_dir", "r", "~/.kwild", "kwild root directory for config and data") + flagSet.StringVarP(&cfg.RootDir, "root-dir", "r", "~/.kwild", "kwild root directory for config and data") // logging flagSet.StringVarP(&cfg.Logging.Level, "log.level", "l", cfg.Logging.Level, "kwild log level") flagSet.StringVar(&cfg.Logging.Format, "log.format", cfg.Logging.Format, "kwild log format") - flagSet.StringVar(&cfg.Logging.TimeEncoding, "log.time_format", cfg.Logging.TimeEncoding, "kwild time log format") - flagSet.StringSliceVar(&cfg.Logging.OutputPaths, "log.output_paths", cfg.Logging.OutputPaths, "kwild log output paths") + flagSet.StringVar(&cfg.Logging.TimeEncoding, "log.time-format", cfg.Logging.TimeEncoding, "kwild time log format") + flagSet.StringSliceVar(&cfg.Logging.OutputPaths, "log.output-paths", cfg.Logging.OutputPaths, "kwild log output paths") // General APP flags: - flagSet.StringVar(&cfg.AppCfg.PrivateKeyPath, "app.private_key_path", cfg.AppCfg.PrivateKeyPath, "Path to the node private key file") - flagSet.StringVar(&cfg.AppCfg.GrpcListenAddress, "app.grpc_listen_addr", cfg.AppCfg.GrpcListenAddress, "kwild gRPC listen address") - flagSet.StringVar(&cfg.AppCfg.HTTPListenAddress, "app.http_listen_addr", cfg.AppCfg.HTTPListenAddress, "kwild HTTP listen address") - flagSet.StringVar(&cfg.AppCfg.AdminListenAddress, "app.admin_listen_addr", cfg.AppCfg.AdminListenAddress, "kwild gRPC listen address") - flagSet.StringVar(&cfg.AppCfg.SqliteFilePath, "app.sqlite_file_path", cfg.AppCfg.SqliteFilePath, "kwild sqlite file path") - flagSet.StringVar(&cfg.AppCfg.TLSCertFile, "app.tls_cert_file", cfg.AppCfg.TLSCertFile, "TLS certificate file path for RPC Server") - flagSet.StringVar(&cfg.AppCfg.TLSKeyFile, "app.tls_key_file", cfg.AppCfg.TLSKeyFile, "TLS key file path for RPC Server") + flagSet.StringVar(&cfg.AppCfg.PrivateKeyPath, "app.private-key-path", cfg.AppCfg.PrivateKeyPath, "Path to the node private key file") + flagSet.StringVar(&cfg.AppCfg.GrpcListenAddress, "app.grpc-listen-addr", cfg.AppCfg.GrpcListenAddress, "kwild gRPC listen address") + flagSet.StringVar(&cfg.AppCfg.HTTPListenAddress, "app.http-listen-addr", cfg.AppCfg.HTTPListenAddress, "kwild HTTP listen address") + flagSet.StringVar(&cfg.AppCfg.AdminListenAddress, "app.admin-listen-addr", cfg.AppCfg.AdminListenAddress, "kwild admin listen address (unix or tcp)") + flagSet.StringVar(&cfg.AppCfg.SqliteFilePath, "app.sqlite-file-path", cfg.AppCfg.SqliteFilePath, "kwild sqlite file path") + flagSet.StringVar(&cfg.AppCfg.TLSCertFile, "app.tls-cert-file", cfg.AppCfg.TLSCertFile, "TLS certificate file path for RPC Server") + flagSet.StringVar(&cfg.AppCfg.TLSKeyFile, "app.tls-key-file", cfg.AppCfg.TLSKeyFile, "TLS key file path for RPC Server") flagSet.BoolVar(&cfg.AppCfg.EnableRPCTLS, "app.rpctls", cfg.AppCfg.EnableRPCTLS, "Use TLS on the user gRPC server") flagSet.StringVar(&cfg.AppCfg.Hostname, "app.hostname", cfg.AppCfg.Hostname, "kwild Server hostname") - flagSet.StringVar(&cfg.AppCfg.ProfileMode, "app.profile_mode", cfg.AppCfg.ProfileMode, "kwild profile mode (http, cpu, mem, mutex, or block)") - flagSet.StringVar(&cfg.AppCfg.ProfileFile, "app.profile_file", cfg.AppCfg.ProfileFile, "kwild profile output file path (e.g. cpu.pprof)") + flagSet.StringVar(&cfg.AppCfg.ProfileMode, "app.profile-mode", cfg.AppCfg.ProfileMode, "kwild profile mode (http, cpu, mem, mutex, or block)") + flagSet.StringVar(&cfg.AppCfg.ProfileFile, "app.profile-file", cfg.AppCfg.ProfileFile, "kwild profile output file path (e.g. cpu.pprof)") // Extension endpoints flags - flagSet.StringSliceVar(&cfg.AppCfg.ExtensionEndpoints, "app.extension_endpoints", cfg.AppCfg.ExtensionEndpoints, "kwild extension endpoints") + flagSet.StringSliceVar(&cfg.AppCfg.ExtensionEndpoints, "app.extension-endpoints", cfg.AppCfg.ExtensionEndpoints, "kwild extension endpoints") // TODO: Snapshots are not supported yet // // Snapshot Config flags // flagSet.BoolVar(&cfg.AppCfg.SnapshotConfig.Enabled, "app.snapshots.enabled", cfg.AppCfg.SnapshotConfig.Enabled, "Enable snapshots") - // flagSet.Uint64Var(&cfg.AppCfg.SnapshotConfig.RecurringHeight, "app.snapshots.recurring_height", cfg.AppCfg.SnapshotConfig.RecurringHeight, "Recurring snapshot height") - // flagSet.Uint64Var(&cfg.AppCfg.SnapshotConfig.MaxSnapshots, "app.snapshots.max_snapshots", cfg.AppCfg.SnapshotConfig.MaxSnapshots, "Maximum snapshots") - // flagSet.StringVar(&cfg.AppCfg.SnapshotConfig.SnapshotDir, "app.snapshots.snapshot_dir", cfg.AppCfg.SnapshotConfig.SnapshotDir, "Snapshot directory path") + // flagSet.Uint64Var(&cfg.AppCfg.SnapshotConfig.RecurringHeight, "app.snapshots.recurring-height", cfg.AppCfg.SnapshotConfig.RecurringHeight, "Recurring snapshot height") + // flagSet.Uint64Var(&cfg.AppCfg.SnapshotConfig.MaxSnapshots, "app.snapshots.max-snapshots", cfg.AppCfg.SnapshotConfig.MaxSnapshots, "Maximum snapshots") + // flagSet.StringVar(&cfg.AppCfg.SnapshotConfig.SnapshotDir, "app.snapshots.snapshot-dir", cfg.AppCfg.SnapshotConfig.SnapshotDir, "Snapshot directory path") // Basic Chain Config flags flagSet.StringVar(&cfg.ChainCfg.Moniker, "chain.moniker", cfg.ChainCfg.Moniker, "Node moniker") - // flagSet.StringVar(&cfg.ChainCfg.DBPath, "chain.db_dir", cfg.ChainCfg.DBPath, "Chain database directory path") // rm? + // flagSet.StringVar(&cfg.ChainCfg.DBPath, "chain.db-dir", cfg.ChainCfg.DBPath, "Chain database directory path") // rm? // Chain RPC flags - flagSet.StringVar(&cfg.ChainCfg.RPC.ListenAddress, "chain.rpc.listen_addr", cfg.ChainCfg.RPC.ListenAddress, "Chain RPC listen address") + flagSet.StringVar(&cfg.ChainCfg.RPC.ListenAddress, "chain.rpc.listen-addr", cfg.ChainCfg.RPC.ListenAddress, "Chain RPC listen address") // Chain P2P flags - flagSet.StringVar(&cfg.ChainCfg.P2P.ListenAddress, "chain.p2p.listen_addr", cfg.ChainCfg.P2P.ListenAddress, "Chain P2P listen address") - flagSet.StringVar(&cfg.ChainCfg.P2P.ExternalAddress, "chain.p2p.external_address", cfg.ChainCfg.P2P.ExternalAddress, "Chain P2P external address to advertise") - flagSet.StringVar(&cfg.ChainCfg.P2P.PersistentPeers, "chain.p2p.persistent_peers", cfg.ChainCfg.P2P.PersistentPeers, "Chain P2P persistent peers") - flagSet.BoolVar(&cfg.ChainCfg.P2P.AddrBookStrict, "chain.p2p.addr_book_strict", cfg.ChainCfg.P2P.AddrBookStrict, "Chain P2P address book strict") - flagSet.StringVar(&cfg.ChainCfg.P2P.UnconditionalPeerIDs, "chain.p2p.unconditional_peer_ids", cfg.ChainCfg.P2P.UnconditionalPeerIDs, "Chain P2P unconditional peer IDs") - flagSet.IntVar(&cfg.ChainCfg.P2P.MaxNumInboundPeers, "chain.p2p.max_num_inbound_peers", cfg.ChainCfg.P2P.MaxNumInboundPeers, "Chain P2P maximum number of inbound peers") - flagSet.IntVar(&cfg.ChainCfg.P2P.MaxNumOutboundPeers, "chain.p2p.max_num_outbound_peers", cfg.ChainCfg.P2P.MaxNumOutboundPeers, "Chain P2P maximum number of outbound peers") - flagSet.BoolVar(&cfg.ChainCfg.P2P.AllowDuplicateIP, "chain.p2p.allow_duplicate_ip", cfg.ChainCfg.P2P.AllowDuplicateIP, "Chain P2P allow multiple peers with the same IP address") + flagSet.StringVar(&cfg.ChainCfg.P2P.ListenAddress, "chain.p2p.listen-addr", cfg.ChainCfg.P2P.ListenAddress, "Chain P2P listen address") + flagSet.StringVar(&cfg.ChainCfg.P2P.ExternalAddress, "chain.p2p.external-address", cfg.ChainCfg.P2P.ExternalAddress, "Chain P2P external address to advertise") + flagSet.StringVar(&cfg.ChainCfg.P2P.PersistentPeers, "chain.p2p.persistent-peers", cfg.ChainCfg.P2P.PersistentPeers, "Chain P2P persistent peers") + flagSet.BoolVar(&cfg.ChainCfg.P2P.AddrBookStrict, "chain.p2p.addr-book-strict", cfg.ChainCfg.P2P.AddrBookStrict, "Chain P2P address book strict") + flagSet.StringVar(&cfg.ChainCfg.P2P.UnconditionalPeerIDs, "chain.p2p.unconditional-peer-ids", cfg.ChainCfg.P2P.UnconditionalPeerIDs, "Chain P2P unconditional peer IDs") + flagSet.IntVar(&cfg.ChainCfg.P2P.MaxNumInboundPeers, "chain.p2p.max-num-inbound-peers", cfg.ChainCfg.P2P.MaxNumInboundPeers, "Chain P2P maximum number of inbound peers") + flagSet.IntVar(&cfg.ChainCfg.P2P.MaxNumOutboundPeers, "chain.p2p.max-num-outbound-peers", cfg.ChainCfg.P2P.MaxNumOutboundPeers, "Chain P2P maximum number of outbound peers") + flagSet.BoolVar(&cfg.ChainCfg.P2P.AllowDuplicateIP, "chain.p2p.allow-duplicate-ip", cfg.ChainCfg.P2P.AllowDuplicateIP, "Chain P2P allow multiple peers with the same IP address") // Chain Mempool flags flagSet.IntVar(&cfg.ChainCfg.Mempool.Size, "chain.mempool.size", cfg.ChainCfg.Mempool.Size, "Chain mempool size") - flagSet.IntVar(&cfg.ChainCfg.Mempool.CacheSize, "chain.mempool.cache_size", cfg.ChainCfg.Mempool.CacheSize, "Chain mempool cache size") - flagSet.IntVar(&cfg.ChainCfg.Mempool.MaxTxBytes, "chain.mempool.max_tx_bytes", cfg.ChainCfg.Mempool.MaxTxBytes, "chain mempool maximum single transaction size in bytes") - flagSet.IntVar(&cfg.ChainCfg.Mempool.MaxTxsBytes, "chain.mempool.max_txs_bytes", cfg.ChainCfg.Mempool.MaxTxsBytes, "chain mempool maximum total transactions in bytes") + flagSet.IntVar(&cfg.ChainCfg.Mempool.CacheSize, "chain.mempool.cache-size", cfg.ChainCfg.Mempool.CacheSize, "Chain mempool cache size") + flagSet.IntVar(&cfg.ChainCfg.Mempool.MaxTxBytes, "chain.mempool.max-tx-bytes", cfg.ChainCfg.Mempool.MaxTxBytes, "chain mempool maximum single transaction size in bytes") + flagSet.IntVar(&cfg.ChainCfg.Mempool.MaxTxsBytes, "chain.mempool.max-txs-bytes", cfg.ChainCfg.Mempool.MaxTxsBytes, "chain mempool maximum total transactions in bytes") // Chain Consensus flags - flagSet.DurationVar(&cfg.ChainCfg.Consensus.TimeoutPropose, "chain.consensus.timeout_propose", cfg.ChainCfg.Consensus.TimeoutPropose, "Chain consensus timeout propose") - flagSet.DurationVar(&cfg.ChainCfg.Consensus.TimeoutPrevote, "chain.consensus.timeout_prevote", cfg.ChainCfg.Consensus.TimeoutPrevote, "Chain consensus timeout prevote") - flagSet.DurationVar(&cfg.ChainCfg.Consensus.TimeoutPrecommit, "chain.consensus.timeout_precommit", cfg.ChainCfg.Consensus.TimeoutPrecommit, "Chain consensus timeout precommit") - flagSet.DurationVar(&cfg.ChainCfg.Consensus.TimeoutCommit, "chain.consensus.timeout_commit", cfg.ChainCfg.Consensus.TimeoutCommit, "Chain consensus timeout commit") + flagSet.Var(&cfg.ChainCfg.Consensus.TimeoutPropose, "chain.consensus.timeout-propose", "Chain consensus timeout propose") + flagSet.Var(&cfg.ChainCfg.Consensus.TimeoutPrevote, "chain.consensus.timeout-prevote", "Chain consensus timeout prevote") + flagSet.Var(&cfg.ChainCfg.Consensus.TimeoutPrecommit, "chain.consensus.timeout-precommit", "Chain consensus timeout precommit") + flagSet.Var(&cfg.ChainCfg.Consensus.TimeoutCommit, "chain.consensus.timeout-commit", "Chain consensus timeout commit") // State Sync flags // TODO: Bring these flags back when we support state sync - // flagSet.BoolVar(&cfg.ChainCfg.StateSync.Enable, "chain.state_sync.enable", cfg.ChainCfg.StateSync.Enable, "Chain state sync enable") - // flagSet.StringVar(&cfg.ChainCfg.StateSync.TempDir, "chain.state_sync.temp_dir", cfg.ChainCfg.StateSync.TempDir, "Chain state sync temp dir") - // flagSet.StringSliceVar(&cfg.ChainCfg.StateSync.RPCServers, "chain.state_sync.rpc_servers", cfg.ChainCfg.StateSync.RPCServers, "Chain state sync rpc servers") - // flagSet.DurationVar(&cfg.ChainCfg.StateSync.DiscoveryTime, "chain.state_sync.discovery_time", cfg.ChainCfg.StateSync.DiscoveryTime, "Chain state sync discovery time") - // flagSet.DurationVar(&cfg.ChainCfg.StateSync.ChunkRequestTimeout, "chain.state_sync.chunk_request_timeout", cfg.ChainCfg.StateSync.ChunkRequestTimeout, "Chain state sync chunk request timeout") + // flagSet.BoolVar(&cfg.ChainCfg.StateSync.Enable, "chain.state-sync.enable", cfg.ChainCfg.StateSync.Enable, "Chain state sync enable") + // flagSet.StringVar(&cfg.ChainCfg.StateSync.TempDir, "chain.state-sync.temp-dir", cfg.ChainCfg.StateSync.TempDir, "Chain state sync temp dir") + // flagSet.StringSliceVar(&cfg.ChainCfg.StateSync.RPCServers, "chain.state-sync.rpc-servers", cfg.ChainCfg.StateSync.RPCServers, "Chain state sync rpc servers") + // flagSet.DurationVar(&cfg.ChainCfg.StateSync.DiscoveryTime, "chain.state-sync.discovery-time", cfg.ChainCfg.StateSync.DiscoveryTime, "Chain state sync discovery time") + // flagSet.DurationVar(&cfg.ChainCfg.StateSync.ChunkRequestTimeout, "chain.state-sync.chunk-request-timeout", cfg.ChainCfg.StateSync.ChunkRequestTimeout, "Chain state sync chunk request timeout") // Block sync can be added later (when they have more version of it) } diff --git a/cmd/kwild/main.go b/cmd/kwild/main.go index 63bd725d5..b91ba991b 100644 --- a/cmd/kwild/main.go +++ b/cmd/kwild/main.go @@ -17,7 +17,6 @@ import ( "github.com/kwilteam/kwil-db/internal/version" "github.com/spf13/cobra" - "github.com/spf13/viper" _ "github.com/kwilteam/kwil-db/extensions/auth" ) @@ -27,60 +26,64 @@ var ( ) func main() { - rootCmd.Version = version.KwilVersion - - flagSet := rootCmd.Flags() - flagSet.SortFlags = false - addKwildFlags(flagSet, kwildCfg) - viper.BindPFlags(flagSet) - - if err := rootCmd.Execute(); err != nil { + if err := rootCmd().Execute(); err != nil { fmt.Println(err) os.Exit(1) } os.Exit(0) } -var rootCmd = &cobra.Command{ - Use: "kwild", - Short: "kwild node and rpc server", - Long: "kwild: the Kwil blockchain node and RPC server", - DisableAutoGenTag: true, - Args: cobra.NoArgs, // just flags - RunE: func(cmd *cobra.Command, args []string) error { - // command line flags are now (finally) parsed by cobra. Bind env vars, - // load the config file, and unmarshal into kwildCfg. - if err := kwildCfg.LoadKwildConfig(); err != nil { - return fmt.Errorf("failed to load kwild config: %w", err) - } +func rootCmd() *cobra.Command { + flagCfg := config.EmptyConfig() + + cmd := &cobra.Command{ + Use: "kwild", + Short: "kwild node and rpc server", + Long: "kwild: the Kwil blockchain node and RPC server", + DisableAutoGenTag: true, + Args: cobra.NoArgs, // just flags + Version: version.KwilVersion, + RunE: func(cmd *cobra.Command, args []string) error { + var err error + kwildCfg, err = config.GetCfg(flagCfg) + if err != nil { + return err + } - nodeKey, genesisConfig, err := kwildCfg.InitPrivateKeyAndGenesis() - if err != nil { - return fmt.Errorf("failed to initialize private key and genesis: %w", err) - } + nodeKey, genesisConfig, err := kwildCfg.InitPrivateKeyAndGenesis() + if err != nil { + return fmt.Errorf("failed to initialize private key and genesis: %w", err) + } - stopProfiler, err := startProfilers(kwildCfg) - if err != nil { - return err - } - defer stopProfiler() + stopProfiler, err := startProfilers(kwildCfg) + if err != nil { + return err + } + defer stopProfiler() - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) - ctx, cancel := context.WithCancel(cmd.Context()) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) + ctx, cancel := context.WithCancel(cmd.Context()) - go func() { - <-signalChan - cancel() - }() + go func() { + <-signalChan + cancel() + }() - svr, err := server.New(ctx, kwildCfg, genesisConfig, nodeKey) - if err != nil { - return err - } + svr, err := server.New(ctx, kwildCfg, genesisConfig, nodeKey) + if err != nil { + return err + } + + return svr.Start(ctx) + }, + } + + flagSet := cmd.Flags() + flagSet.SortFlags = false + addKwildFlags(flagSet, flagCfg) - return svr.Start(ctx) - }, + return cmd } func startProfilers(cfg *config.KwildConfig) (func(), error) { diff --git a/cmd/kwild/server/build.go b/cmd/kwild/server/build.go index afa41f5a7..c7b356248 100644 --- a/cmd/kwild/server/build.go +++ b/cmd/kwild/server/build.go @@ -9,6 +9,7 @@ import ( "net" "os" "path/filepath" + "syscall" "time" "github.com/kwilteam/kwil-db/cmd/kwild/config" @@ -21,6 +22,7 @@ import ( "github.com/kwilteam/kwil-db/internal/modules/datasets" "github.com/kwilteam/kwil-db/internal/modules/validators" admSvc "github.com/kwilteam/kwil-db/internal/services/grpc/admin/v0" + functionSvc "github.com/kwilteam/kwil-db/internal/services/grpc/function/v0" "github.com/kwilteam/kwil-db/internal/services/grpc/healthsvc/v0" txSvc "github.com/kwilteam/kwil-db/internal/services/grpc/txsvc/v1" gateway "github.com/kwilteam/kwil-db/internal/services/grpc_gateway" @@ -35,10 +37,14 @@ import ( "github.com/kwilteam/kwil-db/internal/sql/sqlite" vmgr "github.com/kwilteam/kwil-db/internal/validators" + "github.com/kwilteam/kwil-db/core/crypto" + "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" + functionpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/function/v0" txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" "github.com/kwilteam/kwil-db/core/rpc/transport" + "github.com/kwilteam/kwil-db/core/utils/url" abciTypes "github.com/cometbft/cometbft/abci/types" cmtEd "github.com/cometbft/cometbft/crypto/ed25519" @@ -85,17 +91,17 @@ func buildServer(d *coreDependencies, closers *closeFuncs) *Server { grpcServer := buildGrpcServer(d, txsvc) // admin service and server - admsvc := buildAdminSvc(d, &wrappedCometBFTClient{cometBftClient}) - admServer := buildAdminServer(d, admsvc) + admsvc := buildAdminSvc(d, &wrappedCometBFTClient{cometBftClient}, abciApp, vstore) + adminTCPServer := buildAdminService(d, closers, admsvc, txsvc) return &Server{ - grpcServer: grpcServer, - admServer: admServer, - gateway: buildGatewayServer(d), - cometBftNode: cometBftNode, - log: *d.log.Named("server"), - closers: closers, - cfg: d.cfg, + grpcServer: grpcServer, + adminTPCServer: adminTCPServer, + gateway: buildGatewayServer(d), + cometBftNode: cometBftNode, + log: *d.log.Named("server"), + closers: closers, + cfg: d.cfg, } } @@ -179,8 +185,15 @@ func buildTxSvc(d *coreDependencies, txsvc txSvc.EngineReader, accs txSvc.Accoun ) } -func buildAdminSvc(d *coreDependencies, node admSvc.Node) *admSvc.Service { - return admSvc.NewService(node, +func buildAdminSvc(d *coreDependencies, transactor admSvc.BlockchainTransactor, node admSvc.NodeApplication, validatorStore admSvc.ValidatorReader) *admSvc.Service { + pk, err := crypto.Ed25519PrivateKeyFromBytes(d.privKey.Bytes()) + if err != nil { + failBuild(err, "failed to build admin service") + } + + signer := auth.Ed25519Signer{Ed25519PrivateKey: *pk} + + return admSvc.NewService(transactor, node, validatorStore, &signer, admSvc.WithLogger(*d.log.Named("admin-service")), ) } @@ -378,6 +391,11 @@ func buildGrpcServer(d *coreDependencies, txsvc txpb.TxServiceServer) *kwilgrpc. recvLimit := d.cfg.ChainCfg.Mempool.MaxTxBytes + msgOverHeadBuffer grpcServer := kwilgrpc.New(*d.log.Named("grpc-server"), lis, kwilgrpc.WithSrvOpt(grpc.MaxRecvMsgSize(recvLimit))) txpb.RegisterTxServiceServer(grpcServer, txsvc) + + // right now, the function service is just registered to the public tx service + functionsvc := functionSvc.FunctionService{} + functionpb.RegisterFunctionServiceServer(grpcServer, &functionsvc) + grpc_health_v1.RegisterHealthServer(grpcServer, buildHealthSvc(d)) return grpcServer @@ -397,56 +415,111 @@ func buildHealthSvc(d *coreDependencies) *healthsvc.Server { return healthsvc.NewServer(ck) } -func buildAdminServer(d *coreDependencies, admsvc admpb.AdminServiceServer) *kwilgrpc.Server { - lis, err := net.Listen("tcp", d.cfg.AppCfg.AdminListenAddress) +func buildAdminService(d *coreDependencies, closer *closeFuncs, admsvc admpb.AdminServiceServer, txsvc txpb.TxServiceServer) *kwilgrpc.Server { + u, err := url.ParseURL(d.cfg.AppCfg.AdminListenAddress) if err != nil { - failBuild(err, "failed to build grpc server") + failBuild(err, "failed to build admin service") } - // client certs - caCertPool := x509.NewCertPool() - var clientsCerts []byte - if clientsFile := filepath.Join(d.cfg.RootDir, defaultAdminClients); fileExists(clientsFile) { - clientsCerts, err = os.ReadFile(clientsFile) + + switch u.Scheme { + default: + failBuild(err, "unknown admin service protocol "+u.Scheme.String()) + case url.TCP: + + // if tcp, we need to set up TLS + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", u.Port)) if err != nil { - failBuild(err, "failed to load client CAs file") + failBuild(err, "failed to build grpc server") + } + closer.addCloser(lis.Close) + + // client certs + caCertPool := x509.NewCertPool() + var clientsCerts []byte + if clientsFile := filepath.Join(d.cfg.RootDir, defaultAdminClients); fileExists(clientsFile) { + clientsCerts, err = os.ReadFile(clientsFile) + if err != nil { + failBuild(err, "failed to load client CAs file") + } + } else if d.cfg.AutoGen { + clientCredsFileBase := filepath.Join(d.cfg.RootDir, "auth") + clientCertFile, clientKeyFile := clientCredsFileBase+".cert", clientCredsFileBase+".key" + err = transport.GenTLSKeyPair(clientCertFile, clientKeyFile, "kwild CA", nil) + if err != nil { + failBuild(err, "failed to generate admin client credentials") + } + d.log.Info("generated admin service client key pair", zap.String("cert", clientCertFile), zap.String("key", clientKeyFile)) + if clientsCerts, err = os.ReadFile(clientCertFile); err != nil { + failBuild(err, "failed to read auto-generate client certificate") + } + if err = os.WriteFile(clientsFile, clientsCerts, 0644); err != nil { + failBuild(err, "failed to write client CAs file") + } + d.log.Info("generated admin service client CAs file", zap.String("file", clientsFile)) + } else { + d.log.Info("No admin client CAs file. Use kwil-admin's node gen-auth-key command to generate") + } + if len(clientsCerts) > 0 && !caCertPool.AppendCertsFromPEM(clientsCerts) { + failBuild(err, "invalid client CAs file") + } + + // TLS configuration for mTLS (mutual TLS) protocol-level authentication + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{*d.keypair}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, } - } else if d.cfg.AutoGen { - clientCredsFileBase := filepath.Join(d.cfg.RootDir, "auth") - clientCertFile, clientKeyFile := clientCredsFileBase+".cert", clientCredsFileBase+".key" - err = transport.GenTLSKeyPair(clientCertFile, clientKeyFile, "kwild CA", nil) + + creds := grpc.Creds(credentials.NewTLS(tlsConfig)) + opts := kwilgrpc.WithSrvOpt(creds) + + grpcServer := kwilgrpc.New(*d.log.Named("auth-grpc-server"), lis, opts) + admpb.RegisterAdminServiceServer(grpcServer, admsvc) + txpb.RegisterTxServiceServer(grpcServer, txsvc) + grpc_health_v1.RegisterHealthServer(grpcServer, buildHealthSvc(d)) + + return grpcServer + case url.UNIX: + // if unix, we need to set up unix socket + err = os.MkdirAll(filepath.Dir(u.Target), 0700) // ensure parent dir exists if err != nil { - failBuild(err, "failed to generate admin client credentials") + failBuild(err, "failed to create admin service unix socket directory at "+filepath.Dir(u.Target)) } - d.log.Info("generated admin service client key pair", zap.String("cert", clientCertFile), zap.String("key", clientKeyFile)) - if clientsCerts, err = os.ReadFile(clientCertFile); err != nil { - failBuild(err, "failed to read auto-generate client certificate") + + d.log.Info("creating admin service unix socket at " + u.Target) + + // unix sockets will remain "open" unless lis.Close is called + // In case of crash, this creates very bad ux for developers. + // suggested approach here (not sure about this for obvious reasons): + // https://gist.github.com/hakobe/6f70d69b8c5243117787fd488ae7fbf2 + + err = syscall.Unlink(u.Target) + if err != nil && !os.IsNotExist(err) { + failBuild(err, "failed to build grpc server") } - if err = os.WriteFile(clientsFile, clientsCerts, 0644); err != nil { - failBuild(err, "failed to write client CAs file") + + lis, err := net.Listen("unix", u.Target) + if err != nil { + failBuild(err, "failed to listen to unix socket") } - d.log.Info("generated admin service client CAs file", zap.String("file", clientsFile)) - } else { - d.log.Info("No admin client CAs file. Use kwil-admin's node gen-auth-key command to generate") - } - if len(clientsCerts) > 0 && !caCertPool.AppendCertsFromPEM(clientsCerts) { - failBuild(err, "invalid client CAs file") - } - // TLS configuration for mTLS (mutual TLS) protocol-level authentication - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{*d.keypair}, - ClientAuth: tls.RequireAndVerifyClientCert, - ClientCAs: caCertPool, - } + closer.addCloser(lis.Close) - creds := grpc.Creds(credentials.NewTLS(tlsConfig)) - opts := kwilgrpc.WithSrvOpt(creds) + err = os.Chmod(u.Target, 0777) // TODO: probably want this to be more restrictive + if err != nil { + failBuild(err, "failed to build grpc server") + } - grpcServer := kwilgrpc.New(*d.log.Named("auth-grpc-server"), lis, opts) - admpb.RegisterAdminServiceServer(grpcServer, admsvc) - grpc_health_v1.RegisterHealthServer(grpcServer, buildHealthSvc(d)) + grpcServer := kwilgrpc.New(*d.log.Named("auth-grpc-server"), lis) + admpb.RegisterAdminServiceServer(grpcServer, admsvc) + txpb.RegisterTxServiceServer(grpcServer, txsvc) + grpc_health_v1.RegisterHealthServer(grpcServer, buildHealthSvc(d)) - return grpcServer + return grpcServer + } + + failBuild(nil, "unknown error building admin service") // should never get here + return nil } func buildGatewayServer(d *coreDependencies) *gateway.GatewayServer { diff --git a/cmd/kwild/server/cometbft.go b/cmd/kwild/server/cometbft.go index a96573fbb..301e8fb07 100644 --- a/cmd/kwild/server/cometbft.go +++ b/cmd/kwild/server/cometbft.go @@ -3,6 +3,7 @@ package server import ( "fmt" "path/filepath" + "time" "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/internal/abci/cometbft" @@ -47,18 +48,18 @@ func newCometConfig(cfg *config.KwildConfig) *cmtCfg.Config { nodeCfg.P2P.UnconditionalPeerIDs = userChainCfg.P2P.UnconditionalPeerIDs nodeCfg.P2P.PexReactor = userChainCfg.P2P.PexReactor nodeCfg.P2P.AllowDuplicateIP = cfg.ChainCfg.P2P.AllowDuplicateIP - nodeCfg.P2P.HandshakeTimeout = userChainCfg.P2P.HandshakeTimeout - nodeCfg.P2P.DialTimeout = userChainCfg.P2P.DialTimeout + nodeCfg.P2P.HandshakeTimeout = time.Duration(userChainCfg.P2P.HandshakeTimeout) + nodeCfg.P2P.DialTimeout = time.Duration(userChainCfg.P2P.DialTimeout) nodeCfg.Mempool.Size = userChainCfg.Mempool.Size nodeCfg.Mempool.CacheSize = userChainCfg.Mempool.CacheSize nodeCfg.Mempool.MaxTxBytes = userChainCfg.Mempool.MaxTxBytes nodeCfg.Mempool.MaxTxsBytes = int64(userChainCfg.Mempool.MaxTxsBytes) - nodeCfg.Consensus.TimeoutPropose = userChainCfg.Consensus.TimeoutPropose - nodeCfg.Consensus.TimeoutPrevote = userChainCfg.Consensus.TimeoutPrevote - nodeCfg.Consensus.TimeoutPrecommit = userChainCfg.Consensus.TimeoutPrecommit - nodeCfg.Consensus.TimeoutCommit = userChainCfg.Consensus.TimeoutCommit + nodeCfg.Consensus.TimeoutPropose = time.Duration(userChainCfg.Consensus.TimeoutPropose) + nodeCfg.Consensus.TimeoutPrevote = time.Duration(userChainCfg.Consensus.TimeoutPrevote) + nodeCfg.Consensus.TimeoutPrecommit = time.Duration(userChainCfg.Consensus.TimeoutPrecommit) + nodeCfg.Consensus.TimeoutCommit = time.Duration(userChainCfg.Consensus.TimeoutCommit) nodeCfg.StateSync.Enable = false // nodeCfg.StateSync.Enable = userChainCfg.StateSync.Enable @@ -72,7 +73,7 @@ func newCometConfig(cfg *config.KwildConfig) *cmtCfg.Config { chainRoot := filepath.Join(cfg.RootDir, abciDirName) nodeCfg.SetRoot(chainRoot) - nodeCfg.Genesis = cometbft.GenesisPath(chainRoot) + nodeCfg.Genesis = filepath.Join(cfg.RootDir, cometbft.GenesisJSONName) nodeCfg.P2P.AddrBook = cometbft.AddrBookPath(chainRoot) return nodeCfg diff --git a/cmd/kwild/server/server.go b/cmd/kwild/server/server.go index 2f94e1119..f494799f7 100644 --- a/cmd/kwild/server/server.go +++ b/cmd/kwild/server/server.go @@ -30,12 +30,12 @@ import ( // Server controls the gRPC server and http gateway. type Server struct { - grpcServer *grpc.Server - gateway *gateway.GatewayServer - admServer *grpc.Server - cometBftNode *cometbft.CometBftNode - closers *closeFuncs - log log.Logger + grpcServer *grpc.Server + gateway *gateway.GatewayServer + adminTPCServer *grpc.Server + cometBftNode *cometbft.CometBftNode + closers *closeFuncs + log log.Logger cfg *config.KwildConfig @@ -166,10 +166,10 @@ func (s *Server) Start(ctx context.Context) error { go func() { <-groupCtx.Done() s.log.Info("stop admin server") - s.admServer.Stop() + s.adminTPCServer.Stop() }() - return s.admServer.Start() + return s.adminTPCServer.Start() }) s.log.Info("grpc server started", zap.String("address", s.cfg.AppCfg.AdminListenAddress)) diff --git a/cmd/kwild/server/utils.go b/cmd/kwild/server/utils.go index da1a26fa9..496ff3595 100644 --- a/cmd/kwild/server/utils.go +++ b/cmd/kwild/server/utils.go @@ -116,6 +116,7 @@ func (wc *wrappedCometBFTClient) Peers(ctx context.Context) ([]*types.PeerInfo, if err != nil { return nil, err } + peers := make([]*types.PeerInfo, len(cmtNetInfo.Peers)) for i, p := range cmtNetInfo.Peers { peers[i] = &types.PeerInfo{ @@ -142,9 +143,8 @@ func (wc *wrappedCometBFTClient) Status(ctx context.Context) (*types.Status, err BestBlockTime: si.LatestBlockTime.UTC(), }, Validator: &types.ValidatorInfo{ - PubKey: vi.PubKey.Bytes(), - PubKeyType: vi.PubKey.Type(), - Power: vi.VotingPower, + PubKey: vi.PubKey.Bytes(), + Power: vi.VotingPower, }, }, nil } diff --git a/core/adminclient/client.go b/core/adminclient/client.go new file mode 100644 index 000000000..2b6efa18e --- /dev/null +++ b/core/adminclient/client.go @@ -0,0 +1,119 @@ +// package adminclient provides a client for the Kwil admin service. +// The admin service is used to perform node administrative actions, +// such as submitting validator transactions, retrieving node status, etc. +package adminclient + +import ( + "context" + "crypto/tls" + "fmt" + "net" + + "github.com/kwilteam/kwil-db/core/log" + adminRpc "github.com/kwilteam/kwil-db/core/rpc/client/admin" + admingrpc "github.com/kwilteam/kwil-db/core/rpc/client/admin/grpc" + txGrpc "github.com/kwilteam/kwil-db/core/rpc/client/user/grpc" + "github.com/kwilteam/kwil-db/core/rpc/transport" + "github.com/kwilteam/kwil-db/core/types/transactions" + "github.com/kwilteam/kwil-db/core/utils/url" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" +) + +// AdminClient is a client for the Kwil admin service. +// It inherits both the admin and tx services. +type AdminClient struct { + adminRpc.AdminClient // transport for admin client. we can just expose this, since we don't need to wrap it with any logic + txClient // should be the subset of the interface of core/client/Client that we want to expose here. + + log log.Logger + + // tls cert files, if using grpc and not unix socket + kwildCertFile string + clientKeyFile string + clientCertFile string +} + +// txClient is the txsvc client interface. +// It allows us to selectively expose the txsvc client methods. +type txClient interface { + // Ping pings the connected node. + Ping(ctx context.Context) (string, error) + // TxQuery queries a transaction by hash. + TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) +} + +// New creates a new admin client. +// It can be configured to either use TLS or not, if using gRPC. +// The target arg should be either "tcp://localhost:50151", "localhost:50151", or "unix://path/to/socket.sock" +func New(ctx context.Context, target string, opts ...AdminClientOpt) (*AdminClient, error) { + c := &AdminClient{ + log: log.NewNoOp(), + } + + parsedTarget, err := url.ParseURL(target) + if err != nil { + return nil, err + } + + // we can have: + // tcp + tls + // tcp + no tls + // unix socket + no tls + dialOpts := []grpc.DialOption{} + + switch parsedTarget.Scheme { + case url.TCP: // default to grpc + if c.kwildCertFile != "" || c.clientKeyFile != "" || c.clientCertFile != "" { + // tcp + tls + + tlsCfg, err := newAuthenticatedTLSConfig(c.kwildCertFile, c.clientCertFile, c.clientKeyFile) + if err != nil { + return nil, err + } + + dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))) + } else { + // tcp + no tls + dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + case url.UNIX: + dialOpts = append(dialOpts, grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) { + return net.Dial("unix", s) + }), grpc.WithTransportCredentials(insecure.NewCredentials())) + default: + return nil, fmt.Errorf("unknown scheme %q", parsedTarget.Scheme) + } + + // we dial a normal grpc connection, and then wrap it with the services + conn, err := grpc.DialContext(ctx, parsedTarget.Target, dialOpts...) + if err != nil { + return nil, err + } + + c.AdminClient = admingrpc.NewAdminClient(conn) + + c.txClient = txGrpc.WrapConn(conn) + + return c, nil +} + +// newAuthenticatedTLSConfig creates a new tls.Config for an +// mutually-authenticated TLS (mTLS) client. In addition to the server's +// certificate file, the client's own key pair is required to support protocol +// level client authentication. +func newAuthenticatedTLSConfig(kwildCertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) { + cfg, err := transport.NewClientTLSConfigFromFile(kwildCertFile) + if err != nil { + return nil, err + } + + authCert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile) + if err != nil { + return nil, err + } + cfg.Certificates = append(cfg.Certificates, authCert) + + return cfg, nil +} diff --git a/core/adminclient/opts.go b/core/adminclient/opts.go new file mode 100644 index 000000000..a477cb529 --- /dev/null +++ b/core/adminclient/opts.go @@ -0,0 +1,23 @@ +package adminclient + +import ( + "github.com/kwilteam/kwil-db/core/log" +) + +type AdminClientOpt func(*AdminClient) + +// WithLogger sets the logger for the admin client. +func WithLogger(logger log.Logger) AdminClientOpt { + return func(c *AdminClient) { + c.log = logger + } +} + +// WithTLS provides the required TLS files for the admin client to connect via gRPC. +func WithTLS(kwildCertFile, clientKeyFile, clientCertFile string) AdminClientOpt { + return func(c *AdminClient) { + c.kwildCertFile = kwildCertFile + c.clientKeyFile = clientKeyFile + c.clientCertFile = clientCertFile + } +} diff --git a/core/client/client.go b/core/client/client.go index 943d14c30..5920415c1 100644 --- a/core/client/client.go +++ b/core/client/client.go @@ -1,97 +1,74 @@ // Package client contains the client for interacting with the Kwil public API. // It's supposed to be used as go-sdk for Kwil, currently used by the Kwil CLI. - package client import ( "context" "encoding/base64" "encoding/json" - "errors" "fmt" - "math/big" - "net/http" "net/url" "time" "github.com/cstockton/go-conv" - "github.com/kwilteam/kwil-db/core/crypto" "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" - rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" - httpRPC "github.com/kwilteam/kwil-db/core/rpc/client/user/http" + "github.com/kwilteam/kwil-db/core/rpc/client/user" + "github.com/kwilteam/kwil-db/core/rpc/client/user/http" "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" "github.com/kwilteam/kwil-db/core/utils" "go.uber.org/zap" - "go.uber.org/zap/zapcore" grpcCodes "google.golang.org/grpc/codes" grpcStatus "google.golang.org/grpc/status" ) -// RPCClient defines the methods that the transport layer should implement. -type RPCClient interface { - Close() error - ChainInfo(ctx context.Context) (*types.ChainInfo, error) - Call(ctx context.Context, req *transactions.CallMessage, opts ...rpcClient.ActionCallOption) ([]map[string]any, error) - TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) - GetTarget() string - GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) - Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) - ListDatabases(ctx context.Context, acctID []byte) ([]string, error) - GetAccount(ctx context.Context, acctID []byte, status types.AccountStatus) (*types.Account, error) - Broadcast(ctx context.Context, tx *transactions.Transaction) ([]byte, error) - Ping(ctx context.Context) (string, error) - EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) - ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) - CurrentValidators(ctx context.Context) ([]*types.Validator, error) - VerifySignature(ctx context.Context, sender []byte, signature *auth.Signature, message []byte) error -} - -var ( - ErrNotFound = errors.New("not found") -) - -// Client wraps the methods to interact with the Kwil public API. -// All the transport level details are encapsulated in the rpc. +// Client is a Kwil client that can interact with the main public Kwil RPC. type Client struct { - rpc RPCClient - Signer auth.Signer - logger log.Logger + txClient user.TxSvcClient + Signer auth.Signer + logger log.Logger // chainID is used when creating transactions as replay protection since the // signatures will only be valid on this network. - chainID string - target string - cookie *http.Cookie // current session cookie - tlsCertFile string // the tls cert file path + chainID string + + noWarnings bool // silence warning logs } -// Dial creates a Kwil client. It will by default use http connection, which -// can be overridden by using WithRPCClient. -func Dial(ctx context.Context, target string, opts ...Option) (c *Client, err error) { - c = &Client{ - logger: log.NewNoOp(), // by default, we do not want to force client to log anything - target: target, +// Dial creates a Kwil client. It will dial the remote host via HTTP, and +// verify the chain ID of the remote host against the chain ID passed in. +func Dial(ctx context.Context, target string, options *ClientOptions) (c *Client, err error) { + parsedUrl, err := url.Parse(target) + if err != nil { + return nil, fmt.Errorf("parse url: %w", err) } - for _, opt := range opts { - opt(c) - } + httpClient := http.NewClient(parsedUrl) - if c.rpc == nil { - hc, err := httpRPC.Dial(target) - // NOTE: target will be ignored if WithRPCClient is passed - if err != nil { - return nil, err - } - c.rpc = hc + clt, err := WrapClient(ctx, httpClient, options) + if err != nil { + return nil, fmt.Errorf("wrap client: %w", err) } - zapFields := []zapcore.Field{ - zap.String("host", c.rpc.GetTarget()), - } + clt.logger = *clt.logger.Named("client").With(zap.String("host", target)) + + return clt, nil +} - c.logger = *c.logger.Named("client").With(zapFields...) +// WrapClient wraps an rpc client with a Kwil client. +// It provides a way to use a custom rpc client with the Kwil client. +// Unless a custom rpc client is needed, use Dial instead. +func WrapClient(ctx context.Context, client user.TxSvcClient, options *ClientOptions) (*Client, error) { + clientOptions := DefaultOptions() + clientOptions.Apply(options) + + c := &Client{ + txClient: client, + Signer: clientOptions.Signer, + logger: clientOptions.Logger, + chainID: clientOptions.ChainID, + noWarnings: clientOptions.Silence, + } chainInfo, err := c.ChainInfo(ctx) if err != nil { @@ -99,30 +76,26 @@ func Dial(ctx context.Context, target string, opts ...Option) (c *Client, err er } chainID := chainInfo.ChainID if c.chainID == "" { - // TODO: make this an error instead, or allowed given an Option and/or if TLS is used - c.logger.Warn("chain ID not set, trusting chain ID from remote host!", zap.String("chainID", chainID)) + if !c.noWarnings { + c.logger.Warn("chain ID not set, trusting chain ID from remote host!", zap.String("chainID", chainID)) + } c.chainID = chainID } else if c.chainID != chainID { - c.Close() return nil, fmt.Errorf("remote host chain ID %q != client configured %q", chainID, c.chainID) } return c, nil } -func (c *Client) Close() error { - return c.rpc.Close() -} - // ChainInfo get the current blockchain information like chain ID and best block // height/hash. func (c *Client) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { - return c.rpc.ChainInfo(ctx) + return c.txClient.ChainInfo(ctx) } // GetSchema gets a schema by dbid. func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) { - ds, err := c.rpc.GetSchema(ctx, dbid) + ds, err := c.txClient.GetSchema(ctx, dbid) if err != nil { return nil, err } @@ -140,8 +113,7 @@ func (c *Client) DeployDatabase(ctx context.Context, payload *transactions.Schem c.logger.Debug("deploying database", zap.String("signature_type", tx.Signature.Type), zap.String("signature", base64.StdEncoding.EncodeToString(tx.Signature.Signature))) - - return c.rpc.Broadcast(ctx, tx) + return c.txClient.Broadcast(ctx, tx) } // DropDatabase drops a database by name, using the configured signer to derive @@ -166,7 +138,7 @@ func (c *Client) DropDatabaseID(ctx context.Context, dbid string, opts ...TxOpt) zap.String("signature_type", tx.Signature.Type), zap.String("signature", base64.StdEncoding.EncodeToString(tx.Signature.Signature))) - res, err := c.rpc.Broadcast(ctx, tx) + res, err := c.txClient.Broadcast(ctx, tx) if err != nil { return nil, err } @@ -198,17 +170,11 @@ func (c *Client) ExecuteAction(ctx context.Context, dbid string, action string, zap.String("signature_type", tx.Signature.Type), zap.String("signature", base64.StdEncoding.EncodeToString(tx.Signature.Signature))) - return c.rpc.Broadcast(ctx, tx) + return c.txClient.Broadcast(ctx, tx) } -// CallAction calls an action. It returns the records. -func (c *Client) CallAction(ctx context.Context, dbid string, action string, inputs []any, opts ...CallOpt) (*Records, error) { - callOpts := &callOptions{} // TODO: remove - - for _, opt := range opts { - opt(callOpts) - } - +// CallAction call an action. It returns the result records. +func (c *Client) CallAction(ctx context.Context, dbid string, action string, inputs []any) (*Records, error) { stringInputs, err := convertTuple(inputs) if err != nil { return nil, err @@ -225,15 +191,12 @@ func (c *Client) CallAction(ctx context.Context, dbid string, action string, inp return nil, fmt.Errorf("create signed message: %w", err) } - msg.AuthType = c.Signer.AuthType() - msg.Sender = c.Signer.Identity() - - // NOTE: only HTTP RPC supports authn cookie - var actCallOpts []rpcClient.ActionCallOption - if c.cookie != nil { - actCallOpts = append(actCallOpts, rpcClient.WithAuthCookie(c.cookie)) + if c.Signer != nil { + msg.AuthType = c.Signer.AuthType() + msg.Sender = c.Signer.Identity() } - res, err := c.rpc.Call(ctx, msg, actCallOpts...) + + res, err := c.txClient.Call(ctx, msg) if err != nil { return nil, fmt.Errorf("call action: %w", err) } @@ -257,7 +220,7 @@ func DecodeOutputs(bts []byte) ([]map[string]any, error) { // Query executes a query func (c *Client) Query(ctx context.Context, dbid string, query string) (*Records, error) { - res, err := c.rpc.Query(ctx, dbid, query) + res, err := c.txClient.Query(ctx, dbid, query) if err != nil { return nil, err } @@ -266,101 +229,15 @@ func (c *Client) Query(ctx context.Context, dbid string, query string) (*Records } func (c *Client) ListDatabases(ctx context.Context, owner []byte) ([]string, error) { - return c.rpc.ListDatabases(ctx, owner) + return c.txClient.ListDatabases(ctx, owner) } func (c *Client) Ping(ctx context.Context) (string, error) { - return c.rpc.Ping(ctx) + return c.txClient.Ping(ctx) } func (c *Client) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) { - return c.rpc.GetAccount(ctx, pubKey, status) -} - -func (c *Client) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { - res, err := c.rpc.ValidatorJoinStatus(ctx, pubKey) - if err != nil { - if stat, ok := grpcStatus.FromError(err); ok { - if stat.Code() == grpcCodes.NotFound { - return nil, ErrNotFound - } - } - return nil, err - } - return res, nil -} - -func (c *Client) CurrentValidators(ctx context.Context) ([]*types.Validator, error) { - return c.rpc.CurrentValidators(ctx) -} - -func (c *Client) ApproveValidator(ctx context.Context, joiner []byte, opts ...TxOpt) ([]byte, error) { - _, err := crypto.Ed25519PublicKeyFromBytes(joiner) - if err != nil { - return nil, fmt.Errorf("invalid candidate validator public key: %w", err) - } - payload := &transactions.ValidatorApprove{ - Candidate: joiner, - } - tx, err := c.newTx(ctx, payload, opts...) - if err != nil { - return nil, err - } - - hash, err := c.rpc.Broadcast(ctx, tx) - if err != nil { - return nil, err - } - return hash, nil -} - -// RemoveValidator makes a transaction proposing to remove a validator. This is -// only useful if the Client's signing key is a current validator key. -func (c *Client) RemoveValidator(ctx context.Context, target []byte, opts ...TxOpt) ([]byte, error) { - _, err := crypto.Ed25519PublicKeyFromBytes(target) - if err != nil { - return nil, fmt.Errorf("invalid target validator public key: %w", err) - } - payload := &transactions.ValidatorRemove{ - Validator: target, - } - tx, err := c.newTx(ctx, payload, opts...) - if err != nil { - return nil, err - } - - return c.rpc.Broadcast(ctx, tx) -} - -func (c *Client) ValidatorJoin(ctx context.Context) ([]byte, error) { - const power = 1 - return c.validatorUpdate(ctx, power) -} - -func (c *Client) ValidatorLeave(ctx context.Context) ([]byte, error) { - return c.validatorUpdate(ctx, 0) -} - -func (c *Client) validatorUpdate(ctx context.Context, power int64, opts ...TxOpt) ([]byte, error) { - var payload transactions.Payload - if power <= 0 { - payload = &transactions.ValidatorLeave{} - } else { - payload = &transactions.ValidatorJoin{ - Power: uint64(power), - } - } - - tx, err := c.newTx(ctx, payload, opts...) - if err != nil { - return nil, err - } - - hash, err := c.rpc.Broadcast(ctx, tx) - if err != nil { - return nil, err - } - return hash, nil + return c.txClient.GetAccount(ctx, pubKey, status) } // convertTuples converts user passed tuples to strings. @@ -396,7 +273,7 @@ func convertTuple(tuple []any) ([]string, error) { // TxQuery get transaction by hash func (c *Client) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) { - res, err := c.rpc.TxQuery(ctx, txHash) + res, err := c.txClient.TxQuery(ctx, txHash) if err != nil { return nil, err } @@ -432,52 +309,6 @@ func (c *Client) WaitTx(ctx context.Context, txHash []byte, interval time.Durati } } -// VerifySignature verifies a signature through API. -// An ErrInvalidSignature is returned if the signature is invalid. -func (c *Client) VerifySignature(ctx context.Context, pubKey []byte, - signature *auth.Signature, message []byte) error { - return c.rpc.VerifySignature(ctx, pubKey, signature, message) -} - -// GatewayAuthenticate authenticates the client with the gateway(KGW) provider. -// It returns a cookie so caller can choose a way to persist it if wanted. -// It also sets the cookie in the client, so that it can be used for subsequent requests. -// 'signMessage' is a function to present the message to be signed to -// the user, and returns error if the user declines to sign the message. -func (c *Client) GatewayAuthenticate(ctx context.Context, - signMessage func(message string) error) (*http.Cookie, error) { - // KGW auth is not part of Kwil API, we use a standard http client - // this client is to reuse connection - hc := httpRPC.DefaultHTTPClient() - - authURI, err := url.JoinPath(c.target, kgwAuthEndpoint) - if err != nil { - return nil, fmt.Errorf("%w", err) - } - - authParam, err := requestGatewayAuthParameter(hc, authURI) - if err != nil { - return nil, fmt.Errorf("request for authentication: %w", err) - } - - msg := composeGatewayAuthMessage(authParam, c.target, authURI, kgwAuthVersion, c.chainID) - decline := signMessage(msg) - if decline != nil { - return nil, decline - } - - sig, err := c.Signer.Sign([]byte(msg)) - if err != nil { - return nil, fmt.Errorf("sign message: %w", err) - } - - cookie, err := requestGatewayAuthCookie(hc, c.target, authParam.Nonce, - c.Signer.Identity(), sig) - if err != nil { - return nil, fmt.Errorf("request for token: %w", err) - } - - // set cookie for current session - c.cookie = cookie - return cookie, nil +func (c *Client) ChainID() string { + return c.chainID } diff --git a/core/client/iter.go b/core/client/iter.go index 0266f500d..4cb98bc8a 100644 --- a/core/client/iter.go +++ b/core/client/iter.go @@ -77,173 +77,3 @@ func (r Record) String() map[string]string { return rec } - -/* -func (r *Records) Scan(objects []interface{}) error { - if !r.Next() { - return errors.New("no more records") - } - - if !isSliceOfPointers(objects) { - return errors.New("objects must be a slice of pointers") - } - - for i, record := range r.records { - obj := objects[i] - err := record.Scan(obj) - if err != nil { - return err - } - } - - return nil -} - -func isSliceOfPointers(i interface{}) bool { - v := reflect.ValueOf(i) - if v.Kind() != reflect.Slice { - return false - } - - return v.Type().Elem().Kind() == reflect.Ptr -} - -func (r *Record) Scan(obj any) error { - // check that obj is a pointer - if reflect.TypeOf(obj).Kind() != reflect.Ptr { - return errors.New("obj must be a pointer") - } - - val := reflect.ValueOf(obj) - // check that obj is a struct - switch reflect.TypeOf(obj).Kind() { - case reflect.Struct: - return r.convertIntoStruct(val) - case reflect.Slice: - return r.convertIntoSlice(val) - case reflect.Map: - return r.convertIntoMap(val) - case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Bool: - return r.convertIntoScalarValue(val) - default: - return fmt.Errorf("record scan error: unsupported type: %s", reflect.TypeOf(obj).Kind().String()) - } -} - -func (r *Record) convertIntoStruct(obj reflect.Value) error { - objType := obj.Type() - - if obj.Kind() != reflect.Ptr || obj.Elem().Kind() != reflect.Struct { - return fmt.Errorf("expected pointer to struct, got %s", objType) - } - - structValue := obj.Elem() - structType := structValue.Type() - - for i := 0; i < structValue.NumField(); i++ { - field := structValue.Field(i) - fieldType := structType.Field(i) - - fieldName := fieldType.Name - mapValue, found := (*r)[fieldName] - if !found { - continue - } - - fieldValue := reflect.ValueOf(mapValue) - err := convertIntoScalar(field, fieldValue) - if err != nil { - return err - } - } - - return nil -} - -func (r *Record) convertIntoSlice(sliceValue reflect.Value) error { - if sliceValue.IsNil() { - sliceValue.Set(reflect.MakeSlice(sliceValue.Type(), 0, 0)) - } - - for _, value := range *r { - sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(value))) - } - - return nil -} - -func (r *Record) convertIntoMap(mapValue reflect.Value) error { - if mapValue.IsNil() { - mapValue.Set(reflect.MakeMap(mapValue.Type())) - } - - for key, value := range *r { - mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value)) - } - - return nil -} - -func (r *Record) convertIntoScalarValue(scalarValue reflect.Value) error { - return convertIntoScalar(scalarValue, r.values()) -} - -func convertIntoScalar(scalarValue reflect.Value, val any) error { - if !scalarValue.CanSet() { - return errors.New("scalar value cannot be set") - } - - switch scalarValue.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - intVal, err := conv.Int64(val) - if err != nil { - return err - } - - scalarValue.SetInt(intVal) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - uintVal, err := conv.Uint64(val) - if err != nil { - return err - } - - scalarValue.SetUint(uintVal) - return nil - case reflect.Float32, reflect.Float64: - floatVal, err := conv.Float64(val) - if err != nil { - return err - } - - scalarValue.SetFloat(floatVal) - return nil - case reflect.String: - stringVal, err := conv.String(val) - if err != nil { - return err - } - - scalarValue.SetString(stringVal) - return nil - case reflect.Bool: - boolVal, err := conv.Bool(val) - if err != nil { - return err - } - - scalarValue.SetBool(boolVal) - return nil - default: - return fmt.Errorf("scalar conversion error: unsupported type: %s", scalarValue.Kind().String()) - } -} - -func (r Record) values() []any { - var values []any - for _, value := range r { - values = append(values, value) - } - return values -} -*/ diff --git a/core/client/kgw.go b/core/client/kgw.go deleted file mode 100644 index b249ee2a4..000000000 --- a/core/client/kgw.go +++ /dev/null @@ -1,168 +0,0 @@ -package client - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "net/url" - - "github.com/kwilteam/kwil-db/core/crypto/auth" -) - -// kgw handles the authentication with KGW provider. -// KGW is a LB that als provides authentication for Kwil. It only supports HTTP. -// This is not part of core Kwil API, thus we implement it here. -// -// The authentication process is as follows: -// 1. Client starts an authentication session to KGW provider by sending a GET -// request to /auth endpoint, and KGW will return authn parameters. -// 2. Client composes a message using returned parameters and configuration, -// then presents the message to the user to sign. -// 3. Then user signs the message and passes the signature back to the client. -// 4. Client identifies itself by sending a POST request to the KGW provider, -// and KGW will return a cookie if the signature is valid. -// 5. Following requests to the KGW provider should include the cookie for -// authentication required endpoints. - -const ( - kgwAuthVersion = "1" - kgwAuthEndpoint = "/auth" - kgwAuthCookieName = "kgw_session" -) - -// gatewayAuthParameter defines the result of GET request for gateway(KGW) -// authentication. It's the parameters that will be used to compose the -// message(SIWE like) to sign. -type gatewayAuthParameter struct { - Nonce string `json:"nonce"` - Statement string `json:"statement"` // optional - IssueAt string `json:"issue_at"` - ExpirationTime string `json:"expiration_time"` -} - -// gatewayAuthGetResponse defines the response of GET request for gateway(KGW) authentication. -type gatewayAuthGetResponse struct { - Result *gatewayAuthParameter `json:"result"` - Error string `json:"error"` -} - -// requestGatewayAuthParameter requests authentication parameters from the gateway(KGW) provider. -// This will send a GET request to KGW provider, and the provider will return -// parameters that the user could use to compose a message to sign. -func requestGatewayAuthParameter(hc *http.Client, target string) (*gatewayAuthParameter, error) { - req, err := http.NewRequest(http.MethodGet, target, nil) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := hc.Do(req) - if err != nil { - return nil, fmt.Errorf("request authn: %w", err) - } - defer resp.Body.Close() - - var r gatewayAuthGetResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, fmt.Errorf("unmarshal response: %w", err) - } - - if r.Error != "" { - return nil, fmt.Errorf("got error response: %s", r.Error) - } - - return r.Result, nil -} - -// composeGatewayAuthMessage composes the SIWE-like message to sign. -// param is the result of GET request for authentication. -// ALl the other parameters are expected from config. -func composeGatewayAuthMessage(param *gatewayAuthParameter, domain string, uri string, - version string, chainID string) string { - var msg bytes.Buffer - msg.WriteString( - fmt.Sprintf("%s wants you to sign in with your account:\n", domain)) - msg.WriteString("\n") - if param.Statement != "" { - msg.WriteString(fmt.Sprintf("%s\n", param.Statement)) - } - msg.WriteString("\n") - msg.WriteString(fmt.Sprintf("URI: %s\n", uri)) - msg.WriteString(fmt.Sprintf("Version: %s\n", version)) - msg.WriteString(fmt.Sprintf("Chain ID: %s\n", chainID)) - msg.WriteString(fmt.Sprintf("Nonce: %s\n", param.Nonce)) - msg.WriteString(fmt.Sprintf("Issue At: %s\n", param.IssueAt)) - msg.WriteString(fmt.Sprintf("Expiration Time: %s\n", param.ExpirationTime)) - return msg.String() -} - -type gatewayAuthPostResponse struct { - Result string `json:"result"` - Error string `json:"error"` -} - -// gatewayAuthPostPayload defines the payload of POST request for authentication -type gatewayAuthPostPayload struct { - Nonce string `json:"nonce"` // identifier for authn session - Sender []byte `json:"sender"` // sender public key - Signature *auth.Signature `json:"signature"` -} - -// requestGatewayAuthCookie requests an authenticated cookie from the gateway(KGW) provider. -// This will send a POST request to the KGW provider, and the provider will -// return a cookie. -func requestGatewayAuthCookie(hc *http.Client, target string, nonce string, - sender []byte, sig *auth.Signature) (*http.Cookie, error) { - targetURL, err := url.Parse(target) - if err != nil { - return nil, fmt.Errorf("parse target: %w", err) - } - - authURL, err := targetURL.Parse(kgwAuthEndpoint) - if err != nil { - return nil, fmt.Errorf("parse authURL: %w", err) - } - - payload := gatewayAuthPostPayload{ - Nonce: nonce, - Signature: sig, - Sender: sender, - } - - buf := new(bytes.Buffer) - err = json.NewEncoder(buf).Encode(&payload) - if err != nil { - return nil, fmt.Errorf("marshal payload: %w", err) - } - - req, err := http.NewRequest(http.MethodPost, authURL.String(), buf) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := hc.Do(req) - if err != nil { - return nil, fmt.Errorf("request authn: %w", err) - } - defer resp.Body.Close() - - var r gatewayAuthPostResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, fmt.Errorf("unmarshal response: %w", err) - } - - if r.Error != "" { - return nil, fmt.Errorf("error response: %s", r.Error) - } - - // NOTE: one cookie is enough for now - for _, c := range resp.Cookies() { - if c.Name == kgwAuthCookieName { - return c, nil - } - } - - return nil, fmt.Errorf("no cookie returned") -} diff --git a/core/client/kgw_test.go b/core/client/kgw_test.go deleted file mode 100644 index 8308f9269..000000000 --- a/core/client/kgw_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package client - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_composeKGWAuthMessage(t *testing.T) { - param := &gatewayAuthParameter{ - Nonce: "123456", - Statement: "eww", - IssueAt: "2023-11-05T22:57:46Z", - ExpirationTime: "2023-11-05T22:58:16Z", - } - msg := composeGatewayAuthMessage(param, - "https://example.com", "https://example.com/auth", "1", "test-chain") - want := "https://example.com wants you to sign in with your account:\n\neww\n\nURI: https://example.com/auth\nVersion: 1\nChain ID: test-chain\nNonce: 123456\nIssue At: 2023-11-05T22:57:46Z\nExpiration Time: 2023-11-05T22:58:16Z\n" - assert.Equal(t, want, msg, "should be equal") -} diff --git a/core/client/opts.go b/core/client/opts.go index 72bd23c74..e10c915e3 100644 --- a/core/client/opts.go +++ b/core/client/opts.go @@ -7,57 +7,86 @@ import ( "github.com/kwilteam/kwil-db/core/log" ) -type Option func(*Client) +// ClientOptions are options that can be set for the client +type ClientOptions struct { + // Logger is the logger to use for the client. + Logger log.Logger -func WithLogger(logger log.Logger) Option { - return func(c *Client) { - c.logger = logger - } + // Signer will be used to sign transactions. + Signer auth.Signer + + // The chain ID will be used in all transactions, which helps prevent replay attacks on + // different chains. On the initial connection, the remote node's chain ID is + // checked against ours to ensure were are on the right network. If the chain ID + // is empty, we will create and sign transactions for whatever network the + // remote node claims, which should only be done for testing or when in secure + // communication with a trusted node (using TLS or Unix sockets). + ChainID string + + // Silence silences warnings logged from the client. + Silence bool } -// WithSigner sets a signer to use when authoring transactions. The chain ID -// will be used in all transactions, which helps prevent replay attacks on -// different chains. On the initial connection, the remote node's chain ID is -// checked against ours to ensure were are on the right network. If the chain ID -// is empty, we will create and sign transactions for whatever network the -// remote node claims, which should only be done for testing or when in secure -// (TLS) communication with a trusted node. -func WithSigner(signer auth.Signer, chainID string) Option { - return func(c *Client) { - c.Signer = signer - c.chainID = chainID +// Apply applies the passed options to the receiver. +func (c *ClientOptions) Apply(opts *ClientOptions) { + if opts == nil { + return + } + + if opts.Logger.L != nil { + c.Logger = opts.Logger + } + + if opts.Signer != nil { + c.Signer = opts.Signer } + + if opts.ChainID != "" { + c.ChainID = opts.ChainID + } + + c.Silence = opts.Silence } -func WithTLSCert(certFile string) Option { - return func(c *Client) { - c.tlsCertFile = certFile +// DefaultOptions returns the default options for the client. +func DefaultOptions() *ClientOptions { + return &ClientOptions{ + Logger: log.NewNoOp(), } } -func WithRPCClient(tc RPCClient) Option { - return func(c *Client) { - c.rpc = tc +type Option func(*ClientOptions) + +func WithLogger(logger log.Logger) Option { + return func(c *ClientOptions) { + c.Logger = logger } } -type callOptions struct { - // forceAuthenticated is used to force the client to authenticate - // if nil, the client will use the default value - // if false, it will not authenticate - // if true, it will authenticate - forceAuthenticated *bool // is pointer necessary here? +// WithSigner sets a signer to use when authoring transactions. +func WithSigner(signer auth.Signer) Option { + return func(c *ClientOptions) { + c.Signer = signer + } } -type CallOpt func(*callOptions) +// WithChainID sets the chain ID to use when authoring transactions. The chain ID +// will be used in all transactions, which helps prevent replay attacks on +// different chains. On the initial connection, the remote node's chain ID is +// checked against ours to ensure were are on the right network. If the chain ID +// is empty, we will create and sign transactions for whatever network the +// remote node claims, which should only be done for testing or when in secure +// communication with a trusted node (using TLS or Unix sockets). +func WithChainID(chainID string) Option { + return func(c *ClientOptions) { + c.ChainID = chainID + } +} -// Authenticated can be used to force the client to authenticate (or not) -// if true, the client will authenticate. if false, it will not authenticate -// if nil, the client will decide itself -func Authenticated(shouldSign bool) CallOpt { - return func(o *callOptions) { - copied := shouldSign - o.forceAuthenticated = &copied +// SilenceWarnings silences warnings from the client. +func SilenceWarnings() Option { + return func(c *ClientOptions) { + c.Silence = true } } diff --git a/core/client/tx.go b/core/client/tx.go index 4d523ef2c..42e502967 100644 --- a/core/client/tx.go +++ b/core/client/tx.go @@ -10,6 +10,10 @@ import ( // newTx creates a new Transaction signed by the Client's Signer func (c *Client) newTx(ctx context.Context, data transactions.Payload, opts ...TxOpt) (*transactions.Transaction, error) { + if c.Signer == nil { + return nil, fmt.Errorf("signer must be set to create a transaction") + } + txOpts := &txOptions{} for _, opt := range opts { opt(txOpts) @@ -20,10 +24,11 @@ func (c *Client) newTx(ctx context.Context, data transactions.Payload, opts ...T nonce = uint64(txOpts.nonce) } else { // Get the latest nonce for the account, if it exists. - acc, err := c.rpc.GetAccount(ctx, c.Signer.Identity(), types.AccountStatusPending) + acc, err := c.txClient.GetAccount(ctx, c.Signer.Identity(), types.AccountStatusPending) if err != nil { return nil, err } + // NOTE: an error type would be more robust signalling of a non-existent // account, but presently a nil ID is set by internal/accounts. if len(acc.Identifier) > 0 { @@ -40,7 +45,7 @@ func (c *Client) newTx(ctx context.Context, data transactions.Payload, opts ...T } // estimate price - price, err := c.rpc.EstimateCost(ctx, tx) + price, err := c.txClient.EstimateCost(ctx, tx) if err != nil { return nil, fmt.Errorf("failed to estimate price: %w", err) } diff --git a/core/gatewayclient/client.go b/core/gatewayclient/client.go new file mode 100644 index 000000000..69880632b --- /dev/null +++ b/core/gatewayclient/client.go @@ -0,0 +1,164 @@ +// package gatewayclient implements a client for kwild that can also authenticate +// with a kwil gateway. +package gatewayclient + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/http/cookiejar" + "net/url" + + "github.com/kwilteam/kwil-db/core/client" + rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/core/rpc/client/gateway" + httpGateway "github.com/kwilteam/kwil-db/core/rpc/client/gateway/http" + httpTx "github.com/kwilteam/kwil-db/core/rpc/client/user/http" + gatewayTypes "github.com/kwilteam/kwil-db/core/types/gateway" +) + +// GatewayClient is a client that is made to interact with a kwil gateway. +// It inherits the functionality of the main Kwil client, but also provides +// authentication cookies to the gateway. +// It automatically handles the authentication process with the gateway. +type GatewayClient struct { + client.Client + + target *url.URL + + httpClient *http.Client + gatewayClient gateway.GatewayClient + + gatewaySigner GatewayAuthSignFunc // a hook for when the gateway authentication is needed +} + +func NewGatewayClient(ctx context.Context, target string, opts *GatewayOptions) (*GatewayClient, error) { + options := DefaultOptions() + options.Apply(opts) + + cookieJar, err := cookiejar.New(nil) + if err != nil { + return nil, fmt.Errorf("create cookie jar: %w", err) + } + + httpClient := &http.Client{ + Jar: cookieJar, + } + + parsedTarget, err := url.Parse(target) + if err != nil { + return nil, fmt.Errorf("parse target: %w", err) + } + + txClient := httpTx.NewClient(parsedTarget, httpTx.WithHTTPClient(httpClient)) + + coreClient, err := client.WrapClient(ctx, txClient, &options.ClientOptions) + if err != nil { + return nil, fmt.Errorf("wrap client: %w", err) + } + + gatewayRPC, err := httpGateway.NewGatewayHttpClient(parsedTarget, httpGateway.WithHTTPClient(httpClient)) + if err != nil { + return nil, fmt.Errorf("create gateway rpc client: %w", err) + } + + g := &GatewayClient{ + Client: *coreClient, + httpClient: httpClient, + gatewaySigner: options.AuthSignFunc, + gatewayClient: gatewayRPC, + target: parsedTarget, + } + + return g, nil +} + +// CallAction call an action. It returns the result records. If authentication is needed, +// it will call the gatewaySigner to sign the authentication message. +func (c *GatewayClient) CallAction(ctx context.Context, dbid string, action string, inputs []any) (*client.Records, error) { + // we will try to call with the current cookies set. If we receive an error and it is an auth error, + // we will re-auth and retry. We will only retry once. + res, err := c.Client.CallAction(ctx, dbid, action, inputs) + if err == nil { + return res, nil + } + if !errors.Is(err, rpcClient.ErrUnauthorized) { + return nil, err + } + + // we need to authenticate + err = c.authenticate(ctx) + if err != nil { + return nil, fmt.Errorf("authenticate error: %w", err) + } + + // retry the call + return c.Client.CallAction(ctx, dbid, action, inputs) +} + +// authenticate authenticates the client with the gateway. +func (c *GatewayClient) authenticate(ctx context.Context) error { + authParam, err := c.gatewayClient.GetAuthParameter(ctx) + if err != nil { + return fmt.Errorf("get auth parameter: %w", err) + } + + authURI, err := url.JoinPath(c.target.String(), gateway.AuthEndpoint) + if err != nil { + return fmt.Errorf("join path: %w", err) + } + + msg := composeGatewayAuthMessage(authParam, c.target.String(), authURI, kgwAuthVersion, c.Client.ChainID()) + + if c.Signer == nil { + return fmt.Errorf("cannot authenticate to gateway without a signer") + } + sig, err := c.gatewaySigner(msg, c.Signer) + if err != nil { + return fmt.Errorf("sign message: %w", err) + } + + // send the auth request + return c.gatewayClient.Auth(ctx, &gatewayTypes.GatewayAuth{ + Nonce: authParam.Nonce, + Sender: c.Signer.Identity(), + Signature: sig, + }) +} + +// GetAuthCookie returns the authentication cookie currently being used. +// If no authentication cookie is being used, it returns nil, false. +func (c *GatewayClient) GetAuthCookie() (cookie *http.Cookie, found bool) { + cookies := c.httpClient.Jar.Cookies(c.target) + for _, cookie := range cookies { + if cookie.Name == kgwAuthCookieName { + return cookie, true + } + } + return nil, false +} + +// SetAuthCookie sets the authentication cookie to be used. +// If the cookie is not valid for the client target, it returns an error. +// It will overwrite any existing authentication cookie. +func (c *GatewayClient) SetAuthCookie(cookie *http.Cookie) error { + if cookie.Domain != "" && cookie.Domain != c.target.Host { + return fmt.Errorf("cookie domain %s not valid for host %s", cookie.Domain, c.target.Host) + } + if cookie.Name != kgwAuthCookieName { + return fmt.Errorf("cookie name %s not valid", cookie.Name) + } + + c.httpClient.Jar.SetCookies(c.target, []*http.Cookie{cookie}) + + return nil +} + +// Authenticate will authenticate the client with the gateway. +// This is not necessary, as the client will automatically authenticate when needed, +// however it can be useful if the client desires to control when the authentication +// occurs / wants to manually force re-authentication. +func (c *GatewayClient) Authenticate(ctx context.Context) error { + return c.authenticate(ctx) +} diff --git a/core/gatewayclient/msg.go b/core/gatewayclient/msg.go new file mode 100644 index 000000000..54d0b4539 --- /dev/null +++ b/core/gatewayclient/msg.go @@ -0,0 +1,60 @@ +package gatewayclient + +import ( + "bytes" + "fmt" + + "github.com/kwilteam/kwil-db/core/crypto/auth" + types "github.com/kwilteam/kwil-db/core/types/gateway" +) + +// kgw handles the authentication with KGW provider. +// KGW is a LB that als provides authentication for Kwil. It only supports HTTP. +// This is not part of core Kwil API, thus we implement it here. +// +// The authentication process is as follows: +// 1. Client starts an authentication session to KGW provider by sending a GET +// request to /auth endpoint, and KGW will return authn parameters. +// 2. Client composes a message using returned parameters and configuration, +// then presents the message to the user to sign. +// 3. Then user signs the message and passes the signature back to the client. +// 4. Client identifies itself by sending a POST request to the KGW provider, +// and KGW will return a cookie if the signature is valid. +// 5. Following requests to the KGW provider should include the cookie for +// authentication required endpoints. + +const ( + kgwAuthVersion = "1" + kgwAuthCookieName = "kgw_session" +) + +// GatewayAuthSignFunc is the function that signs the authentication message. +type GatewayAuthSignFunc func(message string, signer auth.Signer) (*auth.Signature, error) + +// defaultGatewayAuthSignFunc is the default function that signs the message. +// It uses the local signer to sign the message. +func defaultGatewayAuthSignFunc(message string, signer auth.Signer) (*auth.Signature, error) { + return signer.Sign([]byte(message)) +} + +// composeGatewayAuthMessage composes the SIWE-like message to sign. +// param is the result of GET request for authentication. +// ALl the other parameters are expected from config. +func composeGatewayAuthMessage(param *types.GatewayAuthParameter, domain string, uri string, + version string, chainID string) string { + var msg bytes.Buffer + msg.WriteString( + fmt.Sprintf("%s wants you to sign in with your account:\n", domain)) + msg.WriteString("\n") + if param.Statement != "" { + msg.WriteString(fmt.Sprintf("%s\n", param.Statement)) + } + msg.WriteString("\n") + msg.WriteString(fmt.Sprintf("URI: %s\n", uri)) + msg.WriteString(fmt.Sprintf("Version: %s\n", version)) + msg.WriteString(fmt.Sprintf("Chain ID: %s\n", chainID)) + msg.WriteString(fmt.Sprintf("Nonce: %s\n", param.Nonce)) + msg.WriteString(fmt.Sprintf("Issue At: %s\n", param.IssueAt)) + msg.WriteString(fmt.Sprintf("Expiration Time: %s\n", param.ExpirationTime)) + return msg.String() +} diff --git a/core/gatewayclient/opts.go b/core/gatewayclient/opts.go new file mode 100644 index 000000000..b0b8987c4 --- /dev/null +++ b/core/gatewayclient/opts.go @@ -0,0 +1,35 @@ +package gatewayclient + +import ( + "github.com/kwilteam/kwil-db/core/client" +) + +// GatewayOptions are options that can be set for the gateway client +type GatewayOptions struct { + client.ClientOptions + + // AuthSignFunc is a function that will be used to sign gateway authentication messages. + AuthSignFunc GatewayAuthSignFunc +} + +// DefaultOptions returns the default options for the gateway client. +func DefaultOptions() *GatewayOptions { + return &GatewayOptions{ + ClientOptions: *client.DefaultOptions(), + + AuthSignFunc: defaultGatewayAuthSignFunc, + } +} + +// Apply applies the passed options to the receiver. +func (c *GatewayOptions) Apply(opt *GatewayOptions) { + if opt == nil { + return + } + + c.ClientOptions.Apply(&opt.ClientOptions) + + if opt.AuthSignFunc != nil { + c.AuthSignFunc = opt.AuthSignFunc + } +} diff --git a/core/go.mod b/core/go.mod index b6828191b..084be734f 100644 --- a/core/go.mod +++ b/core/go.mod @@ -3,15 +3,15 @@ module github.com/kwilteam/kwil-db/core go 1.21 require ( + github.com/antihax/optional v1.0.0 github.com/cstockton/go-conv v1.0.0 github.com/decred/dcrd/certgen v1.1.2 github.com/ethereum/go-ethereum v1.13.2 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 - golang.org/x/net v0.15.0 + golang.org/x/oauth2 v0.12.0 google.golang.org/genproto/googleapis/api v0.0.0-20231009173412-8bfb1ae86b6c - google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 ) @@ -42,10 +42,13 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.13.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/core/go.sum b/core/go.sum index 830356c54..2fffe8c93 100644 --- a/core/go.sum +++ b/core/go.sum @@ -4,6 +4,8 @@ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDO github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= @@ -54,6 +56,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -120,20 +123,30 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= google.golang.org/genproto/googleapis/api v0.0.0-20231009173412-8bfb1ae86b6c h1:0RtEmmHjemvUXloH7+RuBSIw7n+GEHMOMY1CkGYnWq4= diff --git a/core/rpc/client/admin/admin.go b/core/rpc/client/admin/admin.go new file mode 100644 index 000000000..a133f15d4 --- /dev/null +++ b/core/rpc/client/admin/admin.go @@ -0,0 +1,22 @@ +// package admin specifies the interface for the admin service client. +package admin + +import ( + "context" + + "github.com/kwilteam/kwil-db/core/types" + adminTypes "github.com/kwilteam/kwil-db/core/types/admin" +) + +type AdminClient interface { + Approve(ctx context.Context, publicKey []byte) ([]byte, error) + Join(ctx context.Context) ([]byte, error) + JoinStatus(ctx context.Context, pubkey []byte) (*types.JoinRequest, error) + Leave(ctx context.Context) ([]byte, error) + ListValidators(ctx context.Context) ([]*types.Validator, error) + Peers(ctx context.Context) ([]*adminTypes.PeerInfo, error) + Remove(ctx context.Context, publicKey []byte) ([]byte, error) + Status(ctx context.Context) (*adminTypes.Status, error) + Version(ctx context.Context) (string, error) + ListPendingJoins(ctx context.Context) ([]*types.JoinRequest, error) +} diff --git a/core/rpc/client/admin/admin_client.go b/core/rpc/client/admin/admin_client.go deleted file mode 100644 index a2c75dfd2..000000000 --- a/core/rpc/client/admin/admin_client.go +++ /dev/null @@ -1,104 +0,0 @@ -package admin - -import ( - "context" - "crypto/tls" - "time" - - admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" - types "github.com/kwilteam/kwil-db/core/types/admin" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -// AdminClient manages a connection to an authenticated node administrative gRPC -// service. -type AdminClient struct { - admClient admpb.AdminServiceClient - conn *grpc.ClientConn -} - -// New constructs an AdminClient with the provided TLS configuration -func New(target string, tlsCfg *tls.Config, opts ...grpc.DialOption) (*AdminClient, error) { - opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))) - conn, err := grpc.Dial(target, opts...) - if err != nil { - return nil, err - } - return &AdminClient{ - admClient: admpb.NewAdminServiceClient(conn), - conn: conn, - }, nil -} - -func (c *AdminClient) Close() error { - return c.conn.Close() -} - -func (c *AdminClient) Ping(ctx context.Context) (string, error) { - resp, err := c.admClient.Ping(ctx, &admpb.PingRequest{}) - if err != nil { - return "", err - } - return resp.Message, nil -} - -func (c *AdminClient) Version(ctx context.Context) (string, error) { - resp, err := c.admClient.Version(ctx, &admpb.VersionRequest{}) - if err != nil { - return "", err - } - return resp.VersionString, nil -} - -func convertNodeInfo(ni *admpb.NodeInfo) *types.NodeInfo { - return &types.NodeInfo{ - ChainID: ni.ChainId, - Name: ni.NodeName, - NodeID: ni.NodeId, - ProtocolVersion: ni.ProtocolVersion, - AppVersion: ni.AppVersion, - BlockVersion: ni.BlockVersion, - ListenAddr: ni.ListenAddr, - RPCAddr: ni.RpcAddr, - } -} - -func (c *AdminClient) Status(ctx context.Context) (*types.Status, error) { - resp, err := c.admClient.Status(ctx, &admpb.StatusRequest{}) - if err != nil { - return nil, err - } - return &types.Status{ - Node: convertNodeInfo(resp.Node), - Sync: &types.SyncInfo{ - AppHash: resp.Sync.AppHash, - BestBlockHash: resp.Sync.BestBlockHash, - BestBlockHeight: resp.Sync.BestBlockHeight, - BestBlockTime: time.UnixMilli(resp.Sync.BestBlockTime), - Syncing: resp.Sync.Syncing, - }, - Validator: &types.ValidatorInfo{ - PubKey: resp.Validator.Pubkey, - PubKeyType: resp.Validator.PubkeyType, - Power: resp.Validator.Power, - }, - }, nil -} - -func (c *AdminClient) Peers(ctx context.Context) ([]*types.PeerInfo, error) { - resp, err := c.admClient.Peers(ctx, &admpb.PeersRequest{}) - if err != nil { - return nil, err - } - peers := make([]*types.PeerInfo, len(resp.Peers)) - for i, pbPeer := range resp.Peers { - peers[i] = &types.PeerInfo{ - NodeInfo: convertNodeInfo(pbPeer.Node), - Inbound: pbPeer.Inbound, - RemoteAddr: pbPeer.RemoteAddr, - } - } - return peers, nil -} diff --git a/core/rpc/client/admin/grpc/client.go b/core/rpc/client/admin/grpc/client.go new file mode 100644 index 000000000..6ba4f5226 --- /dev/null +++ b/core/rpc/client/admin/grpc/client.go @@ -0,0 +1,170 @@ +// package grpc implements a grpc client for the Kwil admin client. +package grpc + +import ( + "context" + "time" + + "github.com/kwilteam/kwil-db/core/rpc/client" + admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" + "github.com/kwilteam/kwil-db/core/types" + adminTypes "github.com/kwilteam/kwil-db/core/types/admin" + "google.golang.org/grpc" +) + +// GrpcAdminClient is an grpc client for the Kwil admin service. +type GrpcAdminClient struct { + client admpb.AdminServiceClient +} + +// NewAdminClient creates a grpc client for the Kwil admin service. +func NewAdminClient(conn *grpc.ClientConn) *GrpcAdminClient { + return &GrpcAdminClient{ + client: admpb.NewAdminServiceClient(conn), + } +} + +func (c *GrpcAdminClient) Version(ctx context.Context) (string, error) { + resp, err := c.client.Version(ctx, &admpb.VersionRequest{}) + if err != nil { + return "", client.ConvertGRPCErr(err) + } + return resp.VersionString, nil +} + +func convertNodeInfo(ni *admpb.NodeInfo) *adminTypes.NodeInfo { + return &adminTypes.NodeInfo{ + ChainID: ni.ChainId, + Name: ni.NodeName, + NodeID: ni.NodeId, + ProtocolVersion: ni.ProtocolVersion, + AppVersion: ni.AppVersion, + BlockVersion: ni.BlockVersion, + ListenAddr: ni.ListenAddr, + RPCAddr: ni.RpcAddr, + } +} + +func (c *GrpcAdminClient) Status(ctx context.Context) (*adminTypes.Status, error) { + resp, err := c.client.Status(ctx, &admpb.StatusRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + return &adminTypes.Status{ + Node: convertNodeInfo(resp.Node), + Sync: &adminTypes.SyncInfo{ + AppHash: resp.Sync.AppHash, + BestBlockHash: resp.Sync.BestBlockHash, + BestBlockHeight: resp.Sync.BestBlockHeight, + BestBlockTime: time.UnixMilli(resp.Sync.BestBlockTime), + Syncing: resp.Sync.Syncing, + }, + Validator: &adminTypes.ValidatorInfo{ + PubKey: resp.Validator.Pubkey, + Power: resp.Validator.Power, + }, + }, nil +} + +func (c *GrpcAdminClient) Peers(ctx context.Context) ([]*adminTypes.PeerInfo, error) { + resp, err := c.client.Peers(ctx, &admpb.PeersRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + peers := make([]*adminTypes.PeerInfo, len(resp.Peers)) + for i, pbPeer := range resp.Peers { + peers[i] = &adminTypes.PeerInfo{ + NodeInfo: convertNodeInfo(pbPeer.Node), + Inbound: pbPeer.Inbound, + RemoteAddr: pbPeer.RemoteAddr, + } + } + return peers, nil +} + +// Approve approves a node to join the network. +// It returns a transaction hash. +func (c *GrpcAdminClient) Approve(ctx context.Context, publicKey []byte) ([]byte, error) { + resp, err := c.client.Approve(ctx, &admpb.ApproveRequest{Pubkey: publicKey}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + return resp.TxHash, nil +} + +// Join sends a node join request to the network from the connected node. +// It returns a transaction hash. +func (c *GrpcAdminClient) Join(ctx context.Context) ([]byte, error) { + resp, err := c.client.Join(ctx, &admpb.JoinRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + return resp.TxHash, nil +} + +// Leave sends a node leave request to the network from the connected node. +// It returns a transaction hash. +func (c *GrpcAdminClient) Leave(ctx context.Context) ([]byte, error) { + resp, err := c.client.Leave(ctx, &admpb.LeaveRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + return resp.TxHash, nil +} + +// Remove votes to remove a node from the network. +// It returns a transaction hash. +func (c *GrpcAdminClient) Remove(ctx context.Context, publicKey []byte) ([]byte, error) { + resp, err := c.client.Remove(ctx, &admpb.RemoveRequest{Pubkey: publicKey}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + return resp.TxHash, nil +} + +// JoinStatus returns the status of a node's join request. +func (c *GrpcAdminClient) JoinStatus(ctx context.Context, pubkey []byte) (*types.JoinRequest, error) { + resp, err := c.client.JoinStatus(ctx, &admpb.JoinStatusRequest{Pubkey: pubkey}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + + return convertPendingJoin(resp.JoinRequest), nil +} + +func (c *GrpcAdminClient) ListValidators(ctx context.Context) ([]*types.Validator, error) { + resp, err := c.client.ListValidators(ctx, &admpb.ListValidatorsRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + validators := make([]*types.Validator, len(resp.Validators)) + for i, v := range resp.Validators { + validators[i] = &types.Validator{ + PubKey: v.Pubkey, + Power: v.Power, + } + } + return validators, nil +} + +func (c *GrpcAdminClient) ListPendingJoins(ctx context.Context) ([]*types.JoinRequest, error) { + resp, err := c.client.ListPendingJoins(ctx, &admpb.ListJoinRequestsRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + joins := make([]*types.JoinRequest, len(resp.JoinRequests)) + for i, j := range resp.JoinRequests { + joins[i] = convertPendingJoin(j) + } + return joins, nil +} + +func convertPendingJoin(join *admpb.PendingJoin) *types.JoinRequest { + return &types.JoinRequest{ + Candidate: join.Candidate, + Power: join.Power, + Board: join.Board, + Approved: join.Approved, + ExpiresAt: join.ExpiresAt, + } +} diff --git a/core/rpc/client/defaults.go b/core/rpc/client/defaults.go new file mode 100644 index 000000000..8d6343b11 --- /dev/null +++ b/core/rpc/client/defaults.go @@ -0,0 +1,16 @@ +package client + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// DefaultGRPCOpts returns the default grpc options for the client. +func DefaultGRPCOpts() []grpc.DialOption { + return []grpc.DialOption{ + grpc.WithDefaultCallOptions( + grpc.MaxCallRecvMsgSize(64 * 1024 * 1024), // 64MiB limit on *responses*; sends are unlimited + ), + grpc.WithTransportCredentials(insecure.NewCredentials()), + } +} diff --git a/core/rpc/client/error.go b/core/rpc/client/error.go index c8644bfc9..553f55eca 100644 --- a/core/rpc/client/error.go +++ b/core/rpc/client/error.go @@ -1,7 +1,36 @@ package client -import "errors" +import ( + "errors" + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) var ( ErrInvalidSignature = errors.New("invalid signature") + // ErrUnauthorized is returned when the client is not authenticated + // It is the equivalent of http status code 401 + ErrUnauthorized = errors.New("unauthorized") + ErrNotFound = errors.New("not found") ) + +// convertErr will convert the error to a known type, if possible. +// It is expected that the error is from a gRPC call. +func ConvertGRPCErr(err error) error { + statusError, ok := status.FromError(err) + if !ok { + return fmt.Errorf("unrecognized error: %w", err) + } + + switch statusError.Code() { + case codes.OK: + // this should never happen? + return fmt.Errorf("unexpected OK status code returned error") + case codes.NotFound: + return ErrNotFound + } + + return fmt.Errorf("%v (%d)", statusError.Message(), statusError.Code()) +} diff --git a/core/rpc/client/function/function.go b/core/rpc/client/function/function.go new file mode 100644 index 000000000..0e147534a --- /dev/null +++ b/core/rpc/client/function/function.go @@ -0,0 +1,12 @@ +// package function specifies the client interface for Kwil's function service. +package function + +import ( + "context" + + "github.com/kwilteam/kwil-db/core/crypto/auth" +) + +type FunctionServiceClient interface { + VerifySignature(ctx context.Context, sender []byte, signature *auth.Signature, message []byte) error +} diff --git a/core/rpc/client/function/http/client.go b/core/rpc/client/function/http/client.go new file mode 100644 index 000000000..09fa7a305 --- /dev/null +++ b/core/rpc/client/function/http/client.go @@ -0,0 +1,67 @@ +package http + +import ( + "context" + "encoding/base64" + "errors" + "net/http" + "net/url" + + "github.com/kwilteam/kwil-db/core/crypto/auth" + httpFunction "github.com/kwilteam/kwil-db/core/rpc/http/function" +) + +type Client struct { + conn *httpFunction.APIClient + url *url.URL +} + +// NewClient creates a new http client for the Kwil user service +func NewClient(target *url.URL, opts ...ClientOption) *Client { + c := &Client{ + url: target, + } + + clientOpts := &clientOptions{ + client: &http.Client{}, + } + + for _, o := range opts { + o(clientOpts) + } + + cfg := httpFunction.NewConfiguration() + cfg.HTTPClient = clientOpts.client + cfg.BasePath = target.String() + cfg.Host = target.Host + cfg.Scheme = target.Scheme + + c.conn = httpFunction.NewAPIClient(cfg) + + return c +} + +func (c *Client) VerifySignature(ctx context.Context, sender []byte, signature *auth.Signature, message []byte) error { + result, res, err := c.conn.FunctionServiceApi.FunctionServiceVerifySignature(ctx, httpFunction.FunctionVerifySignatureRequest{ + Sender: base64.StdEncoding.EncodeToString(sender), + Msg: base64.StdEncoding.EncodeToString(message), + Signature: &httpFunction.TxSignature{ + SignatureBytes: base64.StdEncoding.EncodeToString(signature.Signature), + SignatureType: signature.Type, + }, + }) + if err != nil { + return err + } + defer res.Body.Close() + + if result.Error_ != "" { + return errors.New(result.Error_) + } + + if !result.Valid { + return errors.New("invalid signature") + } + + return nil +} diff --git a/core/rpc/client/function/http/opts.go b/core/rpc/client/function/http/opts.go new file mode 100644 index 000000000..9f5213085 --- /dev/null +++ b/core/rpc/client/function/http/opts.go @@ -0,0 +1,17 @@ +package http + +import "net/http" + +type ClientOption func(*clientOptions) + +// WithHTTPClient sets the http client for the client. +// This allows custom http clients to be used. +func WithHTTPClient(client *http.Client) ClientOption { + return func(c *clientOptions) { + c.client = client + } +} + +type clientOptions struct { + client *http.Client +} diff --git a/core/rpc/client/gateway/gateway.go b/core/rpc/client/gateway/gateway.go new file mode 100644 index 000000000..0f7dc8154 --- /dev/null +++ b/core/rpc/client/gateway/gateway.go @@ -0,0 +1,38 @@ +package gateway + +import ( + "context" + "fmt" + + "github.com/kwilteam/kwil-db/core/types/gateway" +) + +// GatewayClient is the interface for the Kwil gateway client. +type GatewayClient interface { + // Auth sends an authentication request to the gateway. + // It will set a cookie in the client if successful. + Auth(ctx context.Context, req *gateway.GatewayAuth) error + + // GetAuthParameter returns the parameters that will be used to compose the + // authentication message that will be signed by the client. + GetAuthParameter(ctx context.Context) (*gateway.GatewayAuthParameter, error) + + // TODO: how do we check for cookie expiration? +} + +var ( + // ErrAuthenticationFailed is returned when the gateway authentication fails. + // This is usually due to an incorrect signature. + ErrAuthenticationFailed = fmt.Errorf("gateway authentication failed") + + // ErrGatewayNotAuthenticated is returned when the client is not authenticated + // with the gateway. + ErrGatewayNotAuthenticated = fmt.Errorf("gateway not authenticated") +) + +const ( + // AuthEndpoint is the endpoint for the gateway authentication. + // This is defined here since the endpoint is part of the signature + // protocol, which both the gateway and client are expected to follow. + AuthEndpoint = "/auth" +) diff --git a/core/rpc/client/gateway/http/client.go b/core/rpc/client/gateway/http/client.go new file mode 100644 index 000000000..c718844a5 --- /dev/null +++ b/core/rpc/client/gateway/http/client.go @@ -0,0 +1,128 @@ +package http + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "net/http" + "net/http/cookiejar" + "net/url" + + "github.com/kwilteam/kwil-db/core/rpc/client/gateway" + types "github.com/kwilteam/kwil-db/core/types/gateway" +) + +type GatewayHttpClient struct { + client *http.Client + target *url.URL +} + +// NewGatewayHttpClient creates a new gateway http client. +// If the client does not have a cookie jar, an error is returned. +func NewGatewayHttpClient(target *url.URL, opts ...ClientOption) (*GatewayHttpClient, error) { + // gateway needs access to the cookie jar + jar, err := cookiejar.New(nil) + if err != nil { + return nil, err + } + c := &clientOptions{ + client: &http.Client{ + Jar: jar, + }, + } + + for _, o := range opts { + o(c) + } + + g := &GatewayHttpClient{ + client: c.client, + target: target, + } + + // if the caller passed a custom http client without a cookie jar, return an error + // otherwise, it will not error in the future- it simply will not work as expected + if g.client.Jar == nil { + return nil, errors.New("gateway http client must have a cookie jar") + } + + return g, nil +} + +var _ gateway.GatewayClient = (*GatewayHttpClient)(nil) + +// fullUrl returns the full url for the given endpoint +func (g *GatewayHttpClient) fullUrl(endpoint string) string { + return g.target.String() + endpoint +} + +// Auth authenticates the client with the gateway. +// It sets the returned cookie in the client's cookie jar. +func (g *GatewayHttpClient) Auth(ctx context.Context, auth *types.GatewayAuth) error { + buf := new(bytes.Buffer) + err := json.NewEncoder(buf).Encode(auth) + if err != nil { + return err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, g.fullUrl(gateway.AuthEndpoint), buf) + if err != nil { + return err + } + + res, err := g.client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + var r gatewayAuthPostResponse + err = json.NewDecoder(res.Body).Decode(&r) + if err != nil { + return err + } + + if r.Error != "" { + return errors.New(r.Error) + } + + return nil +} + +// GetAuthParameter returns the auth parameter for the client. +func (g *GatewayHttpClient) GetAuthParameter(ctx context.Context) (*types.GatewayAuthParameter, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, g.fullUrl(gateway.AuthEndpoint), nil) + if err != nil { + return nil, err + } + + res, err := g.client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + var r gatewayAuthGetResponse + err = json.NewDecoder(res.Body).Decode(&r) + if err != nil { + return nil, err + } + + if r.Error != "" { + return nil, errors.New(r.Error) + } + + return r.Result, nil +} + +// gatewayAuthPostResponse defines the response of POST request for /auth +type gatewayAuthPostResponse struct { + Error string `json:"error"` +} + +// gatewayAuthGetResponse defines the response of GET request for /auth +type gatewayAuthGetResponse struct { + Result *types.GatewayAuthParameter `json:"result"` + Error string `json:"error"` +} diff --git a/core/rpc/client/gateway/http/opts.go b/core/rpc/client/gateway/http/opts.go new file mode 100644 index 000000000..9f5213085 --- /dev/null +++ b/core/rpc/client/gateway/http/opts.go @@ -0,0 +1,17 @@ +package http + +import "net/http" + +type ClientOption func(*clientOptions) + +// WithHTTPClient sets the http client for the client. +// This allows custom http clients to be used. +func WithHTTPClient(client *http.Client) ClientOption { + return func(c *clientOptions) { + c.client = client + } +} + +type clientOptions struct { + client *http.Client +} diff --git a/core/rpc/client/user/grpc/client.go b/core/rpc/client/user/grpc/client.go index e6eda5e70..b1579cdb1 100644 --- a/core/rpc/client/user/grpc/client.go +++ b/core/rpc/client/user/grpc/client.go @@ -1,3 +1,4 @@ +// package grpc implements a gRPC client for the Kwil txsvc client. package grpc import ( @@ -5,6 +6,7 @@ import ( "fmt" "os" + "github.com/kwilteam/kwil-db/core/rpc/client/user" txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" "github.com/kwilteam/kwil-db/core/rpc/transport" @@ -14,12 +16,14 @@ import ( ) type Client struct { - txClient txpb.TxServiceClient + TxClient txpb.TxServiceClient conn *grpc.ClientConn - dailOpts []grpc.DialOption + dialOpts []grpc.DialOption } +var _ user.TxSvcClient = (*Client)(nil) + type Option func(*Client) error func WithTlsCert(certFile string) Option { @@ -28,21 +32,21 @@ func WithTlsCert(certFile string) Option { if err != nil { return err } - c.dailOpts = append(c.dailOpts, tlsDailOption) + c.dialOpts = append(c.dialOpts, tlsDailOption) return nil } } func WithDialOptions(opts ...grpc.DialOption) Option { return func(c *Client) error { - c.dailOpts = append(c.dailOpts, opts...) + c.dialOpts = append(c.dialOpts, opts...) return nil } } func New(ctx context.Context, target string, opts ...Option) (*Client, error) { clt := &Client{ - dailOpts: []grpc.DialOption{ + dialOpts: []grpc.DialOption{ grpc.WithDefaultCallOptions( grpc.MaxCallRecvMsgSize(64 * 1024 * 1024), // 64MiB limit on *responses*; sends are unlimited ), @@ -55,16 +59,24 @@ func New(ctx context.Context, target string, opts ...Option) (*Client, error) { } } - conn, err := grpc.DialContext(ctx, target, clt.dailOpts...) + conn, err := grpc.DialContext(ctx, target, clt.dialOpts...) if err != nil { return nil, err } - clt.txClient = txpb.NewTxServiceClient(conn) + clt.TxClient = txpb.NewTxServiceClient(conn) clt.conn = conn return clt, nil } +// WrapConn wraps an existing grpc.ClientConn with the TxServiceClient. +func WrapConn(conn *grpc.ClientConn) *Client { + return &Client{ + TxClient: txpb.NewTxServiceClient(conn), + conn: conn, + } +} + func (c *Client) Close() error { return c.conn.Close() } diff --git a/core/rpc/client/user/grpc/rpc.go b/core/rpc/client/user/grpc/rpc.go index 29a807c33..e2204938a 100644 --- a/core/rpc/client/user/grpc/rpc.go +++ b/core/rpc/client/user/grpc/rpc.go @@ -7,7 +7,6 @@ import ( "fmt" "math/big" - "github.com/kwilteam/kwil-db/core/crypto/auth" rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" "github.com/kwilteam/kwil-db/core/rpc/conversion" txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" @@ -18,7 +17,7 @@ import ( func (c *Client) GetAccount(ctx context.Context, identifier []byte, status types.AccountStatus) (*types.Account, error) { pbStatus := txpb.AccountStatus(status) - res, err := c.txClient.GetAccount(ctx, &txpb.GetAccountRequest{ + res, err := c.TxClient.GetAccount(ctx, &txpb.GetAccountRequest{ Identifier: identifier, Status: &pbStatus, }) @@ -41,7 +40,7 @@ func (c *Client) GetAccount(ctx context.Context, identifier []byte, status types } func (c *Client) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) { - res, err := c.txClient.TxQuery(ctx, &txpb.TxQueryRequest{ + res, err := c.TxClient.TxQuery(ctx, &txpb.TxQueryRequest{ TxHash: txHash, }) if err != nil { @@ -53,7 +52,7 @@ func (c *Client) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTx // ChainInfo gets information on the blockchain of the remote host. func (c *Client) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { - res, err := c.txClient.ChainInfo(ctx, &txpb.ChainInfoRequest{}) + res, err := c.TxClient.ChainInfo(ctx, &txpb.ChainInfoRequest{}) if err != nil { return nil, err } @@ -66,7 +65,7 @@ func (c *Client) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { func (c *Client) Broadcast(ctx context.Context, tx *transactions.Transaction) ([]byte, error) { pbTx := convertTx(tx) - res, err := c.txClient.Broadcast(ctx, &txpb.BroadcastRequest{Tx: pbTx}) + res, err := c.TxClient.Broadcast(ctx, &txpb.BroadcastRequest{Tx: pbTx}) if err != nil { statusError, ok := status.FromError(err) if !ok { @@ -97,7 +96,7 @@ func (c *Client) Broadcast(ctx context.Context, tx *transactions.Transaction) ([ } func (c *Client) Ping(ctx context.Context) (string, error) { - res, err := c.txClient.Ping(ctx, &txpb.PingRequest{}) + res, err := c.TxClient.Ping(ctx, &txpb.PingRequest{}) if err != nil { return "", fmt.Errorf("failed to ping: %w", err) } @@ -109,7 +108,7 @@ func (c *Client) EstimateCost(ctx context.Context, tx *transactions.Transaction) // convert transaction to proto pbTx := convertTx(tx) - res, err := c.txClient.EstimatePrice(ctx, &txpb.EstimatePriceRequest{ + res, err := c.TxClient.EstimatePrice(ctx, &txpb.EstimatePriceRequest{ Tx: pbTx, }) if err != nil { @@ -139,7 +138,7 @@ func (c *Client) Call(ctx context.Context, req *transactions.CallMessage, Sender: sender, } - res, err := c.txClient.Call(ctx, callReq) + res, err := c.TxClient.Call(ctx, callReq) if err != nil { return nil, fmt.Errorf("failed to call: %w", err) @@ -155,7 +154,7 @@ func (c *Client) Call(ctx context.Context, req *transactions.CallMessage, } func (c *Client) GetConfig(ctx context.Context) (*SvcConfig, error) { - res, err := c.txClient.GetConfig(ctx, &txpb.GetConfigRequest{}) + res, err := c.TxClient.GetConfig(ctx, &txpb.GetConfigRequest{}) if err != nil { return nil, fmt.Errorf("failed to get config: %w", err) } @@ -173,9 +172,9 @@ type SvcConfig struct { ProviderAddress string } -func (c *Client) ListDatabases(ctx context.Context, userIdentifier []byte) ([]string, error) { - res, err := c.txClient.ListDatabases(ctx, &txpb.ListDatabasesRequest{ - Owner: userIdentifier, +func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]string, error) { + res, err := c.TxClient.ListDatabases(ctx, &txpb.ListDatabasesRequest{ + Owner: ownerIdentifier, }) if err != nil { @@ -186,7 +185,7 @@ func (c *Client) ListDatabases(ctx context.Context, userIdentifier []byte) ([]st } func (c *Client) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) { - res, err := c.txClient.Query(ctx, &txpb.QueryRequest{ + res, err := c.TxClient.Query(ctx, &txpb.QueryRequest{ Dbid: dbid, Query: query, }) @@ -204,7 +203,7 @@ func (c *Client) Query(ctx context.Context, dbid string, query string) ([]map[st } func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) { - res, err := c.txClient.GetSchema(ctx, &txpb.GetSchemaRequest{ + res, err := c.TxClient.GetSchema(ctx, &txpb.GetSchemaRequest{ Dbid: dbid, }) if err != nil { @@ -213,57 +212,3 @@ func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Sche return conversion.ConvertFromPBSchema(res.Schema), nil } - -func (c *Client) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { - resp, err := c.txClient.ValidatorJoinStatus(ctx, &txpb.ValidatorJoinStatusRequest{Pubkey: pubKey}) - if err != nil { - return nil, fmt.Errorf("failed check validator status: %w", err) - } - - jq := conversion.ConvertFromPBJoinRequest(resp) - jq.Candidate = pubKey - return jq, nil -} - -func (c *Client) CurrentValidators(ctx context.Context) ([]*types.Validator, error) { - req := &txpb.CurrentValidatorsRequest{} - resp, err := c.txClient.CurrentValidators(ctx, req) - if err != nil { - return nil, fmt.Errorf("failed to retrieve current validators: %w", err) - } - vals := make([]*types.Validator, len(resp.Validators)) - for i, vi := range resp.Validators { - vals[i] = &types.Validator{ - PubKey: vi.Pubkey, - Power: vi.Power, - } - } - return vals, nil -} - -// VerifySignature verifies the signature. -// An ErrInvalidSignature is returned if the signature is invalid. -func (c *Client) VerifySignature(ctx context.Context, sender []byte, - signature *auth.Signature, message []byte) error { - req := &txpb.VerifySignatureRequest{ - Signature: &txpb.Signature{ - SignatureBytes: signature.Signature, - SignatureType: signature.Type, - }, - Sender: sender, - Msg: message, - } - - // communication error - resp, err := c.txClient.VerifySignature(ctx, req) - if err != nil { - return fmt.Errorf("verify signature: %w", err) - } - - // caller can tell if signature is valid - if !resp.Valid { - return fmt.Errorf("%w: %s", rpcClient.ErrInvalidSignature, resp.Error) - } - - return nil -} diff --git a/core/rpc/client/user/http/client.go b/core/rpc/client/user/http/client.go index 294cf0670..60c94890c 100644 --- a/core/rpc/client/user/http/client.go +++ b/core/rpc/client/user/http/client.go @@ -1,195 +1,273 @@ +// package http implements an http transport for the Kwil txsvc client. package http import ( + "encoding/base64" + "encoding/json" + "errors" "fmt" "net/http" - "net/http/cookiejar" - "net/http/httptrace" "net/url" - "slices" - "time" + "strconv" - "golang.org/x/net/publicsuffix" -) + "context" + "math/big" -const ( - contentType = "application/json" + "github.com/antihax/optional" + "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/core/rpc/client/user" + httpTx "github.com/kwilteam/kwil-db/core/rpc/http/tx" + "github.com/kwilteam/kwil-db/core/types" + "github.com/kwilteam/kwil-db/core/types/transactions" ) -// Client represent a connection to a kwil node type Client struct { - target string // host:port or domain - debugMode bool - // https://cs.opensource.google/go/go/+/refs/tags/go1.21.3:src/net/http/client.go;l=562 - // https://cs.opensource.google/go/go/+/refs/tags/go1.21.3:src/net/http/response.go;l=59 - // for the connection to be reused, just close the resp.body is not enough, - // the body also has to be read fully. - conn *http.Client - headers http.Header + conn *httpTx.APIClient + url *url.URL } -// Dial creates an HTTP connection to the given target. -// Supported URL schemes are http and https. -// For more configuration options, use DialOptions. -func Dial(target string) (*Client, error) { - return DialOptions(target) +// NewClient creates a new http client for the Kwil user service +func NewClient(target *url.URL, opts ...ClientOption) *Client { + c := &Client{ + url: target, + } + + clientOpts := &clientOptions{ + client: &http.Client{}, + } + + for _, o := range opts { + o(clientOpts) + } + + cfg := httpTx.NewConfiguration() + cfg.HTTPClient = clientOpts.client + cfg.BasePath = target.String() + cfg.Host = target.Host + cfg.Scheme = target.Scheme + + c.conn = httpTx.NewAPIClient(cfg) + + return c } -// DialOptions creates an HTTP connection to the given options. -func DialOptions(target string, opts ...ClientOption) (*Client, error) { - u, err := url.Parse(target) +var _ user.TxSvcClient = (*Client)(nil) + +func (c *Client) Broadcast(ctx context.Context, tx *transactions.Transaction) ([]byte, error) { + result, res, err := c.conn.TxServiceApi.TxServiceBroadcast(ctx, httpTx.TxBroadcastRequest{ + Tx: convertTx(tx), + }) if err != nil { - return nil, fmt.Errorf("failed to parse target: %w", err) + return nil, err } + defer res.Body.Close() - switch u.Scheme { - case "http", "https": - default: - return nil, fmt.Errorf("URL scheme not support: %s", u.Scheme) + decodedTxHash, err := base64.StdEncoding.DecodeString(result.TxHash) + if err != nil { + return nil, err } - cfg := new(clientConfig) - for _, opt := range opts { - opt.apply(cfg) + return decodedTxHash, nil +} + +func (c *Client) Call(ctx context.Context, msg *transactions.CallMessage, opts ...client.ActionCallOption) ([]map[string]any, error) { + result, res, err := c.conn.TxServiceApi.TxServiceCall(ctx, httpTx.TxCallRequest{ + AuthType: msg.AuthType, + Sender: base64.StdEncoding.EncodeToString(msg.Sender), + Body: &httpTx.TxCallRequestBody{ + Payload: base64.StdEncoding.EncodeToString(msg.Body.Payload), + }, + }) + if err != nil { + // we need to account for a 401 Unauthorized error in this function, + // but the codegen will return 400 responses as an err, causing this + // to return. We need to check for this error here and wrap it in + // our own error type. + if res != nil && res.StatusCode == http.StatusUnauthorized { + err = errors.Join(err, client.ErrUnauthorized) + } + + return nil, err } + defer res.Body.Close() - headers := make(http.Header, 2+len(cfg.httpHeaders)) - headers.Set("Accept", contentType) - headers.Set("Content-Type", contentType) - for key, values := range cfg.httpHeaders { - headers[key] = values + // result is []map[string]any encoded in base64 + decodedResult, err := base64.StdEncoding.DecodeString(result.Result) + if err != nil { + return nil, err } - clt := cfg.httpClient - if clt == nil { - clt = DefaultHTTPClient() + // unmashal result + var resultSet []map[string]any + err = json.Unmarshal(decodedResult, &resultSet) + if err != nil { + return nil, err } - // enable cookie jar - if clt.Jar == nil { - clt.Jar = newCookieJar() + return resultSet, nil +} + +func (c *Client) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { + result, res, err := c.conn.TxServiceApi.TxServiceChainInfo(ctx) + if err != nil { + return nil, err } + defer res.Body.Close() - clt.Jar.SetCookies(u, cfg.cookies) + parsedHeight, err := strconv.ParseUint(result.Height, 10, 64) + if err != nil { + return nil, err + } - client := &Client{ - target: target, - debugMode: cfg.debugMode, - conn: clt, - headers: headers, + return &types.ChainInfo{ + ChainID: result.ChainId, + BlockHeight: parsedHeight, + BlockHash: result.Hash, + }, nil +} + +func (c *Client) EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) { + result, res, err := c.conn.TxServiceApi.TxServiceEstimatePrice(ctx, httpTx.TxEstimatePriceRequest{ + Tx: convertTx(tx), + }) + if err != nil { + return nil, err } + defer res.Body.Close() - return client, nil + // parse result.Price to big.Int + price, ok := new(big.Int).SetString(result.Price, 10) + if !ok { + return nil, fmt.Errorf("failed to parse price to big.Int. received: %s", result.Price) + } + + return price, nil } -// makeRequest makes a request to the target and returns the response body -// the caller should read all data in the body and close the response body -func (c *Client) makeRequest(req *http.Request) (*http.Response, error) { - carriedCookies := req.Cookies() - // default headers - req.Header = c.headers.Clone() - s := time.Now() - - var dnsStart, connStart, reqStart time.Time - var dnsDuration, connDuration, reqDuration time.Duration - var connReused bool - if c.debugMode { - trace := &httptrace.ClientTrace{ - DNSStart: func(_ httptrace.DNSStartInfo) { - dnsStart = time.Now() - }, - DNSDone: func(_ httptrace.DNSDoneInfo) { - dnsDuration = time.Since(dnsStart) - }, - GetConn: func(_ string) { - connStart = time.Now() - }, - GotConn: func(info httptrace.GotConnInfo) { - if !info.Reused { - connDuration = time.Since(connStart) - } else { - connReused = true - } - reqStart = time.Now() - }, - WroteRequest: func(_ httptrace.WroteRequestInfo) { - reqDuration = time.Since(reqStart) - }, - } - req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) - } - - // handle jar cookies and request cookies - if carriedCookies != nil { - jarCookies := c.conn.Jar.Cookies(req.URL) - if jarCookies == nil { - // use request cookies if jar has no cookies - for _, cookie := range carriedCookies { - req.AddCookie(cookie) - } - } else { - // NOTE: SetCookies won't overwrite existing cookies of cookieJar, - // so we have to create a new cookie jar - oldJar := c.conn.Jar - defer func() { - c.conn.Jar = oldJar - }() - - // overwrite jar cookies with request cookies - newJarCookies := append(carriedCookies, jarCookies...) // order matters - // remove duplicated cookies; CompactFunc will modify the slice and - // keep the first one of duplicated cookies, e.g., from carryCookies - newJarCookies = slices.CompactFunc(newJarCookies, - func(c1 *http.Cookie, c2 *http.Cookie) bool { - return c1.Name == c2.Name - }) - - c.conn.Jar = newCookieJar() - c.conn.Jar.SetCookies(req.URL, newJarCookies) - } +func (c *Client) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) { + // we need to use b64url since this method uses a query string + result, res, err := c.conn.TxServiceApi.TxServiceGetAccount(ctx, base64.URLEncoding.EncodeToString(pubKey), &httpTx.TxServiceApiTxServiceGetAccountOpts{ + Status: optional.NewString(strconv.FormatUint(uint64(status), 10)), // does not seem to properly handle optional enum properly. This could cause a bug, will need to investigate + }) + if err != nil { + return nil, err } + defer res.Body.Close() - resp, err := c.conn.Do(req) - // NOTE: we can copy&close resp.Body to a buffer here so that later we - // don't need to close the resp.Body to ensure the connection can be reused. - // seems not a good idea + // parse result.Balance to big.Int + balance, ok := new(big.Int).SetString(result.Account.Balance, 10) + if !ok { + return nil, fmt.Errorf("failed to parse balance to big.Int. received: %s", result.Account.Balance) + } - if c.debugMode { - duration := time.Since(s) - // NOTE: kind of exotic using fmt here, but it's just for debugging - fmt.Printf("request %s completed in %s (dns=%s, conn=%s, req=%s), reused=%t\n", - req.URL.Path, duration, dnsDuration, connDuration, reqDuration, connReused) + parsedNonce, err := strconv.ParseInt(result.Account.Nonce, 10, 64) + if err != nil { + return nil, err } - return resp, err + return &types.Account{ + Identifier: pubKey, + Balance: balance, + Nonce: parsedNonce, + }, nil } -func (c *Client) GetTarget() string { - return c.target +func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) { + result, res, err := c.conn.TxServiceApi.TxServiceGetSchema(ctx, dbid) + if err != nil { + return nil, err + } + defer res.Body.Close() + + convertedSchema, err := convertHttpSchema(result.Schema) + if err != nil { + return nil, err + } + + return convertedSchema, nil } -func (c *Client) Close() error { - c.conn = nil - return nil +func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]string, error) { + result, res, err := c.conn.TxServiceApi.TxServiceListDatabases(ctx, base64.StdEncoding.EncodeToString(ownerPubKey)) + if err != nil { + return nil, err + } + defer res.Body.Close() + + return result.Databases, nil } -func DefaultHTTPClient() *http.Client { - // same transport same connection - tr := &http.Transport{ - //MaxConnsPerHost: 5, // default is 0, no limit - //MaxIdleConnsPerHost: 2, // default is 2 - //DisableCompression: , - //DisableKeepAlives: , - IdleConnTimeout: time.Second * 5, // default is 90s +func (c *Client) Ping(ctx context.Context) (string, error) { + result, res, err := c.conn.TxServiceApi.TxServicePing(ctx, &httpTx.TxServiceApiTxServicePingOpts{ + Message: optional.NewString("ping"), // we don't really need this I believe? + }) + if err != nil { + return "", err } - return &http.Client{ - Transport: tr, - Timeout: time.Second * 3, + defer res.Body.Close() + + return result.Message, nil +} + +func (c *Client) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) { + result, res, err := c.conn.TxServiceApi.TxServiceQuery(ctx, httpTx.TxQueryRequest{ + Dbid: dbid, + Query: query, + }) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // result is []map[string]any encoded in base64 + decodedResult, err := base64.StdEncoding.DecodeString(result.Result) + if err != nil { + return nil, err + } + + // unmashal result + var resultSet []map[string]any + err = json.Unmarshal(decodedResult, &resultSet) + if err != nil { + return nil, err } + + return resultSet, nil } -func newCookieJar() http.CookieJar { - // NOTE: not entirely sure about the PublicSuffixList - jar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) - return jar +func (c *Client) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) { + result, res, err := c.conn.TxServiceApi.TxServiceTxQuery(ctx, httpTx.TxTxQueryRequest{ + TxHash: base64.StdEncoding.EncodeToString(txHash), + }) + if err != nil { + return nil, err + } + defer res.Body.Close() + + decodedHeight, err := strconv.ParseInt(result.Height, 10, 64) + if err != nil { + return nil, err + } + + decodedHash, err := base64.StdEncoding.DecodeString(result.Hash) + if err != nil { + return nil, err + } + + convertedTx, err := convertHttpTx(result.Tx) + if err != nil { + return nil, err + } + + convertedTxResult, err := convertHttpTxResult(result.TxResult) + if err != nil { + return nil, err + } + + return &transactions.TcTxQueryResponse{ + Hash: decodedHash, + Height: decodedHeight, + Tx: *convertedTx, + TxResult: *convertedTxResult, + }, nil } diff --git a/core/rpc/client/user/http/client_opt.go b/core/rpc/client/user/http/client_opt.go deleted file mode 100644 index f38048d99..000000000 --- a/core/rpc/client/user/http/client_opt.go +++ /dev/null @@ -1,54 +0,0 @@ -package http - -import ( - "net/http" -) - -type ClientOption interface { - apply(*clientConfig) -} - -type fnClientOption func(*clientConfig) - -func (fn fnClientOption) apply(opt *clientConfig) { - fn(opt) -} - -func EnableDebugMode() ClientOption { - return fnClientOption(func(cfg *clientConfig) { - cfg.debugMode = true - }) -} - -func WithHttpClient(httpClient *http.Client) ClientOption { - return fnClientOption(func(cfg *clientConfig) { - cfg.httpClient = httpClient - }) -} - -func WithHeader(key, value string) ClientOption { - return fnClientOption(func(cfg *clientConfig) { - if cfg.httpHeaders == nil { - cfg.httpHeaders = make(http.Header) - } - cfg.httpHeaders.Set(key, value) - }) -} - -func WithCookie(cookie *http.Cookie) ClientOption { - return fnClientOption(func(cfg *clientConfig) { - if cfg.cookies == nil { - cfg.cookies = make([]*http.Cookie, 0) - } - cfg.cookies = append(cfg.cookies, cookie) - - }) -} - -// clientConfig is the configuration for a Client. -type clientConfig struct { - httpClient *http.Client - debugMode bool - httpHeaders http.Header - cookies []*http.Cookie -} diff --git a/core/rpc/client/user/http/convert.go b/core/rpc/client/user/http/convert.go new file mode 100644 index 000000000..d5ade28f4 --- /dev/null +++ b/core/rpc/client/user/http/convert.go @@ -0,0 +1,255 @@ +package http + +import ( + "encoding/base64" + "fmt" + "math/big" + "strconv" + + "github.com/kwilteam/kwil-db/core/crypto/auth" + httpTx "github.com/kwilteam/kwil-db/core/rpc/http/tx" + "github.com/kwilteam/kwil-db/core/types/transactions" +) + +// convertTx converts a transaction to a httpTx.TxTransaction +func convertTx(tx *transactions.Transaction) *httpTx.TxTransaction { + if tx.Sender == nil { + tx.Sender = []byte{} + } + if tx.Signature == nil { + tx.Signature = &auth.Signature{ + Signature: []byte{}, + Type: "", + } + } + + return &httpTx.TxTransaction{ + Sender: base64.StdEncoding.EncodeToString(tx.Sender), + Serialization: tx.Serialization.String(), + Signature: &httpTx.TxSignature{ + SignatureBytes: base64.StdEncoding.EncodeToString(tx.Signature.Signature), + SignatureType: tx.Signature.Type, + }, + Body: &httpTx.TxTransactionBody{ + Payload: base64.StdEncoding.EncodeToString(tx.Body.Payload), + PayloadType: tx.Body.PayloadType.String(), + Fee: tx.Body.Fee.String(), + Nonce: strconv.FormatUint(tx.Body.Nonce, 10), + ChainId: tx.Body.ChainID, + Description: tx.Body.Description, + }, + } +} + +// convertHttpTx converts a httpTx.TxTransaction to a transactions.Transaction +func convertHttpTx(tx *httpTx.TxTransaction) (*transactions.Transaction, error) { + decodedSender, err := base64.StdEncoding.DecodeString(tx.Sender) + if err != nil { + return nil, err + } + + decodedSignature, err := base64.StdEncoding.DecodeString(tx.Signature.SignatureBytes) + if err != nil { + return nil, err + } + + decodedPayload, err := base64.StdEncoding.DecodeString(tx.Body.Payload) + if err != nil { + return nil, err + } + + fee, ok := new(big.Int).SetString(tx.Body.Fee, 10) + if !ok { + return nil, fmt.Errorf("failed to parse fee to big.Int. received: %s", tx.Body.Fee) + } + + decodedNonce, err := strconv.ParseUint(tx.Body.Nonce, 10, 64) + if err != nil { + return nil, err + } + + return &transactions.Transaction{ + Sender: decodedSender, + Serialization: transactions.SignedMsgSerializationType(tx.Serialization), + Signature: &auth.Signature{ + Signature: decodedSignature, + Type: tx.Signature.SignatureType, + }, + Body: &transactions.TransactionBody{ + Payload: decodedPayload, + PayloadType: transactions.PayloadType(tx.Body.PayloadType), + Fee: fee, + Nonce: decodedNonce, + ChainID: tx.Body.ChainId, + Description: tx.Body.Description, + }, + }, nil +} + +// convertHttpTxResult converts a httpTx.TxTransactionResult to a transactions.TransactionResult +func convertHttpTxResult(result *httpTx.TxTransactionResult) (*transactions.TransactionResult, error) { + decodedGasUsed, err := strconv.ParseInt(result.GasUsed, 10, 64) + if err != nil { + return nil, err + } + + decodedGasWanted, err := strconv.ParseInt(result.GasWanted, 10, 64) + if err != nil { + return nil, err + } + + decodedData, err := base64.StdEncoding.DecodeString(result.Data) + if err != nil { + return nil, err + } + + decodedEvents := make([][]byte, 0, len(result.Events)) + for _, event := range result.Events { + decodedEvent, err := base64.StdEncoding.DecodeString(event) + if err != nil { + return nil, err + } + decodedEvents = append(decodedEvents, decodedEvent) + } + + return &transactions.TransactionResult{ + Code: uint32(result.Code), + Log: result.Log, + GasUsed: decodedGasUsed, + GasWanted: decodedGasWanted, + Data: decodedData, + Events: decodedEvents, + }, nil +} + +// convertHttpSchema converts a httpTx.TxSchema to a transactions.Schema +func convertHttpSchema(schema *httpTx.TxSchema) (*transactions.Schema, error) { + decodedOwner, err := base64.StdEncoding.DecodeString(schema.Owner) + if err != nil { + return nil, err + } + + return &transactions.Schema{ + Owner: decodedOwner, + Name: schema.Name, + Tables: convertHttpTables(schema.Tables), + Actions: convertHttpActions(schema.Actions), + Extensions: convertHttpExtensions(schema.Extensions), + }, nil +} + +// convertHttpTables converts []httpTx.TxTable to a []transactions.Table +func convertHttpTables(tables []httpTx.TxTable) []*transactions.Table { + tbls := make([]*transactions.Table, len(tables)) + + for i, table := range tables { + tbls[i] = &transactions.Table{ + Name: table.Name, + Columns: convertHttpColumns(table.Columns), + Indexes: convertHttpIndexes(table.Indexes), + ForeignKeys: convertHttpForeignKeys(table.ForeignKeys), + } + } + + return tbls +} + +// convertHttpColumns converts []httpTx.TxColumn to []transactions.Column +func convertHttpColumns(columns []httpTx.TxColumn) []*transactions.Column { + cols := make([]*transactions.Column, len(columns)) + + for i, column := range columns { + cols[i] = &transactions.Column{ + Name: column.Name, + Type: column.Type_, + Attributes: convertHttpAttributes(column.Attributes), + } + } + + return cols +} + +// convertHttpAttributes converts []httpTx.TxAttribute to []transactions.Attribute +func convertHttpAttributes(attributes []httpTx.TxAttribute) []*transactions.Attribute { + attrs := make([]*transactions.Attribute, len(attributes)) + for i, attribute := range attributes { + attrs[i] = &transactions.Attribute{ + Type: attribute.Type_, + Value: attribute.Value, + } + } + return attrs +} + +// convertHttpIndexes converts []httpTx.TxIndex to []transactions.Index +func convertHttpIndexes(indexes []httpTx.TxIndex) []*transactions.Index { + idxs := make([]*transactions.Index, len(indexes)) + for i, index := range indexes { + idxs[i] = &transactions.Index{ + Name: index.Name, + Columns: index.Columns, + Type: index.Type_, + } + } + return idxs +} + +// convertHttpForeignKeys converts []httpTx.TxForeignKey to []transactions.ForeignKey +func convertHttpForeignKeys(foreignKeys []httpTx.TxForeignKey) []*transactions.ForeignKey { + fks := make([]*transactions.ForeignKey, len(foreignKeys)) + for i, fk := range foreignKeys { + actions := make([]*transactions.ForeignKeyAction, len(fk.Actions)) + for j, action := range fk.Actions { + actions[j] = &transactions.ForeignKeyAction{ + On: action.On, + Do: action.Do, + } + } + + fks[i] = &transactions.ForeignKey{ + ChildKeys: fk.ChildKeys, + ParentKeys: fk.ParentKeys, + ParentTable: fk.ParentTable, + Actions: actions, + } + } + return fks +} + +// convertHttpActions converts []httpTx.TxAction to []transactions.Action +func convertHttpActions(actions []httpTx.TxAction) []*transactions.Action { + acts := make([]*transactions.Action, len(actions)) + for i, action := range actions { + acts[i] = &transactions.Action{ + Name: action.Name, + Annotations: action.Annotations, + Inputs: action.Inputs, + Mutability: action.Mutability, + Auxiliaries: action.Auxiliaries, + Public: action.Public, + Statements: action.Statements, + } + } + return acts +} + +// convertHttpExtensions converts []httpTx.TxExtension to []transactions.Extension +func convertHttpExtensions(extensions []httpTx.TxExtensions) []*transactions.Extension { + exts := make([]*transactions.Extension, len(extensions)) + for i, extension := range extensions { + initialize := make([]*transactions.ExtensionConfig, len(extension.Initialization)) + for j, init := range extension.Initialization { + initialize[j] = &transactions.ExtensionConfig{ + Argument: init.Argument, + Value: init.Value, + } + } + + exts[i] = &transactions.Extension{ + Name: extension.Name, + Config: initialize, + Alias: extension.Alias, + } + } + return exts +} diff --git a/core/rpc/client/user/http/cookie_test.go b/core/rpc/client/user/http/cookie_test.go deleted file mode 100644 index c30fcb593..000000000 --- a/core/rpc/client/user/http/cookie_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package http - -import ( - "fmt" - "net/http" - "net/http/cookiejar" - "net/url" - "testing" -) - -func Test_cookie(t *testing.T) { - jar, _ := cookiejar.New(nil) - var cookies []*http.Cookie - cookie := &http.Cookie{ - Name: "test", - Value: "tv", - Path: "/", - Domain: "example.com", - } - cookies = append(cookies, cookie) - u, _ := url.Parse("http://example.com/search/") - jar.SetCookies(u, cookies) - fmt.Println(jar.Cookies(u)) -} - -func Test_cookie2(t *testing.T) { - - jar, _ := cookiejar.New(nil) - var cookies []*http.Cookie - cookie := &http.Cookie{ - Name: "test", - Value: "tv", - Path: "/", - Domain: "localhost:8080", - } - cookies = append(cookies, cookie) - u, _ := url.Parse("localhost:8080/search/") - jar.SetCookies(u, cookies) - fmt.Println(jar.Cookies(u)) -} - -func Test_cookie3(t *testing.T) { - - jar, _ := cookiejar.New(nil) - var cookies []*http.Cookie - cookie := &http.Cookie{ - Name: "test", - Value: "tv", - Path: "/", - Domain: "localhost:8080", - } - cookies = append(cookies, cookie) - u, _ := url.Parse("http://localhost:8080/search/") - jar.SetCookies(u, cookies) - fmt.Println(jar.Cookies(u)) -} - -func Test_cookie4(t *testing.T) { - // we can test locally like this, set local dns point example.com to localhost - jar, _ := cookiejar.New(nil) - var cookies []*http.Cookie - cookie := &http.Cookie{ - Name: "test", - Value: "tv", - Path: "/", - Domain: "example.com", - } - cookies = append(cookies, cookie) - u, _ := url.Parse("http://example.com:8080/search/") - jar.SetCookies(u, cookies) - fmt.Println(jar.Cookies(u)) -} diff --git a/core/rpc/client/user/http/opts.go b/core/rpc/client/user/http/opts.go new file mode 100644 index 000000000..50edd1b53 --- /dev/null +++ b/core/rpc/client/user/http/opts.go @@ -0,0 +1,19 @@ +package http + +import ( + "net/http" +) + +type ClientOption func(*clientOptions) + +// WithHTTPClient sets the http client for the client. +// This allows custom http clients to be used. +func WithHTTPClient(client *http.Client) ClientOption { + return func(c *clientOptions) { + c.client = client + } +} + +type clientOptions struct { + client *http.Client +} diff --git a/core/rpc/client/user/http/req.go b/core/rpc/client/user/http/req.go deleted file mode 100644 index 38609763c..000000000 --- a/core/rpc/client/user/http/req.go +++ /dev/null @@ -1,437 +0,0 @@ -package http - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - - "github.com/kwilteam/kwil-db/core/crypto/auth" - "github.com/kwilteam/kwil-db/core/rpc/client" - "github.com/kwilteam/kwil-db/core/rpc/conversion" - txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" - "github.com/kwilteam/kwil-db/core/types" - "github.com/kwilteam/kwil-db/core/types/transactions" - "google.golang.org/genproto/googleapis/rpc/status" -) - -// NOTE: a lot of boilerplate code, and part of the logic is kind of duplicated -// from the grpc client -// TODO: refactor - -func NewGetRequest(server string, path string) (*http.Request, error) { - target, err := url.JoinPath(server, path) - if err != nil { - return nil, err - } - - return http.NewRequest(http.MethodGet, target, nil) -} - -func NewJsonPostRequest(server string, path string, body io.Reader) (*http.Request, error) { - target, err := url.JoinPath(server, path) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodPost, target, body) - if err != nil { - return nil, err - } - - return req, nil -} - -func newPingRequest(server string) (*http.Request, error) { - return NewGetRequest(server, "/api/v1/ping") -} - -func parsePingResponse(resp *http.Response) (string, error) { - if resp.StatusCode != http.StatusOK { - return "", parseErrorResponse(resp) - } - - var res txpb.PingResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return "", fmt.Errorf("parsePingResponse: %w", err) - } - - return res.Message, nil -} - -func newEstimateCostRequest(server string, tx *transactions.Transaction) (*http.Request, error) { - pbTx := conversion.ConvertToPBTx(tx) - var bodyReader io.Reader - buf, err := json.Marshal(txpb.EstimatePriceRequest{Tx: pbTx}) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/estimate_price", bodyReader) -} - -func parseErrorResponse(resp *http.Response) error { - // NOTE: here directly use status.Status from googleapis/rpc/status - var res status.Status - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return err - } - - msg := res.GetMessage() - if msg == "" { - msg = resp.Status - } - - return errors.New(msg) -} - -func parseEstimateCostResponse(resp *http.Response) (*big.Int, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.EstimatePriceResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseEstimateCostResponse: %w", err) - } - - bigCost, ok := new(big.Int).SetString(res.Price, 10) - if !ok { - return nil, fmt.Errorf("parsePrice failed") - } - - return bigCost, nil -} - -func newBroadcastRequest(server string, tx *transactions.Transaction) (*http.Request, error) { - pbTx := conversion.ConvertToPBTx(tx) - var bodyReader io.Reader - buf, err := json.Marshal(txpb.BroadcastRequest{Tx: pbTx}) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/broadcast", bodyReader) -} - -func parseBroadcastResponse(resp *http.Response) ([]byte, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.BroadcastResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseBroadcastResponse: %w", err) - } - - return res.TxHash, nil -} - -func newGetAccountRequest(server string, publicKey []byte, _ types.AccountStatus) (*http.Request, error) { - // TODO: change proto HTTP option to add a query parameter `status` - pk := url.PathEscape(base64.URLEncoding.EncodeToString(publicKey)) - return NewGetRequest(server, fmt.Sprintf("/api/v1/accounts/%s", pk)) -} - -func parseGetAccountResponse(resp *http.Response) (*types.Account, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res getAccountResponse // weird, server respond with a `string` field nonce - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseGetAccountResponse: %w", err) - } - - bigBalance, ok := new(big.Int).SetString(res.Account.Balance, 10) - if !ok { - return nil, fmt.Errorf("parseBalance failed") - - } - - acc := types.Account{ - Identifier: res.Account.Identifier, - Balance: bigBalance, - Nonce: res.Account.Nonce, - } - - return &acc, nil -} - -func newTxQueryRequest(server string, txHash []byte) (*http.Request, error) { - txQueryReq := txpb.TxQueryRequest{ - TxHash: txHash, - } - - var bodyReader io.Reader - buf, err := json.Marshal(&txQueryReq) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/tx_query", bodyReader) - - // NOTE: should make tx_query a GET request? - //h := url.PathEscape(base64.URLEncoding.EncodeToString(txHash)) - //return NewGetRequest(server, fmt.Sprintf("/api/v1/tx_query/%s", h)) -} - -// parseTxQueryResponse parses the response from tx_query endpoint -// All returned fields from resp are preserved -func parseTxQueryResponse(resp *http.Response) (*transactions.TcTxQueryResponse, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txQueryResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseTxQueryResponse: %w", err) - } - - return conversion.ConvertFromPBTxQueryResp((*txpb.TxQueryResponse)(&res)) -} - -func newListDatabasesRequest(server string, publicKey []byte) (*http.Request, error) { - pk := url.PathEscape(base64.URLEncoding.EncodeToString(publicKey)) - return NewGetRequest(server, fmt.Sprintf("/api/v1/%s/databases", pk)) -} - -func parseListDatabasesResponse(resp *http.Response) ([]string, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.ListDatabasesResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseListDatabasesResponse: %w", err) - } - - return res.Databases, nil -} - -func newActionCallRequest(server string, msg *transactions.CallMessage) (*http.Request, error) { - var sender []byte - if msg.Sender != nil { - sender = msg.Sender - } - - callReq := &txpb.CallRequest{ - Body: &txpb.CallRequest_Body{ - Payload: msg.Body.Payload, - }, - AuthType: msg.AuthType, - Sender: sender, - } - - var bodyReader io.Reader - buf, err := json.Marshal(callReq) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/call", bodyReader) -} - -func parseActionCallResponse(resp *http.Response) ([]map[string]any, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.CallResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseActionCallResponse: %w", err) - } - - var result []map[string]any - err = json.Unmarshal(res.Result, &result) - if err != nil { - return nil, fmt.Errorf("parseActionCallResponse: %w", err) - } - - return result, nil -} - -func newDBQueryRequest(server string, dbid string, query string) (*http.Request, error) { - queryReq := &txpb.QueryRequest{ - Dbid: dbid, - Query: query, - } - - var bodyReader io.Reader - buf, err := json.Marshal(queryReq) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/query", bodyReader) -} - -func parseDBQueryResponse(resp *http.Response) ([]map[string]any, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.QueryResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseDBQueryResponse: %w", err) - } - - var result []map[string]any - err = json.Unmarshal(res.Result, &result) - if err != nil { - return nil, fmt.Errorf("parseDBQueryResponse: %w", err) - } - - return result, nil -} - -func newGetSchemaRequest(server string, dbid string) (*http.Request, error) { - dbid = url.PathEscape(dbid) - return NewGetRequest(server, fmt.Sprintf("/api/v1/databases/%s/schema", dbid)) -} - -func parseGetSchemaResponse(resp *http.Response) (*transactions.Schema, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res txpb.GetSchemaResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseGetSchemaResponse: %w", err) - } - - return conversion.ConvertFromPBSchema(res.Schema), nil -} - -func newValidatorJoinStatusRequest(server string, publicKey []byte) (*http.Request, error) { - pk := url.PathEscape(base64.URLEncoding.EncodeToString(publicKey)) - return NewGetRequest(server, fmt.Sprintf("/api/v1/validator_join_status/%s", pk)) -} - -func parseValidatorJoinStatusResponse(resp *http.Response, publicKey []byte) (*types.JoinRequest, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res validatorJoinsStatusResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseValidatorJoinStatusResponse: %w", err) - } - - jq := conversion.ConvertFromPBJoinRequest((*txpb.ValidatorJoinStatusResponse)(&res)) - jq.Candidate = publicKey - return jq, nil -} - -func newCurrentValidatorsRequest(server string) (*http.Request, error) { - return NewGetRequest(server, "/api/v1/current_validators") -} - -func parseCurrentValidatorsResponse(resp *http.Response) ([]*types.Validator, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res currentValidatorsResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseCurrentValidatorsResponse: %w", err) - } - - vals := make([]*types.Validator, len(res.Validators)) - for i, vi := range res.Validators { - vals[i] = &types.Validator{ - PubKey: vi.Pubkey, - Power: vi.Power, - } - } - return vals, nil -} - -func newChainInfoRequest(server string) (*http.Request, error) { - return NewGetRequest(server, "/api/v1/chain_info") -} - -func parseChainInfoResponse(resp *http.Response) (*types.ChainInfo, error) { - if resp.StatusCode != http.StatusOK { - return nil, parseErrorResponse(resp) - } - - var res chainInfoResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return nil, fmt.Errorf("parseChainInfoResponse: %w", err) - } - - info := types.ChainInfo{ - ChainID: res.ChainId, - BlockHeight: res.Height, - BlockHash: res.Hash, - } - - return &info, nil -} - -func newVerifySignatureRequest(server string, sender []byte, sig *auth.Signature, - msg []byte) (*http.Request, error) { - req := &txpb.VerifySignatureRequest{ - Signature: &txpb.Signature{ - SignatureBytes: sig.Signature, - SignatureType: sig.Type, - }, - Sender: sender, - Msg: msg, - } - - var bodyReader io.Reader - buf, err := json.Marshal(req) - if err != nil { - return nil, err - } - - bodyReader = bytes.NewReader(buf) - - return NewJsonPostRequest(server, "/api/v1/verify_signature", bodyReader) -} - -// parseVerifySignatureResponse parses the response from verify_signature endpoint. -// An ErrInvalidSignature is returned if the signature is invalid. -func parseVerifySignatureResponse(resp *http.Response) error { - if resp.StatusCode != http.StatusOK { - return parseErrorResponse(resp) - } - - var res txpb.VerifySignatureResponse - err := unmarshalResponse(resp.Body, &res) - if err != nil { - return fmt.Errorf("parseVerifySignatureResponse: %w", err) - } - - // caller can tell if signature is valid - if !res.Valid { - return fmt.Errorf("%w: %s", client.ErrInvalidSignature, res.Error) - } - - return nil -} diff --git a/core/rpc/client/user/http/req_test.go b/core/rpc/client/user/http/req_test.go deleted file mode 100644 index 935ceb543..000000000 --- a/core/rpc/client/user/http/req_test.go +++ /dev/null @@ -1,564 +0,0 @@ -package http - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "flag" - "fmt" - "io" - "math/big" - "net/http" - "os" - "path/filepath" - "testing" - - "github.com/kwilteam/kwil-db/core/rpc/client" - "github.com/kwilteam/kwil-db/core/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var ( - update = flag.Bool("update", false, "update the golden files of this test") -) - -var testDataDir = "testdata" - -func goldenValue(t *testing.T, goldenFile string, actual string, update bool) string { - t.Helper() - goldenPath := filepath.Join(".", testDataDir, goldenFile+"_expect.json") - - f, err := os.OpenFile(goldenPath, os.O_RDWR|os.O_CREATE, 0666) - require.NoError(t, err) - defer f.Close() - - if update { - _, err := f.WriteString(actual) - if err != nil { - t.Fatalf("Error writing to file %s: %s", goldenPath, err) - } - - return actual - } - - content, err := io.ReadAll(f) - if err != nil { - t.Fatalf("Error opening file %s: %s", goldenPath, err) - } - return string(content) -} - -func Test_parseEstimateCostResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - want *big.Int - }{ - { - name: "ok", - resp: []byte(`{"price":"100"}`), - want: big.NewInt(100), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseEstimateCostResponse(&response) - assert.NoError(t, err) - assert.Equal(t, tt.want, got) - }) - } -} - -func Test_parseBroadcastResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - wantBase64 string - }{ - { - name: "ok", - resp: []byte(`{"tx_hash":"FawI7Hzfc3lC9zqyWvO6xeXAsCGjsI99d/cjXShFoXU="}`), - wantBase64: "FawI7Hzfc3lC9zqyWvO6xeXAsCGjsI99d/cjXShFoXU=", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseBroadcastResponse(&response) - assert.NoError(t, err) - - want, _ := base64.StdEncoding.DecodeString(tt.wantBase64) - assert.Equal(t, want, got) - }) - } -} - -func Test_parseGetAccountResponse(t *testing.T) { - // got lazy so no need to construct the whole parsed *types.Account - // `go test -run Test_parseGetAccountResponse . -update` to update _expect.json - tests := []struct { - name string - target string - statusCode int - }{ - { - name: "ok but not exist", - target: "get_account_not_exist", - statusCode: http.StatusOK, - }, - { - name: "ok", - target: "get_account_ok", - statusCode: http.StatusOK, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - jsonPath := filepath.Join(".", testDataDir, tt.target+"_response.json") - data, err := os.ReadFile(jsonPath) - require.NoError(t, err) - - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(data)), - } - - gotObj, err := parseGetAccountResponse(&response) - if tt.statusCode != http.StatusOK { - assert.Error(t, err) - return - } - - assert.NoError(t, err) - - got, err := json.MarshalIndent(gotObj, "", " ") - assert.NoError(t, err) - - want := goldenValue(t, tt.target, string(got), *update) - assert.Equal(t, want, string(got)) - }) - } -} - -func Test_parseTxQueryResponse(t *testing.T) { - // NOTE: probably should construct *transactions.TcTxQueryResponse - // ./testdata/NAME_response.json - // ./testdata/NAME_expect.json - // the difference between _response.json and _expect.json is that - // int64 is string in _response.json - // `go test -run Test_parseTxQueryResponse . -update` to update _expect.json - - tests := []struct { - name string - target string - statusCode int - errMsg string // this sucks - }{ - { - name: "ok", - target: "tx_query_ok", - statusCode: http.StatusOK, - }, - { - name: "tx not found", - target: "tx_query_not_found", - statusCode: http.StatusNotFound, - errMsg: "transaction not found", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - jsonPath := filepath.Join(".", testDataDir, tt.target+"_response.json") - data, err := os.ReadFile(jsonPath) - require.NoError(t, err) - - response := http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(data)), - } - - gotObj, err := parseTxQueryResponse(&response) - if tt.statusCode != http.StatusOK { - assert.Error(t, err) - assert.Contains(t, err.Error(), tt.errMsg) - return - } - - assert.NoError(t, err) - - got, err := json.MarshalIndent(gotObj, "", " ") - assert.NoError(t, err) - - want := goldenValue(t, tt.target, string(got), *update) - assert.Equal(t, want, string(got)) - }) - } -} - -func Test_parseListDatabasesResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - want []string - }{ - { - name: "ok", - resp: []byte(`{ - "databases": [ - "testdb" - ] -}`), - want: []string{"testdb"}, - }, - { - name: "ok but no databases", - resp: []byte(`{ - "databases": [] -}`), - want: []string{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseListDatabasesResponse(&response) - assert.NoError(t, err) - assert.Equal(t, tt.want, got) - }) - } -} - -func Test_parseActionCallResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - want []map[string]any - }{ - { - name: "ok", - // base64 of [{"owner only":"owner only"}] - resp: []byte(`{"result":"W3siJ293bmVyIG9ubHknIjoib3duZXIgb25seSJ9XQ=="}`), - want: []map[string]any{ - { - "'owner only'": "owner only", - }, - }, - }, - { - name: "data", - resp: []byte(`{"result":"W3siYWdlIjozMywiaWQiOjIsInVzZXJuYW1lIjoic2F0b3NoaSJ9XQ=="}`), - want: []map[string]any{ - { - "age": float64(33), // json unmarshal to float64 - "id": float64(2), - "username": "satoshi", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseActionCallResponse(&response) - assert.NoError(t, err) - - assert.EqualValues(t, tt.want, got) - }) - } -} - -func Test_parseDBQueryResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - want []map[string]any - }{ - { - name: "ok", - // base64 of [{"owner only":"owner only"}] - resp: []byte(`{"result":"W3siJ293bmVyIG9ubHknIjoib3duZXIgb25seSJ9XQ=="}`), - want: []map[string]any{ - { - "'owner only'": "owner only", - }, - }, - }, - { - name: "data", - resp: []byte(`{"result":"W3siYWdlIjozMywiaWQiOjIsInVzZXJuYW1lIjoic2F0b3NoaSJ9XQ=="}`), - want: []map[string]any{ - { - "age": float64(33), // json unmarshal to float64 - "id": float64(2), - "username": "satoshi", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseDBQueryResponse(&response) - assert.NoError(t, err) - - assert.EqualValues(t, tt.want, got) - }) - } -} - -func Test_parseGetSchemaResponse(t *testing.T) { - // go test -run Test_parseGetSchemaResponse . -update - tests := []struct { - name string - target string - statusCode int - errMsg string // this sucks - }{ - { - name: "ok", - target: "get_schema_ok", - statusCode: http.StatusOK, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - jsonPath := filepath.Join(".", testDataDir, tt.target+"_response.json") - data, err := os.ReadFile(jsonPath) - require.NoError(t, err) - - response := http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(data)), - } - - gotObj, err := parseGetSchemaResponse(&response) - if tt.statusCode != http.StatusOK { - assert.Error(t, err) - assert.Contains(t, err.Error(), tt.errMsg) - return - } - - assert.NoError(t, err) - - got, err := json.MarshalIndent(gotObj, "", " ") - assert.NoError(t, err) - - want := goldenValue(t, tt.target, string(got), *update) - assert.Equal(t, want, string(got)) - }) - } -} - -func Test_parseValidatorJoinStatusResponse(t *testing.T) { - pbk1Str := "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=" - pbk2Str := "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDL0=" - pubKey1, _ := base64.StdEncoding.DecodeString(pbk1Str) - pubKey2, _ := base64.StdEncoding.DecodeString(pbk2Str) - - tests := []struct { - name string - resp []byte - want *types.JoinRequest - }{ - { - name: "ok", - resp: []byte(fmt.Sprintf(`{ - "approved_validators":[ - "%s" - ], - "pending_validators":[ - "%s" - ], - "power": "10" -}`, pbk1Str, pbk2Str)), - want: &types.JoinRequest{ - Power: 10, - Board: [][]byte{ - pubKey1, - pubKey2, - }, - Approved: []bool{ - true, - false, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseValidatorJoinStatusResponse(&response, nil) - assert.NoError(t, err) - - assert.EqualValues(t, tt.want, got) - }) - } -} - -func Test_parseCurrentValidatorsResponse(t *testing.T) { - pbk1Str := "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=" - pbk2Str := "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDL0=" - pubKey1, _ := base64.StdEncoding.DecodeString(pbk1Str) - pubKey2, _ := base64.StdEncoding.DecodeString(pbk2Str) - - tests := []struct { - name string - resp []byte - want []*types.Validator - }{ - { - name: "ok", - resp: []byte(fmt.Sprintf(`{ - "validators": [ - { - "pubkey": "%s", - "power": "10" - }, - { - "pubkey": "%s", - "power": "10" - } - ] -} -`, pbk1Str, pbk2Str)), - want: []*types.Validator{ - { - PubKey: pubKey1, - Power: 10, - }, - { - PubKey: pubKey2, - Power: 10, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseCurrentValidatorsResponse(&response) - assert.NoError(t, err) - - assert.Equal(t, tt.want, got) - }) - } -} - -func Test_parseChainInfoResponse(t *testing.T) { - tests := []struct { - name string - resp []byte - want *types.ChainInfo - }{ - { - name: "ok", - resp: []byte(`{ - "chain_id": "kwil-chain-XHAPEDGA", - "height": "375", - "hash": "bfacc4bfc60620dec2456f3e66a369ce60ceb53402dd600163c68e1bbffb87e8" -}`), - want: &types.ChainInfo{ - ChainID: "kwil-chain-XHAPEDGA", - BlockHeight: 375, - BlockHash: "bfacc4bfc60620dec2456f3e66a369ce60ceb53402dd600163c68e1bbffb87e8", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - got, err := parseChainInfoResponse(&response) - assert.NoError(t, err) - - assert.EqualValues(t, tt.want, got) - }) - } -} - -func Test_parseVerifySignatureRespoonse(t *testing.T) { - tests := []struct { - name string - statusCode int - resp []byte - wantErr bool - invalid bool - }{ - { - name: "other error", - statusCode: http.StatusInternalServerError, - resp: []byte(`{ - "code": 5, - "message": "something happen", - "details": [] -}`), - wantErr: true, - }, - { - name: "ok", - statusCode: http.StatusOK, - resp: []byte(`{"valid":true, "error": ""}`), - }, - { - name: "invalid", - statusCode: http.StatusOK, - resp: []byte(`{"valid":false, "error": "some reason"}`), - wantErr: true, - invalid: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - response := http.Response{ - StatusCode: tt.statusCode, - Body: io.NopCloser(bytes.NewReader(tt.resp)), - } - - err := parseVerifySignatureResponse(&response) - if tt.wantErr { - assert.Error(t, err) - - if tt.invalid { - assert.ErrorIs(t, err, client.ErrInvalidSignature) - } - - return - } - - assert.NoError(t, err) - }) - } -} diff --git a/core/rpc/client/user/http/rpc.go b/core/rpc/client/user/http/rpc.go deleted file mode 100644 index 814755595..000000000 --- a/core/rpc/client/user/http/rpc.go +++ /dev/null @@ -1,232 +0,0 @@ -package http - -import ( - "context" - "encoding/json" - "fmt" - "io" - "math/big" - - "github.com/kwilteam/kwil-db/core/crypto/auth" - rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" - "github.com/kwilteam/kwil-db/core/types" - "github.com/kwilteam/kwil-db/core/types/transactions" -) - -func (c *Client) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { - req, err := newChainInfoRequest(c.target) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseChainInfoResponse(resp) -} - -func (c *Client) Call(ctx context.Context, msg *transactions.CallMessage, - opts ...rpcClient.ActionCallOption) ([]map[string]any, error) { - req, err := newActionCallRequest(c.target, msg) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - ctxReq := req.WithContext(ctx) - - // add auth cookies from current session - callOpts := rpcClient.ActionCallOpts{} - for _, o := range opts { - o(&callOpts) - } - if callOpts.AuthCookies != nil { - for _, cookie := range callOpts.AuthCookies { - ctxReq.AddCookie(cookie) - } - } - - // NOTE: probably should start to use status.FromError - resp, err := c.makeRequest(ctxReq) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseActionCallResponse(resp) -} - -func (c *Client) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) { - req, err := newTxQueryRequest(c.target, txHash) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseTxQueryResponse(resp) -} - -func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) { - req, err := newGetSchemaRequest(c.target, dbid) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseGetSchemaResponse(resp) -} - -func (c *Client) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) { - req, err := newDBQueryRequest(c.target, dbid, query) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseDBQueryResponse(resp) -} - -func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]string, error) { - req, err := newListDatabasesRequest(c.target, ownerPubKey) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseListDatabasesResponse(resp) -} - -func (c *Client) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) { - req, err := newGetAccountRequest(c.target, pubKey, status) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseGetAccountResponse(resp) -} - -func (c *Client) Broadcast(ctx context.Context, tx *transactions.Transaction) ([]byte, error) { - req, err := newBroadcastRequest(c.target, tx) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseBroadcastResponse(resp) -} - -// unmarshalResponse unmarshal the response into v, which should be a pointer. -func unmarshalResponse(resp io.Reader, v any) error { - decoder := json.NewDecoder(resp) - return decoder.Decode(v) -} - -// Ping sends a ping request to the target and returns the response body -func (c *Client) Ping(ctx context.Context) (string, error) { - req, err := newPingRequest(c.target) - if err != nil { - return "", fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return "", fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parsePingResponse(resp) -} - -func (c *Client) EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) { - req, err := newEstimateCostRequest(c.target, tx) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseEstimateCostResponse(resp) -} - -func (c *Client) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { - req, err := newValidatorJoinStatusRequest(c.target, pubKey) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseValidatorJoinStatusResponse(resp, pubKey) -} - -func (c *Client) CurrentValidators(ctx context.Context) ([]*types.Validator, error) { - req, err := newCurrentValidatorsRequest(c.target) - if err != nil { - return nil, fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return nil, fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseCurrentValidatorsResponse(resp) -} - -func (c *Client) VerifySignature(ctx context.Context, sender []byte, - signature *auth.Signature, message []byte) error { - req, err := newVerifySignatureRequest(c.target, sender, signature, message) - if err != nil { - return fmt.Errorf("create request: %w", err) - } - - resp, err := c.makeRequest(req.WithContext(ctx)) - if err != nil { - return fmt.Errorf("make request: %w", err) - } - defer resp.Body.Close() - - return parseVerifySignatureResponse(resp) -} diff --git a/core/rpc/client/user/http/testdata/get_account_not_exist_expect.json b/core/rpc/client/user/http/testdata/get_account_not_exist_expect.json deleted file mode 100644 index 3ca923efc..000000000 --- a/core/rpc/client/user/http/testdata/get_account_not_exist_expect.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "identifier": "", - "balance": 0, - "nonce": 0 -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/get_account_not_exist_response.json b/core/rpc/client/user/http/testdata/get_account_not_exist_response.json deleted file mode 100644 index 94af573c6..000000000 --- a/core/rpc/client/user/http/testdata/get_account_not_exist_response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "account": { - "identifier": "", - "balance": "0", - "nonce": "0" - } -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/get_account_ok_expect.json b/core/rpc/client/user/http/testdata/get_account_ok_expect.json deleted file mode 100644 index b34b490b6..000000000 --- a/core/rpc/client/user/http/testdata/get_account_ok_expect.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "identifier": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=", - "balance": 0, - "nonce": 1 -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/get_account_ok_response.json b/core/rpc/client/user/http/testdata/get_account_ok_response.json deleted file mode 100644 index 56714d178..000000000 --- a/core/rpc/client/user/http/testdata/get_account_ok_response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "account": { - "identifier": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=", - "balance": "0", - "nonce": "1" - } -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/get_schema_ok_expect.json b/core/rpc/client/user/http/testdata/get_schema_ok_expect.json deleted file mode 100644 index ac6a8e372..000000000 --- a/core/rpc/client/user/http/testdata/get_schema_ok_expect.json +++ /dev/null @@ -1,275 +0,0 @@ -{ - "owner": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=", - "name": "testdb", - "tables": [ - { - "name": "posts", - "columns": [ - { - "name": "id", - "type": "INT", - "attributes": [ - { - "type": "PRIMARY_KEY" - }, - { - "type": "NOT_NULL" - } - ] - }, - { - "name": "user_id", - "type": "INT" - }, - { - "name": "title", - "type": "TEXT" - }, - { - "name": "content", - "type": "TEXT", - "attributes": [ - { - "type": "MAX_LENGTH", - "value": "1000" - } - ] - } - ], - "indexes": [ - { - "name": "unique_index", - "columns": [ - "user_id", - "title" - ], - "type": "UNIQUE_BTREE" - } - ] - }, - { - "name": "users", - "columns": [ - { - "name": "id", - "type": "INT", - "attributes": [ - { - "type": "PRIMARY_KEY" - }, - { - "type": "NOT_NULL" - } - ] - }, - { - "name": "username", - "type": "TEXT", - "attributes": [ - { - "type": "DEFAULT", - "value": "sds" - } - ] - }, - { - "name": "age", - "type": "INT", - "attributes": [ - { - "type": "MIN", - "value": "0" - } - ] - }, - { - "name": "wallet", - "type": "BLOB", - "attributes": [ - { - "type": "UNIQUE" - } - ] - } - ] - } - ], - "actions": [ - { - "name": "get_post_authenticated", - "inputs": [ - "$id" - ], - "mutability": "view", - "public": true, - "statements": [ - "SELECT *\n FROM posts\n WHERE id = $id;" - ] - }, - { - "name": "get_user_posts", - "inputs": [ - "$username" - ], - "mutability": "update", - "public": true, - "statements": [ - "SELECT title, content\n FROM posts\n WHERE user_id = (\n SELECT id\n FROM users\n WHERE username = $username\n );" - ] - }, - { - "name": "update_user", - "inputs": [ - "$id", - "$username", - "$age" - ], - "mutability": "update", - "public": true, - "statements": [ - "UPDATE [users]\n SET id = $id, username = $username, age = $age\n WHERE wallet = @caller;" - ] - }, - { - "name": "divide", - "inputs": [ - "$numerator1", - "$numerator2", - "$denominator" - ], - "mutability": "view", - "public": true, - "statements": [ - "$up=math_up.div(abs($numerator1+$numerator2),$denominator);", - "$down=math_down.div(abs($numerator1+$numerator2),$denominator);", - "select $up AS upper_value, $down AS lower_value;" - ] - }, - { - "name": "get_post_unauthenticated", - "inputs": [ - "$id" - ], - "mutability": "view", - "public": true, - "statements": [ - "SELECT *\n FROM \"posts\"\n WHERE id = $id;" - ] - }, - { - "name": "get_user_by_wallet", - "inputs": [ - "$address" - ], - "mutability": "update", - "public": true, - "statements": [ - "SELECT *\n FROM users\n WHERE wallet = $address;" - ] - }, - { - "name": "get_user_posts_by_userid", - "inputs": [ - "$id" - ], - "mutability": "update", - "public": true, - "statements": [ - "SELECT title, content\n FROM posts\n WHERE user_id = $id;" - ] - }, - { - "name": "list_users", - "mutability": "update", - "public": true, - "statements": [ - "SELECT *\n FROM users;" - ] - }, - { - "name": "owner_only", - "mutability": "view", - "public": true, - "statements": [ - "select 'owner only';" - ] - }, - { - "name": "create_post", - "inputs": [ - "$id", - "$title", - "$content" - ], - "mutability": "update", - "public": true, - "statements": [ - "INSERT INTO posts (id, user_id, title, content)\n VALUES ($id, (\n SELECT id FROM users WHERE wallet = @caller\n ), $title, $content);" - ] - }, - { - "name": "create_user", - "inputs": [ - "$id", - "$username", - "$age" - ], - "mutability": "update", - "public": true, - "statements": [ - "INSERT INTO \"users\" (id, username, age, wallet)\n VALUES ($id, $username, $age, @caller);" - ] - }, - { - "name": "delete_post", - "inputs": [ - "$id" - ], - "mutability": "update", - "public": true, - "statements": [ - "DELETE FROM posts\n WHERE id = $id AND user_id = (\n SELECT id\n FROM users\n WHERE wallet = @caller\n );" - ] - }, - { - "name": "update_username", - "inputs": [ - "$username" - ], - "mutability": "update", - "public": true, - "statements": [ - "UPDATE `users`\n SET username = $username\n WHERE wallet = @caller;" - ] - }, - { - "name": "delete_user", - "mutability": "update", - "public": true, - "statements": [ - "DELETE FROM users\n WHERE public_key(wallet) = public_key(@caller);" - ] - }, - { - "name": "delete_user_by_id", - "inputs": [ - "$id" - ], - "mutability": "update", - "public": true, - "statements": [ - "DELETE FROM \"users\"\n WHERE id = $id AND public_key(wallet) = public_key(@caller);" - ] - }, - { - "name": "multi_select", - "mutability": "update", - "public": true, - "statements": [ - "SELECT * FROM posts;", - "SELECT * FROM users;" - ] - } - ], - "extensions": null -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/get_schema_ok_response.json b/core/rpc/client/user/http/testdata/get_schema_ok_response.json deleted file mode 100644 index bd79a55d8..000000000 --- a/core/rpc/client/user/http/testdata/get_schema_ok_response.json +++ /dev/null @@ -1,312 +0,0 @@ -{ - "schema": { - "owner": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=", - "name": "testdb", - "tables": [ - { - "name": "posts", - "columns": [ - { - "name": "id", - "type": "INT", - "attributes": [ - { - "type": "PRIMARY_KEY", - "value": "" - }, - { - "type": "NOT_NULL", - "value": "" - } - ] - }, - { - "name": "user_id", - "type": "INT", - "attributes": [] - }, - { - "name": "title", - "type": "TEXT", - "attributes": [] - }, - { - "name": "content", - "type": "TEXT", - "attributes": [ - { - "type": "MAX_LENGTH", - "value": "1000" - } - ] - } - ], - "indexes": [ - { - "name": "unique_index", - "columns": [ - "user_id", - "title" - ], - "type": "UNIQUE_BTREE" - } - ] - }, - { - "name": "users", - "columns": [ - { - "name": "id", - "type": "INT", - "attributes": [ - { - "type": "PRIMARY_KEY", - "value": "" - }, - { - "type": "NOT_NULL", - "value": "" - } - ] - }, - { - "name": "username", - "type": "TEXT", - "attributes": [ - { - "type": "DEFAULT", - "value": "sds" - } - ] - }, - { - "name": "age", - "type": "INT", - "attributes": [ - { - "type": "MIN", - "value": "0" - } - ] - }, - { - "name": "wallet", - "type": "BLOB", - "attributes": [ - { - "type": "UNIQUE", - "value": "" - } - ] - } - ], - "indexes": [] - } - ], - "actions": [ - { - "name": "get_post_authenticated", - "public": true, - "inputs": [ - "$id" - ], - "statements": [ - "SELECT *\n FROM posts\n WHERE id = $id;" - ], - "mutability": "view", - "auxiliaries": [ - "mustsign" - ] - }, - { - "name": "get_user_posts", - "public": true, - "inputs": [ - "$username" - ], - "statements": [ - "SELECT title, content\n FROM posts\n WHERE user_id = (\n SELECT id\n FROM users\n WHERE username = $username\n );" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "update_user", - "public": true, - "inputs": [ - "$id", - "$username", - "$age" - ], - "statements": [ - "UPDATE [users]\n SET id = $id, username = $username, age = $age\n WHERE wallet = @caller;" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "divide", - "public": true, - "inputs": [ - "$numerator1", - "$numerator2", - "$denominator" - ], - "statements": [ - "$up=math_up.div(abs($numerator1+$numerator2),$denominator);", - "$down=math_down.div(abs($numerator1+$numerator2),$denominator);", - "select $up AS upper_value, $down AS lower_value;" - ], - "mutability": "view", - "auxiliaries": [] - }, - { - "name": "get_post_unauthenticated", - "public": true, - "inputs": [ - "$id" - ], - "statements": [ - "SELECT *\n FROM \"posts\"\n WHERE id = $id;" - ], - "mutability": "view", - "auxiliaries": [] - }, - { - "name": "get_user_by_wallet", - "public": true, - "inputs": [ - "$address" - ], - "statements": [ - "SELECT *\n FROM users\n WHERE wallet = $address;" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "get_user_posts_by_userid", - "public": true, - "inputs": [ - "$id" - ], - "statements": [ - "SELECT title, content\n FROM posts\n WHERE user_id = $id;" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "list_users", - "public": true, - "inputs": [], - "statements": [ - "SELECT *\n FROM users;" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "owner_only", - "public": true, - "inputs": [], - "statements": [ - "select 'owner only';" - ], - "mutability": "view", - "auxiliaries": [ - "owner", - "mustsign" - ] - }, - { - "name": "create_post", - "public": true, - "inputs": [ - "$id", - "$title", - "$content" - ], - "statements": [ - "INSERT INTO posts (id, user_id, title, content)\n VALUES ($id, (\n SELECT id FROM users WHERE wallet = @caller\n ), $title, $content);" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "create_user", - "public": true, - "inputs": [ - "$id", - "$username", - "$age" - ], - "statements": [ - "INSERT INTO \"users\" (id, username, age, wallet)\n VALUES ($id, $username, $age, @caller);" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "delete_post", - "public": true, - "inputs": [ - "$id" - ], - "statements": [ - "DELETE FROM posts\n WHERE id = $id AND user_id = (\n SELECT id\n FROM users\n WHERE wallet = @caller\n );" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "update_username", - "public": true, - "inputs": [ - "$username" - ], - "statements": [ - "UPDATE `users`\n SET username = $username\n WHERE wallet = @caller;" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "delete_user", - "public": true, - "inputs": [], - "statements": [ - "DELETE FROM users\n WHERE public_key(wallet) = public_key(@caller);" - ], - "mutability": "update", - "auxiliaries": [] - }, - { - "name": "delete_user_by_id", - "public": true, - "inputs": [ - "$id" - ], - "statements": [ - "DELETE FROM \"users\"\n WHERE id = $id AND public_key(wallet) = public_key(@caller);" - ], - "mutability": "update", - "auxiliaries": [ - "owner" - ] - }, - { - "name": "multi_select", - "public": true, - "inputs": [], - "statements": [ - "SELECT * FROM posts;", - "SELECT * FROM users;" - ], - "mutability": "update", - "auxiliaries": [] - } - ], - "extensions": [] - } -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/tx_query_not_found_response.json b/core/rpc/client/user/http/testdata/tx_query_not_found_response.json deleted file mode 100644 index cabca7221..000000000 --- a/core/rpc/client/user/http/testdata/tx_query_not_found_response.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": 5, - "message": "transaction not found", - "details": [] -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/tx_query_ok_expect.json b/core/rpc/client/user/http/testdata/tx_query_ok_expect.json deleted file mode 100644 index 7072eb470..000000000 --- a/core/rpc/client/user/http/testdata/tx_query_ok_expect.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "hash": "FawI7Hzfc3lC9zqyWvO6xeXAsCGjsI99d/cjXShFoXU=", - "height": 486, - "tx": { - "Signature": { - "signature_bytes": "ynYVUxFKPQ5/kXpFeWpfUHtVE1a0+/YjeNjxl1ogamwcT0r85ZwNZFXtC82PHLZw41655FZNWrp1SHDn6hJJ8gE=", - "signature_type": "secp256k1_ep" - }, - "Body": { - "Description": "", - "Payload": "AAH5CQuAhnRlc3RkYvkBOvhwhXVzZXJz+Gbhgmlkg2ludNnNi3ByaW1hcnlfa2V5gMqIbm90X251bGyA3Ih1c2VybmFtZYR0ZXh0zcyHZGVmYXVsdINzZHPPg2FnZYNpbnTGxYNtaW4w1oZ3YWxsZXSEYmxvYsnIhnVuaXF1ZYDAwPjGhXBvc3Rz+F3hgmlkg2ludNnNi3ByaW1hcnlfa2V5gMqIbm90X251bGyAzYd1c2VyX2lkg2ludMDMhXRpdGxlhHRleHTA34djb250ZW50hHRleHTR0IptYXhfbGVuZ3RohDEwMDDq6Yx1bmlxdWVfaW5kZXjOh3VzZXJfaWSFdGl0bGWMdW5pcXVlX2J0cmVl9fTIh3VzZXJfaWTDgmlkhXVzZXJz4M+GREVMRVRFh0NBU0NBREXPhlVQREFURYdDQVNDQURF+QeH+IiLY3JlYXRlX3VzZXLTgyRpZIkkdXNlcm5hbWWEJGFnZYZ1cGRhdGXAAfhduFtJTlNFUlQgSU5UTyAidXNlcnMiIChpZCwgdXNlcm5hbWUsIGFnZSwgd2FsbGV0KQogICAgVkFMVUVTICgkaWQsICR1c2VybmFtZSwgJGFnZSwgQGNhbGxlcik7+IqLdXBkYXRlX3VzZXLTgyRpZIkkdXNlcm5hbWWEJGFnZYZ1cGRhdGXAAfhfuF1VUERBVEUgW3VzZXJzXQogICAgU0VUIGlkID0gJGlkLCB1c2VybmFtZSA9ICR1c2VybmFtZSwgYWdlID0gJGFnZQogICAgV0hFUkUgd2FsbGV0ID0gQGNhbGxlcjv4b491cGRhdGVfdXNlcm5hbWXKiSR1c2VybmFtZYZ1cGRhdGXAAfhJuEdVUERBVEUgYHVzZXJzYAogICAgU0VUIHVzZXJuYW1lID0gJHVzZXJuYW1lCiAgICBXSEVSRSB3YWxsZXQgPSBAY2FsbGVyO/hfi2RlbGV0ZV91c2VywIZ1cGRhdGXAAfhHuEVERUxFVEUgRlJPTSB1c2VycwogICAgV0hFUkUgcHVibGljX2tleSh3YWxsZXQpID0gcHVibGljX2tleShAY2FsbGVyKTv4fpFkZWxldGVfdXNlcl9ieV9pZMSDJGlkhnVwZGF0ZcaFb3duZXIB+Fa4VERFTEVURSBGUk9NICJ1c2VycyIKICAgIFdIRVJFIGlkID0gJGlkIEFORCBwdWJsaWNfa2V5KHdhbGxldCkgPSBwdWJsaWNfa2V5KEBjYWxsZXIpO/i+i2NyZWF0ZV9wb3N01IMkaWSGJHRpdGxliCRjb250ZW50hnVwZGF0ZcAB+JK4kElOU0VSVCBJTlRPIHBvc3RzIChpZCwgdXNlcl9pZCwgdGl0bGUsIGNvbnRlbnQpCiAgICBWQUxVRVMgKCRpZCwgKAogICAgICAgIFNFTEVDVCBpZCBGUk9NIHVzZXJzIFdIRVJFIHdhbGxldCA9IEBjYWxsZXIKICAgICksICR0aXRsZSwgJGNvbnRlbnQpO/idi2RlbGV0ZV9wb3N0xIMkaWSGdXBkYXRlwAH4gbh/REVMRVRFIEZST00gcG9zdHMKICAgIFdIRVJFIGlkID0gJGlkIEFORCB1c2VyX2lkID0gKAogICAgICAgIFNFTEVDVCBpZAogICAgICAgIEZST00gdXNlcnMKICAgICAgICBXSEVSRSB3YWxsZXQgPSBAY2FsbGVyCiAgICApO/hckmdldF91c2VyX2J5X3dhbGxldMmIJGFkZHJlc3OGdXBkYXRlwAH1tFNFTEVDVCAqCiAgICBGUk9NIHVzZXJzCiAgICBXSEVSRSB3YWxsZXQgPSAkYWRkcmVzczvvimxpc3RfdXNlcnPAhnVwZGF0ZcAB2ZhTRUxFQ1QgKgogICAgRlJPTSB1c2Vyczv4aJhnZXRfdXNlcl9wb3N0c19ieV91c2VyaWTEgyRpZIZ1cGRhdGXAAfg/uD1TRUxFQ1QgdGl0bGUsIGNvbnRlbnQKICAgIEZST00gcG9zdHMKICAgIFdIRVJFIHVzZXJfaWQgPSAkaWQ7+LCOZ2V0X3VzZXJfcG9zdHPKiSR1c2VybmFtZYZ1cGRhdGXAAfiLuIlTRUxFQ1QgdGl0bGUsIGNvbnRlbnQKICAgIEZST00gcG9zdHMKICAgIFdIRVJFIHVzZXJfaWQgPSAoCiAgICAgICAgU0VMRUNUIGlkCiAgICAgICAgRlJPTSB1c2VycwogICAgICAgIFdIRVJFIHVzZXJuYW1lID0gJHVzZXJuYW1lCiAgICApO/hZlmdldF9wb3N0X2F1dGhlbnRpY2F0ZWTEgyRpZIR2aWV3yYhtdXN0c2lnbgHsq1NFTEVDVCAqCiAgICBGUk9NIHBvc3RzCiAgICBXSEVSRSBpZCA9ICRpZDv4VJhnZXRfcG9zdF91bmF1dGhlbnRpY2F0ZWTEgyRpZIR2aWV3wAHurVNFTEVDVCAqCiAgICBGUk9NICJwb3N0cyIKICAgIFdIRVJFIGlkID0gJGlkO/hCjG11bHRpX3NlbGVjdMCGdXBkYXRlwAHqlFNFTEVDVCAqIEZST00gcG9zdHM7lFNFTEVDVCAqIEZST00gdXNlcnM7+OWGZGl2aWRl5YskbnVtZXJhdG9yMYskbnVtZXJhdG9yMowkZGVub21pbmF0b3KEdmlld8AB+K+4OyR1cD1tYXRoX3VwLmRpdihhYnMoJG51bWVyYXRvcjErJG51bWVyYXRvcjIpLCRkZW5vbWluYXRvcik7uD8kZG93bj1tYXRoX2Rvd24uZGl2KGFicygkbnVtZXJhdG9yMSskbnVtZXJhdG9yMiksJGRlbm9taW5hdG9yKTuwc2VsZWN0ICR1cCBBUyB1cHBlcl92YWx1ZSwgJGRvd24gQVMgbG93ZXJfdmFsdWU7+DiKb3duZXJfb25secCEdmlld8+Fb3duZXKIbXVzdHNpZ24B1ZRzZWxlY3QgJ293bmVyIG9ubHknO/g62oRtYXRozMuFcm91bmSEJ3VwJ4dtYXRoX3Vw3oRtYXRozs2Fcm91bmSGJ2Rvd24niW1hdGhfZG93bg==", - "PayloadType": "deploy_schema", - "Fee": 0, - "Nonce": 1, - "ChainID": "kwil-chain-1" - }, - "Serialization": "concat", - "Sender": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=" - }, - "tx_result": { - "code": 0, - "log": "success", - "gas_used": 0, - "gas_wanted": 0 - } -} \ No newline at end of file diff --git a/core/rpc/client/user/http/testdata/tx_query_ok_response.json b/core/rpc/client/user/http/testdata/tx_query_ok_response.json deleted file mode 100644 index 242a8bfa9..000000000 --- a/core/rpc/client/user/http/testdata/tx_query_ok_response.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "hash": "FawI7Hzfc3lC9zqyWvO6xeXAsCGjsI99d/cjXShFoXU=", - "height": "486", - "tx": { - "body": { - "payload": "AAH5CQuAhnRlc3RkYvkBOvhwhXVzZXJz+Gbhgmlkg2ludNnNi3ByaW1hcnlfa2V5gMqIbm90X251bGyA3Ih1c2VybmFtZYR0ZXh0zcyHZGVmYXVsdINzZHPPg2FnZYNpbnTGxYNtaW4w1oZ3YWxsZXSEYmxvYsnIhnVuaXF1ZYDAwPjGhXBvc3Rz+F3hgmlkg2ludNnNi3ByaW1hcnlfa2V5gMqIbm90X251bGyAzYd1c2VyX2lkg2ludMDMhXRpdGxlhHRleHTA34djb250ZW50hHRleHTR0IptYXhfbGVuZ3RohDEwMDDq6Yx1bmlxdWVfaW5kZXjOh3VzZXJfaWSFdGl0bGWMdW5pcXVlX2J0cmVl9fTIh3VzZXJfaWTDgmlkhXVzZXJz4M+GREVMRVRFh0NBU0NBREXPhlVQREFURYdDQVNDQURF+QeH+IiLY3JlYXRlX3VzZXLTgyRpZIkkdXNlcm5hbWWEJGFnZYZ1cGRhdGXAAfhduFtJTlNFUlQgSU5UTyAidXNlcnMiIChpZCwgdXNlcm5hbWUsIGFnZSwgd2FsbGV0KQogICAgVkFMVUVTICgkaWQsICR1c2VybmFtZSwgJGFnZSwgQGNhbGxlcik7+IqLdXBkYXRlX3VzZXLTgyRpZIkkdXNlcm5hbWWEJGFnZYZ1cGRhdGXAAfhfuF1VUERBVEUgW3VzZXJzXQogICAgU0VUIGlkID0gJGlkLCB1c2VybmFtZSA9ICR1c2VybmFtZSwgYWdlID0gJGFnZQogICAgV0hFUkUgd2FsbGV0ID0gQGNhbGxlcjv4b491cGRhdGVfdXNlcm5hbWXKiSR1c2VybmFtZYZ1cGRhdGXAAfhJuEdVUERBVEUgYHVzZXJzYAogICAgU0VUIHVzZXJuYW1lID0gJHVzZXJuYW1lCiAgICBXSEVSRSB3YWxsZXQgPSBAY2FsbGVyO/hfi2RlbGV0ZV91c2VywIZ1cGRhdGXAAfhHuEVERUxFVEUgRlJPTSB1c2VycwogICAgV0hFUkUgcHVibGljX2tleSh3YWxsZXQpID0gcHVibGljX2tleShAY2FsbGVyKTv4fpFkZWxldGVfdXNlcl9ieV9pZMSDJGlkhnVwZGF0ZcaFb3duZXIB+Fa4VERFTEVURSBGUk9NICJ1c2VycyIKICAgIFdIRVJFIGlkID0gJGlkIEFORCBwdWJsaWNfa2V5KHdhbGxldCkgPSBwdWJsaWNfa2V5KEBjYWxsZXIpO/i+i2NyZWF0ZV9wb3N01IMkaWSGJHRpdGxliCRjb250ZW50hnVwZGF0ZcAB+JK4kElOU0VSVCBJTlRPIHBvc3RzIChpZCwgdXNlcl9pZCwgdGl0bGUsIGNvbnRlbnQpCiAgICBWQUxVRVMgKCRpZCwgKAogICAgICAgIFNFTEVDVCBpZCBGUk9NIHVzZXJzIFdIRVJFIHdhbGxldCA9IEBjYWxsZXIKICAgICksICR0aXRsZSwgJGNvbnRlbnQpO/idi2RlbGV0ZV9wb3N0xIMkaWSGdXBkYXRlwAH4gbh/REVMRVRFIEZST00gcG9zdHMKICAgIFdIRVJFIGlkID0gJGlkIEFORCB1c2VyX2lkID0gKAogICAgICAgIFNFTEVDVCBpZAogICAgICAgIEZST00gdXNlcnMKICAgICAgICBXSEVSRSB3YWxsZXQgPSBAY2FsbGVyCiAgICApO/hckmdldF91c2VyX2J5X3dhbGxldMmIJGFkZHJlc3OGdXBkYXRlwAH1tFNFTEVDVCAqCiAgICBGUk9NIHVzZXJzCiAgICBXSEVSRSB3YWxsZXQgPSAkYWRkcmVzczvvimxpc3RfdXNlcnPAhnVwZGF0ZcAB2ZhTRUxFQ1QgKgogICAgRlJPTSB1c2Vyczv4aJhnZXRfdXNlcl9wb3N0c19ieV91c2VyaWTEgyRpZIZ1cGRhdGXAAfg/uD1TRUxFQ1QgdGl0bGUsIGNvbnRlbnQKICAgIEZST00gcG9zdHMKICAgIFdIRVJFIHVzZXJfaWQgPSAkaWQ7+LCOZ2V0X3VzZXJfcG9zdHPKiSR1c2VybmFtZYZ1cGRhdGXAAfiLuIlTRUxFQ1QgdGl0bGUsIGNvbnRlbnQKICAgIEZST00gcG9zdHMKICAgIFdIRVJFIHVzZXJfaWQgPSAoCiAgICAgICAgU0VMRUNUIGlkCiAgICAgICAgRlJPTSB1c2VycwogICAgICAgIFdIRVJFIHVzZXJuYW1lID0gJHVzZXJuYW1lCiAgICApO/hZlmdldF9wb3N0X2F1dGhlbnRpY2F0ZWTEgyRpZIR2aWV3yYhtdXN0c2lnbgHsq1NFTEVDVCAqCiAgICBGUk9NIHBvc3RzCiAgICBXSEVSRSBpZCA9ICRpZDv4VJhnZXRfcG9zdF91bmF1dGhlbnRpY2F0ZWTEgyRpZIR2aWV3wAHurVNFTEVDVCAqCiAgICBGUk9NICJwb3N0cyIKICAgIFdIRVJFIGlkID0gJGlkO/hCjG11bHRpX3NlbGVjdMCGdXBkYXRlwAHqlFNFTEVDVCAqIEZST00gcG9zdHM7lFNFTEVDVCAqIEZST00gdXNlcnM7+OWGZGl2aWRl5YskbnVtZXJhdG9yMYskbnVtZXJhdG9yMowkZGVub21pbmF0b3KEdmlld8AB+K+4OyR1cD1tYXRoX3VwLmRpdihhYnMoJG51bWVyYXRvcjErJG51bWVyYXRvcjIpLCRkZW5vbWluYXRvcik7uD8kZG93bj1tYXRoX2Rvd24uZGl2KGFicygkbnVtZXJhdG9yMSskbnVtZXJhdG9yMiksJGRlbm9taW5hdG9yKTuwc2VsZWN0ICR1cCBBUyB1cHBlcl92YWx1ZSwgJGRvd24gQVMgbG93ZXJfdmFsdWU7+DiKb3duZXJfb25secCEdmlld8+Fb3duZXKIbXVzdHNpZ24B1ZRzZWxlY3QgJ293bmVyIG9ubHknO/g62oRtYXRozMuFcm91bmSEJ3VwJ4dtYXRoX3Vw3oRtYXRozs2Fcm91bmSGJ2Rvd24niW1hdGhfZG93bg==", - "payload_type": "deploy_schema", - "fee": "0", - "nonce": "1", - "chain_id": "kwil-chain-1", - "description": "" - }, - "signature": { - "signature_bytes": "ynYVUxFKPQ5/kXpFeWpfUHtVE1a0+/YjeNjxl1ogamwcT0r85ZwNZFXtC82PHLZw41655FZNWrp1SHDn6hJJ8gE=", - "signature_type": "secp256k1_ep" - }, - "sender": "BIEr70T257KhnAsBwtyl5Uuhk1oYkP/cuTq9DFNLIJwh5PYXaCP+9JP3ta+qRW8x1SkzY9j4AcVA68wGGBKJDLo=", - "serialization": "concat" - }, - "tx_result": { - "code": 0, - "log": "success", - "gas_used": "0", - "gas_wanted": "0", - "data": "", - "events": [] - } -} \ No newline at end of file diff --git a/core/rpc/client/user/http/typewrap.go b/core/rpc/client/user/http/typewrap.go deleted file mode 100644 index 0039ff2e1..000000000 --- a/core/rpc/client/user/http/typewrap.go +++ /dev/null @@ -1,225 +0,0 @@ -package http - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "strconv" - - txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" -) - -// Due to https://protobuf.dev/programming-guides/proto3/#json, protobuf -// fields defined as `int64` will be marshaled as `string` in JSON. -// Those types are wrapped here to unmarshal them correctly. -// NOTE: Should always wrap the protobuf type. - -type account txpb.Account - -func (a *account) UnmarshalJSON(data []byte) error { - var acc struct { - Identifier string `json:"identifier"` - Balance string `json:"balance"` - Nonce string `json:"nonce"` // int64 - } - - err := json.Unmarshal(data, &acc) - if err != nil { - return err - } - - nonce, err := strconv.ParseInt(acc.Nonce, 10, 64) - if err != nil { - return fmt.Errorf("parseNonce: %w", err) - } - - pk, err := base64.StdEncoding.DecodeString(acc.Identifier) - if err != nil { - return fmt.Errorf("parsePublicKey: %w", err) - } - - a.Balance = acc.Balance - a.Nonce = nonce - a.Identifier = pk - return nil -} - -type getAccountResponse struct { - Account account `json:"account"` -} - -type transactionResult txpb.TransactionResult - -func (r *transactionResult) UnmarshalJSON(data []byte) error { - var res struct { - Code uint32 `json:"code"` - Log string `json:"log"` - GasUsed string `json:"gas_used"` // int64 - GasWanted string `json:"gas_wanted"` // int64 - Data []byte `json:"data"` - Events [][]byte `json:"events"` - } - - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - r.Code = res.Code - r.Log = res.Log - r.GasUsed, err = strconv.ParseInt(res.GasUsed, 10, 64) - if err != nil { - return fmt.Errorf("parseGasUsed: %w", err) - } - - r.GasWanted, err = strconv.ParseInt(res.GasWanted, 10, 64) - if err != nil { - return fmt.Errorf("parseGasWanted: %w", err) - } - - r.Data = res.Data - r.Events = res.Events - return nil -} - -type transaction txpb.Transaction - -func (t *transaction) UnmarshalJSON(data []byte) error { - var res struct { - Body struct { - Payload []byte `json:"payload"` - PayloadType string `json:"payload_type"` - Fee string `json:"fee"` - Nonce string `json:"nonce"` - ChainID string `json:"chain_id"` - Description string `json:"description"` - } `json:"body"` - Serialization string `json:"serialization"` - Signature struct { - SignatureBytes []byte `json:"signature_bytes"` - SignatureType string `json:"signature_type"` - } `json:"signature"` - Sender []byte `json:"sender"` - } - - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - t.Body = &txpb.Transaction_Body{ - Payload: res.Body.Payload, - PayloadType: res.Body.PayloadType, - Fee: res.Body.Fee, - ChainId: res.Body.ChainID, - Description: res.Body.Description, - } - t.Body.Nonce, err = strconv.ParseUint(res.Body.Nonce, 10, 64) - if err != nil { - return fmt.Errorf("parseNonce: %w", err) - } - - t.Serialization = res.Serialization - t.Signature = &txpb.Signature{ - SignatureBytes: res.Signature.SignatureBytes, - SignatureType: res.Signature.SignatureType, - } - t.Sender = res.Sender - return nil -} - -type txQueryResponse txpb.TxQueryResponse - -func (r *txQueryResponse) UnmarshalJSON(data []byte) error { - var res struct { - Hash []byte `json:"hash"` - Height string `json:"height"` - Tx transaction `json:"tx"` - TxResult transactionResult `json:"tx_result"` - } - - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - r.Hash = res.Hash - r.Height, err = strconv.ParseInt(res.Height, 10, 64) - if err != nil { - return fmt.Errorf("parseHeight: %w", err) - } - - r.Tx = (*txpb.Transaction)(&res.Tx) - r.TxResult = (*txpb.TransactionResult)(&res.TxResult) - return nil -} - -type validatorJoinsStatusResponse txpb.ValidatorJoinStatusResponse - -func (r *validatorJoinsStatusResponse) UnmarshalJSON(data []byte) error { - var res struct { - ApprovedValidators [][]byte `json:"approved_validators"` - PendingValidators [][]byte `json:"pending_validators"` - Power string `json:"power"` - } - - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - r.ApprovedValidators = res.ApprovedValidators - r.PendingValidators = res.PendingValidators - r.Power, err = strconv.ParseInt(res.Power, 10, 64) - if err != nil { - return fmt.Errorf("parsePower: %w", err) - } - return nil -} - -type validator txpb.Validator - -func (r *validator) UnmarshalJSON(data []byte) error { - var res struct { - PubKey []byte `json:"pubkey"` - Power string `json:"power"` - } - - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - r.Pubkey = res.PubKey - r.Power, err = strconv.ParseInt(res.Power, 10, 64) - if err != nil { - return fmt.Errorf("parsePower: %w", err) - } - return nil -} - -type currentValidatorsResponse struct { - Validators []*validator `json:"validators"` -} - -type chainInfoResponse txpb.ChainInfoResponse - -func (r *chainInfoResponse) UnmarshalJSON(data []byte) error { - var res struct { - ChainID string `json:"chain_id"` - Height string `json:"height"` - Hash string `json:"hash"` - } - err := json.Unmarshal(data, &res) - if err != nil { - return err - } - - r.ChainId = res.ChainID - r.Height, err = strconv.ParseUint(res.Height, 10, 64) - if err != nil { - return fmt.Errorf("parseHeight: %w", err) - } - r.Hash = res.Hash - return nil -} diff --git a/core/rpc/client/user/txsvc.go b/core/rpc/client/user/txsvc.go new file mode 100644 index 000000000..7f8b75345 --- /dev/null +++ b/core/rpc/client/user/txsvc.go @@ -0,0 +1,27 @@ +// package user defines the interface for a user client transport. +// the user client is the main service for end users to interact with a Kwil network. +package user + +import ( + "context" + "math/big" + + "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/core/types" + "github.com/kwilteam/kwil-db/core/types/transactions" +) + +// TxSvcClient is the interface for a txsvc client. +// The txsvc is the main service for end users to interact with a Kwil network. +type TxSvcClient interface { + Broadcast(ctx context.Context, tx *transactions.Transaction) ([]byte, error) + Call(ctx context.Context, msg *transactions.CallMessage, opts ...client.ActionCallOption) ([]map[string]any, error) + ChainInfo(ctx context.Context) (*types.ChainInfo, error) + EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) + GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) + GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) + ListDatabases(ctx context.Context, ownerPubKey []byte) ([]string, error) + Ping(ctx context.Context) (string, error) + Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) + TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) +} diff --git a/core/rpc/conversion/tx.go b/core/rpc/conversion/tx.go index 95079eb64..ffda75745 100644 --- a/core/rpc/conversion/tx.go +++ b/core/rpc/conversion/tx.go @@ -124,10 +124,11 @@ func ConvertFromPBTxQueryResp(resp *txpb.TxQueryResponse) (*transactions.TcTxQue func ConvertFromPBSchema(dataset *txpb.Schema) *transactions.Schema { return &transactions.Schema{ - Owner: dataset.Owner, - Name: dataset.Name, - Tables: convertFromPBTables(dataset.Tables), - Actions: convertFromPBActions(dataset.Actions), + Owner: dataset.Owner, + Name: dataset.Name, + Tables: convertFromPBTables(dataset.Tables), + Actions: convertFromPBActions(dataset.Actions), + Extensions: convertFromPBExtensions(dataset.Extensions), } } @@ -135,9 +136,10 @@ func convertFromPBTables(tables []*txpb.Table) []*transactions.Table { convTables := make([]*transactions.Table, len(tables)) for i, table := range tables { convTables[i] = &transactions.Table{ - Name: table.Name, - Columns: convertFromPBColumns(table.Columns), - Indexes: convertFromPBIndexes(table.Indexes), + Name: table.Name, + Columns: convertFromPBColumns(table.Columns), + Indexes: convertFromPBIndexes(table.Indexes), + ForeignKeys: convertFromPBForeignKeys(table.ForeignKeys), } } @@ -197,3 +199,46 @@ func convertFromPBActions(actions []*txpb.Action) []*transactions.Action { return convActions } + +func convertFromPBForeignKeys(foreignKeys []*txpb.ForeignKey) []*transactions.ForeignKey { + convForeignKeys := make([]*transactions.ForeignKey, len(foreignKeys)) + for i, foreignKey := range foreignKeys { + actions := make([]*transactions.ForeignKeyAction, len(foreignKey.Actions)) + for j, action := range foreignKey.Actions { + actions[j] = &transactions.ForeignKeyAction{ + On: action.On, + Do: action.Do, + } + } + + convForeignKeys[i] = &transactions.ForeignKey{ + ChildKeys: foreignKey.ChildKeys, + ParentKeys: foreignKey.ParentKeys, + ParentTable: foreignKey.ParentTable, + Actions: actions, + } + } + + return convForeignKeys +} + +func convertFromPBExtensions(extensions []*txpb.Extensions) []*transactions.Extension { + convExtensions := make([]*transactions.Extension, len(extensions)) + for i, extension := range extensions { + extensionsConfigs := make([]*transactions.ExtensionConfig, len(extension.Initialization)) + for j, config := range extension.Initialization { + extensionsConfigs[j] = &transactions.ExtensionConfig{ + Argument: config.Argument, + Value: config.Value, + } + } + + convExtensions[i] = &transactions.Extension{ + Name: extension.Name, + Config: extensionsConfigs, + Alias: extension.Alias, + } + } + + return convExtensions +} diff --git a/core/rpc/http/function/.gitignore b/core/rpc/http/function/.gitignore new file mode 100644 index 000000000..daf913b1b --- /dev/null +++ b/core/rpc/http/function/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/core/rpc/http/function/.swagger-codegen-ignore b/core/rpc/http/function/.swagger-codegen-ignore new file mode 100644 index 000000000..c5fa491b4 --- /dev/null +++ b/core/rpc/http/function/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/core/rpc/http/function/.swagger-codegen/VERSION b/core/rpc/http/function/.swagger-codegen/VERSION new file mode 100644 index 000000000..b262b4de7 --- /dev/null +++ b/core/rpc/http/function/.swagger-codegen/VERSION @@ -0,0 +1 @@ +3.0.51 \ No newline at end of file diff --git a/core/rpc/http/function/.travis.yml b/core/rpc/http/function/.travis.yml new file mode 100644 index 000000000..f5cb2ce9a --- /dev/null +++ b/core/rpc/http/function/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/core/rpc/http/function/README.md b/core/rpc/http/function/README.md new file mode 100644 index 000000000..8896f3543 --- /dev/null +++ b/core/rpc/http/function/README.md @@ -0,0 +1,39 @@ +# Go API client for swagger + +No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: version not set +- Package version: 1.0.0 +- Build package: io.swagger.codegen.v3.generators.go.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +```golang +import "./swagger" +``` + +## Documentation for API Endpoints + +All URIs are relative to */* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*FunctionServiceApi* | [**FunctionServiceVerifySignature**](docs/FunctionServiceApi.md#functionserviceverifysignature) | **Post** /api/v1/verify_signature | + +## Documentation For Models + + - [FunctionVerifySignatureRequest](docs/FunctionVerifySignatureRequest.md) + - [FunctionVerifySignatureResponse](docs/FunctionVerifySignatureResponse.md) + - [RpcStatus](docs/RpcStatus.md) + - [TxSignature](docs/TxSignature.md) + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + diff --git a/core/rpc/http/function/api/swagger.yaml b/core/rpc/http/function/api/swagger.yaml new file mode 100644 index 000000000..d323a4d7c --- /dev/null +++ b/core/rpc/http/function/api/swagger.yaml @@ -0,0 +1,89 @@ +openapi: 3.0.1 +info: + title: kwil/function/v0/messages.proto + version: version not set +servers: +- url: / +tags: +- name: FunctionService +paths: + /api/v1/verify_signature: + post: + tags: + - FunctionService + operationId: FunctionService_VerifySignature + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/functionVerifySignatureRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/functionVerifySignatureResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body +components: + schemas: + functionVerifySignatureRequest: + type: object + properties: + signature: + $ref: '#/components/schemas/txSignature' + sender: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + msg: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + functionVerifySignatureResponse: + type: object + properties: + valid: + type: boolean + error: + type: string + example: + valid: true + error: error + protobufAny: + type: object + properties: + '@type': + type: string + additionalProperties: + type: object + x-schema-name: protobufAny + rpcStatus: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + $ref: '#/components/schemas/protobufAny' + txSignature: + type: object + properties: + signature_bytes: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + signature_type: + type: string +x-original-swagger-version: "2.0" diff --git a/core/rpc/http/function/api_function_service.go b/core/rpc/http/function/api_function_service.go new file mode 100644 index 000000000..78076cc8f --- /dev/null +++ b/core/rpc/http/function/api_function_service.go @@ -0,0 +1,120 @@ + +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +// Linger please +var ( + _ context.Context +) + +type FunctionServiceApiService service +/* +FunctionServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return FunctionVerifySignatureResponse +*/ +func (a *FunctionServiceApiService) FunctionServiceVerifySignature(ctx context.Context, body FunctionVerifySignatureRequest) (FunctionVerifySignatureResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue FunctionVerifySignatureResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/verify_signature" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v FunctionVerifySignatureResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} diff --git a/core/rpc/http/function/client.go b/core/rpc/http/function/client.go new file mode 100644 index 000000000..c18416885 --- /dev/null +++ b/core/rpc/http/function/client.go @@ -0,0 +1,473 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the kwil/function/v0/messages.proto API vversion not set +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + + FunctionServiceApi *FunctionServiceApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.FunctionServiceApi = (*FunctionServiceApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { + if body != nil { + return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") + } + body = &bytes.Buffer{} + body.WriteString(formParams.Encode()) + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { + if strings.Contains(contentType, "application/xml") { + if err = xml.Unmarshal(b, v); err != nil { + return err + } + return nil + } else if strings.Contains(contentType, "application/json") { + if err = json.Unmarshal(b, v); err != nil { + return err + } + return nil + } + return errors.New("undefined response type") +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if s, ok := body.(*string); ok { + _, err = bodyBuf.WriteString(*s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} + +// GenericSwaggerError Provides access to the body, error and model on returned errors. +type GenericSwaggerError struct { + body []byte + error string + model interface{} +} + +// Error returns non-empty string if there was an error. +func (e GenericSwaggerError) Error() string { + return e.error +} + +// Body returns the raw bytes of the response +func (e GenericSwaggerError) Body() []byte { + return e.body +} + +// Model returns the unpacked model of the error +func (e GenericSwaggerError) Model() interface{} { + return e.model +} diff --git a/core/rpc/http/function/configuration.go b/core/rpc/http/function/configuration.go new file mode 100644 index 000000000..1a7ca7c7b --- /dev/null +++ b/core/rpc/http/function/configuration.go @@ -0,0 +1,71 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "/", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/core/rpc/http/function/docs/FunctionServiceApi.md b/core/rpc/http/function/docs/FunctionServiceApi.md new file mode 100644 index 000000000..aef35bc9c --- /dev/null +++ b/core/rpc/http/function/docs/FunctionServiceApi.md @@ -0,0 +1,34 @@ +# {{classname}} + +All URIs are relative to */* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**FunctionServiceVerifySignature**](FunctionServiceApi.md#FunctionServiceVerifySignature) | **Post** /api/v1/verify_signature | + +# **FunctionServiceVerifySignature** +> FunctionVerifySignatureResponse FunctionServiceVerifySignature(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**FunctionVerifySignatureRequest**](FunctionVerifySignatureRequest.md)| | + +### Return type + +[**FunctionVerifySignatureResponse**](functionVerifySignatureResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/core/rpc/http/function/docs/FunctionVerifySignatureRequest.md b/core/rpc/http/function/docs/FunctionVerifySignatureRequest.md new file mode 100644 index 000000000..bdce99b5c --- /dev/null +++ b/core/rpc/http/function/docs/FunctionVerifySignatureRequest.md @@ -0,0 +1,11 @@ +# FunctionVerifySignatureRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Signature** | [***TxSignature**](txSignature.md) | | [optional] [default to null] +**Sender** | **string** | | [optional] [default to null] +**Msg** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/function/docs/FunctionVerifySignatureResponse.md b/core/rpc/http/function/docs/FunctionVerifySignatureResponse.md new file mode 100644 index 000000000..7028618b7 --- /dev/null +++ b/core/rpc/http/function/docs/FunctionVerifySignatureResponse.md @@ -0,0 +1,10 @@ +# FunctionVerifySignatureResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Valid** | **bool** | | [optional] [default to null] +**Error_** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/function/docs/RpcStatus.md b/core/rpc/http/function/docs/RpcStatus.md new file mode 100644 index 000000000..174cbd2a2 --- /dev/null +++ b/core/rpc/http/function/docs/RpcStatus.md @@ -0,0 +1,11 @@ +# RpcStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Code** | **int32** | | [optional] [default to null] +**Message** | **string** | | [optional] [default to null] +**Details** | [**[]map[string]interface{}**](map.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/function/docs/TxSignature.md b/core/rpc/http/function/docs/TxSignature.md new file mode 100644 index 000000000..1f64be9e2 --- /dev/null +++ b/core/rpc/http/function/docs/TxSignature.md @@ -0,0 +1,10 @@ +# TxSignature + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**SignatureBytes** | **string** | | [optional] [default to null] +**SignatureType** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/function/git_push.sh b/core/rpc/http/function/git_push.sh new file mode 100644 index 000000000..ae01b182a --- /dev/null +++ b/core/rpc/http/function/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/core/rpc/http/function/model_function_verify_signature_request.go b/core/rpc/http/function/model_function_verify_signature_request.go new file mode 100644 index 000000000..fe77101c5 --- /dev/null +++ b/core/rpc/http/function/model_function_verify_signature_request.go @@ -0,0 +1,15 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type FunctionVerifySignatureRequest struct { + Signature *TxSignature `json:"signature,omitempty"` + Sender string `json:"sender,omitempty"` + Msg string `json:"msg,omitempty"` +} diff --git a/core/rpc/http/function/model_function_verify_signature_response.go b/core/rpc/http/function/model_function_verify_signature_response.go new file mode 100644 index 000000000..2bdfb3a77 --- /dev/null +++ b/core/rpc/http/function/model_function_verify_signature_response.go @@ -0,0 +1,14 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type FunctionVerifySignatureResponse struct { + Valid bool `json:"valid,omitempty"` + Error_ string `json:"error,omitempty"` +} diff --git a/core/rpc/http/function/model_rpc_status.go b/core/rpc/http/function/model_rpc_status.go new file mode 100644 index 000000000..cd9062329 --- /dev/null +++ b/core/rpc/http/function/model_rpc_status.go @@ -0,0 +1,15 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type RpcStatus struct { + Code int32 `json:"code,omitempty"` + Message string `json:"message,omitempty"` + Details []map[string]interface{} `json:"details,omitempty"` +} diff --git a/core/rpc/http/function/model_tx_signature.go b/core/rpc/http/function/model_tx_signature.go new file mode 100644 index 000000000..c8263e6ca --- /dev/null +++ b/core/rpc/http/function/model_tx_signature.go @@ -0,0 +1,14 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxSignature struct { + SignatureBytes string `json:"signature_bytes,omitempty"` + SignatureType string `json:"signature_type,omitempty"` +} diff --git a/core/rpc/http/function/response.go b/core/rpc/http/function/response.go new file mode 100644 index 000000000..587c3eafc --- /dev/null +++ b/core/rpc/http/function/response.go @@ -0,0 +1,42 @@ +/* + * kwil/function/v0/messages.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/core/rpc/http/tx/.gitignore b/core/rpc/http/tx/.gitignore new file mode 100644 index 000000000..daf913b1b --- /dev/null +++ b/core/rpc/http/tx/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/core/rpc/http/tx/.swagger-codegen-ignore b/core/rpc/http/tx/.swagger-codegen-ignore new file mode 100644 index 000000000..c5fa491b4 --- /dev/null +++ b/core/rpc/http/tx/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/core/rpc/http/tx/.swagger-codegen/VERSION b/core/rpc/http/tx/.swagger-codegen/VERSION new file mode 100644 index 000000000..b262b4de7 --- /dev/null +++ b/core/rpc/http/tx/.swagger-codegen/VERSION @@ -0,0 +1 @@ +3.0.51 \ No newline at end of file diff --git a/core/rpc/http/tx/.travis.yml b/core/rpc/http/tx/.travis.yml new file mode 100644 index 000000000..f5cb2ce9a --- /dev/null +++ b/core/rpc/http/tx/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/core/rpc/http/tx/README.md b/core/rpc/http/tx/README.md new file mode 100644 index 000000000..f2bf96edd --- /dev/null +++ b/core/rpc/http/tx/README.md @@ -0,0 +1,79 @@ +# Go API client for swagger + +No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: version not set +- Package version: 1.0.0 +- Build package: io.swagger.codegen.v3.generators.go.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +```golang +import "./swagger" +``` + +## Documentation for API Endpoints + +All URIs are relative to */* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*TxServiceApi* | [**TxServiceBroadcast**](docs/TxServiceApi.md#txservicebroadcast) | **Post** /api/v1/broadcast | +*TxServiceApi* | [**TxServiceCall**](docs/TxServiceApi.md#txservicecall) | **Post** /api/v1/call | +*TxServiceApi* | [**TxServiceChainInfo**](docs/TxServiceApi.md#txservicechaininfo) | **Get** /api/v1/chain_info | +*TxServiceApi* | [**TxServiceEstimatePrice**](docs/TxServiceApi.md#txserviceestimateprice) | **Post** /api/v1/estimate_price | +*TxServiceApi* | [**TxServiceGetAccount**](docs/TxServiceApi.md#txservicegetaccount) | **Get** /api/v1/accounts/{identifier} | +*TxServiceApi* | [**TxServiceGetConfig**](docs/TxServiceApi.md#txservicegetconfig) | **Get** /api/v1/config | +*TxServiceApi* | [**TxServiceGetSchema**](docs/TxServiceApi.md#txservicegetschema) | **Get** /api/v1/databases/{dbid}/schema | +*TxServiceApi* | [**TxServiceListDatabases**](docs/TxServiceApi.md#txservicelistdatabases) | **Get** /api/v1/{owner}/databases | +*TxServiceApi* | [**TxServicePing**](docs/TxServiceApi.md#txserviceping) | **Get** /api/v1/ping | +*TxServiceApi* | [**TxServiceQuery**](docs/TxServiceApi.md#txservicequery) | **Post** /api/v1/query | +*TxServiceApi* | [**TxServiceTxQuery**](docs/TxServiceApi.md#txservicetxquery) | **Post** /api/v1/tx_query | + +## Documentation For Models + + - [ExtensionsExtensionConfig](docs/ExtensionsExtensionConfig.md) + - [RpcStatus](docs/RpcStatus.md) + - [TxAccount](docs/TxAccount.md) + - [TxAccountStatus](docs/TxAccountStatus.md) + - [TxAction](docs/TxAction.md) + - [TxAttribute](docs/TxAttribute.md) + - [TxBroadcastRequest](docs/TxBroadcastRequest.md) + - [TxBroadcastResponse](docs/TxBroadcastResponse.md) + - [TxCallRequest](docs/TxCallRequest.md) + - [TxCallRequestBody](docs/TxCallRequestBody.md) + - [TxCallResponse](docs/TxCallResponse.md) + - [TxChainInfoResponse](docs/TxChainInfoResponse.md) + - [TxColumn](docs/TxColumn.md) + - [TxEstimatePriceRequest](docs/TxEstimatePriceRequest.md) + - [TxEstimatePriceResponse](docs/TxEstimatePriceResponse.md) + - [TxExtensions](docs/TxExtensions.md) + - [TxForeignKey](docs/TxForeignKey.md) + - [TxForeignKeyAction](docs/TxForeignKeyAction.md) + - [TxGetAccountResponse](docs/TxGetAccountResponse.md) + - [TxGetConfigResponse](docs/TxGetConfigResponse.md) + - [TxGetSchemaResponse](docs/TxGetSchemaResponse.md) + - [TxIndex](docs/TxIndex.md) + - [TxListDatabasesResponse](docs/TxListDatabasesResponse.md) + - [TxPingResponse](docs/TxPingResponse.md) + - [TxQueryRequest](docs/TxQueryRequest.md) + - [TxQueryResponse](docs/TxQueryResponse.md) + - [TxSchema](docs/TxSchema.md) + - [TxSignature](docs/TxSignature.md) + - [TxTable](docs/TxTable.md) + - [TxTransaction](docs/TxTransaction.md) + - [TxTransactionBody](docs/TxTransactionBody.md) + - [TxTransactionResult](docs/TxTransactionResult.md) + - [TxTxQueryRequest](docs/TxTxQueryRequest.md) + - [TxTxQueryResponse](docs/TxTxQueryResponse.md) + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + diff --git a/core/rpc/http/tx/api/swagger.yaml b/core/rpc/http/tx/api/swagger.yaml new file mode 100644 index 000000000..90da7bd24 --- /dev/null +++ b/core/rpc/http/tx/api/swagger.yaml @@ -0,0 +1,1165 @@ +openapi: 3.0.1 +info: + title: kwil/tx/v1/account.proto + version: version not set +servers: +- url: / +tags: +- name: TxService +paths: + /api/v1/accounts/{identifier}: + get: + tags: + - TxService + operationId: TxService_GetAccount + parameters: + - name: identifier + in: path + required: true + style: simple + explode: false + schema: + type: string + format: byte + - name: status + in: query + description: Mapped to URL query parameter `status`. + required: false + style: form + explode: true + schema: + type: string + default: latest + enum: + - latest + - pending + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txGetAccountResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + /api/v1/broadcast: + post: + tags: + - TxService + operationId: TxService_Broadcast + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/txBroadcastRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txBroadcastResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body + /api/v1/call: + post: + tags: + - TxService + operationId: TxService_Call + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/txCallRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txCallResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body + /api/v1/chain_info: + get: + tags: + - TxService + operationId: TxService_ChainInfo + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txChainInfoResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + /api/v1/config: + get: + tags: + - TxService + operationId: TxService_GetConfig + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txGetConfigResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + /api/v1/databases/{dbid}/schema: + get: + tags: + - TxService + operationId: TxService_GetSchema + parameters: + - name: dbid + in: path + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txGetSchemaResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + /api/v1/estimate_price: + post: + tags: + - TxService + operationId: TxService_EstimatePrice + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/txEstimatePriceRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txEstimatePriceResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body + /api/v1/ping: + get: + tags: + - TxService + operationId: TxService_Ping + parameters: + - name: message + in: query + required: false + style: form + explode: true + schema: + type: string + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txPingResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + /api/v1/query: + post: + tags: + - TxService + operationId: TxService_Query + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/txQueryRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txQueryResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body + /api/v1/tx_query: + post: + tags: + - TxService + operationId: TxService_TxQuery + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/txTxQueryRequest' + required: true + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txTxQueryResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' + x-codegen-request-body-name: body + /api/v1/{owner}/databases: + get: + tags: + - TxService + operationId: TxService_ListDatabases + parameters: + - name: owner + in: path + required: true + style: simple + explode: false + schema: + type: string + format: byte + responses: + "200": + description: A successful response. + content: + application/json: + schema: + $ref: '#/components/schemas/txListDatabasesResponse' + default: + description: An unexpected error response. + content: + application/json: + schema: + $ref: '#/components/schemas/rpcStatus' +components: + schemas: + ExtensionsExtensionConfig: + type: object + properties: + argument: + type: string + value: + type: string + example: + argument: argument + value: value + protobufAny: + type: object + properties: + '@type': + type: string + additionalProperties: + type: object + x-schema-name: protobufAny + rpcStatus: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + $ref: '#/components/schemas/protobufAny' + txAccount: + type: object + properties: + identifier: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + balance: + type: string + nonce: + type: string + format: int64 + example: + identifier: "" + balance: balance + nonce: nonce + txAccountStatus: + type: string + default: latest + enum: + - latest + - pending + txAction: + type: object + properties: + name: + type: string + public: + type: boolean + inputs: + type: array + items: + type: string + statements: + type: array + items: + type: string + mutability: + type: string + auxiliaries: + type: array + items: + type: string + annotations: + type: array + items: + type: string + example: + public: true + inputs: + - inputs + - inputs + auxiliaries: + - auxiliaries + - auxiliaries + name: name + annotations: + - annotations + - annotations + statements: + - statements + - statements + mutability: mutability + txAttribute: + type: object + properties: + type: + type: string + value: + type: string + example: + type: type + value: value + txBroadcastRequest: + type: object + properties: + tx: + $ref: '#/components/schemas/txTransaction' + txBroadcastResponse: + type: object + properties: + tx_hash: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + example: + tx_hash: "" + txCallRequest: + type: object + properties: + body: + $ref: '#/components/schemas/txCallRequestBody' + auth_type: + type: string + description: |- + auth_type is the type of authenticator that will be used to derive + identifier from the sender. + sender: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + txCallRequestBody: + type: object + properties: + payload: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + txCallResponse: + type: object + properties: + result: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + example: + result: "" + txChainInfoResponse: + type: object + properties: + chain_id: + type: string + height: + type: string + format: uint64 + hash: + type: string + example: + chain_id: chain_id + hash: hash + height: height + txColumn: + type: object + properties: + name: + type: string + type: + type: string + attributes: + type: array + items: + $ref: '#/components/schemas/txAttribute' + example: + name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + txEstimatePriceRequest: + type: object + properties: + tx: + $ref: '#/components/schemas/txTransaction' + txEstimatePriceResponse: + type: object + properties: + price: + type: string + example: + price: price + txExtensions: + type: object + properties: + name: + type: string + initialization: + type: array + items: + $ref: '#/components/schemas/ExtensionsExtensionConfig' + alias: + type: string + example: + name: name + initialization: + - argument: argument + value: value + - argument: argument + value: value + alias: alias + txForeignKey: + type: object + properties: + child_keys: + type: array + items: + type: string + parent_keys: + type: array + items: + type: string + parent_table: + type: string + actions: + type: array + items: + $ref: '#/components/schemas/txForeignKeyAction' + example: + child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + txForeignKeyAction: + type: object + properties: + "on": + type: string + do: + type: string + example: + do: do + "on": "on" + txGetAccountResponse: + type: object + properties: + account: + $ref: '#/components/schemas/txAccount' + example: + account: + identifier: "" + balance: balance + nonce: nonce + txGetConfigResponse: + type: object + properties: + chain_code: + type: string + format: int64 + provider_address: + type: string + pool_address: + type: string + example: + provider_address: provider_address + chain_code: chain_code + pool_address: pool_address + txGetSchemaResponse: + type: object + properties: + schema: + $ref: '#/components/schemas/txSchema' + example: + schema: + owner: "" + tables: + - indexes: + - columns: + - columns + - columns + name: name + type: type + - columns: + - columns + - columns + name: name + type: type + columns: + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + name: name + foreign_keys: + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - indexes: + - columns: + - columns + - columns + name: name + type: type + - columns: + - columns + - columns + name: name + type: type + columns: + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + name: name + foreign_keys: + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + extensions: + - name: name + initialization: + - argument: argument + value: value + - argument: argument + value: value + alias: alias + - name: name + initialization: + - argument: argument + value: value + - argument: argument + value: value + alias: alias + name: name + actions: + - public: true + inputs: + - inputs + - inputs + auxiliaries: + - auxiliaries + - auxiliaries + name: name + annotations: + - annotations + - annotations + statements: + - statements + - statements + mutability: mutability + - public: true + inputs: + - inputs + - inputs + auxiliaries: + - auxiliaries + - auxiliaries + name: name + annotations: + - annotations + - annotations + statements: + - statements + - statements + mutability: mutability + txIndex: + type: object + properties: + name: + type: string + columns: + type: array + items: + type: string + type: + type: string + example: + columns: + - columns + - columns + name: name + type: type + txListDatabasesResponse: + type: object + properties: + databases: + type: array + items: + type: string + example: + databases: + - databases + - databases + txPingResponse: + type: object + properties: + message: + type: string + example: + message: message + txQueryRequest: + type: object + properties: + dbid: + type: string + query: + type: string + txQueryResponse: + type: object + properties: + result: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + example: + result: "" + txSchema: + type: object + properties: + owner: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + name: + type: string + tables: + type: array + items: + $ref: '#/components/schemas/txTable' + actions: + type: array + items: + $ref: '#/components/schemas/txAction' + extensions: + type: array + items: + $ref: '#/components/schemas/txExtensions' + example: + owner: "" + tables: + - indexes: + - columns: + - columns + - columns + name: name + type: type + - columns: + - columns + - columns + name: name + type: type + columns: + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + name: name + foreign_keys: + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - indexes: + - columns: + - columns + - columns + name: name + type: type + - columns: + - columns + - columns + name: name + type: type + columns: + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + name: name + foreign_keys: + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + extensions: + - name: name + initialization: + - argument: argument + value: value + - argument: argument + value: value + alias: alias + - name: name + initialization: + - argument: argument + value: value + - argument: argument + value: value + alias: alias + name: name + actions: + - public: true + inputs: + - inputs + - inputs + auxiliaries: + - auxiliaries + - auxiliaries + name: name + annotations: + - annotations + - annotations + statements: + - statements + - statements + mutability: mutability + - public: true + inputs: + - inputs + - inputs + auxiliaries: + - auxiliaries + - auxiliaries + name: name + annotations: + - annotations + - annotations + statements: + - statements + - statements + mutability: mutability + txSignature: + type: object + properties: + signature_bytes: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + signature_type: + type: string + example: + signature_bytes: "" + signature_type: signature_type + txTable: + type: object + properties: + name: + type: string + columns: + type: array + items: + $ref: '#/components/schemas/txColumn' + indexes: + type: array + items: + $ref: '#/components/schemas/txIndex' + foreign_keys: + type: array + items: + $ref: '#/components/schemas/txForeignKey' + example: + indexes: + - columns: + - columns + - columns + name: name + type: type + - columns: + - columns + - columns + name: name + type: type + columns: + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + - name: name + attributes: + - type: type + value: value + - type: type + value: value + type: type + name: name + foreign_keys: + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + - child_keys: + - child_keys + - child_keys + parent_keys: + - parent_keys + - parent_keys + parent_table: parent_table + actions: + - do: do + "on": "on" + - do: do + "on": "on" + txTransaction: + type: object + properties: + body: + $ref: '#/components/schemas/txTransactionBody' + signature: + $ref: '#/components/schemas/txSignature' + sender: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + serialization: + type: string + example: + serialization: serialization + signature: + signature_bytes: "" + signature_type: signature_type + sender: "" + body: + payload_type: payload_type + chain_id: chain_id + payload: "" + fee: fee + description: description + nonce: nonce + txTransactionBody: + type: object + properties: + payload: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + payload_type: + type: string + fee: + type: string + nonce: + type: string + format: uint64 + chain_id: + type: string + description: + type: string + example: + payload_type: payload_type + chain_id: chain_id + payload: "" + fee: fee + description: description + nonce: nonce + txTransactionResult: + type: object + properties: + code: + type: integer + format: int64 + log: + type: string + gas_used: + type: string + format: int64 + gas_wanted: + type: string + format: int64 + data: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + description: Data contains the output of the transaction. + format: byte + events: + type: array + items: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + example: + code: 0 + data: "" + log: log + gas_used: gas_used + gas_wanted: gas_wanted + events: + - "" + - "" + txTxQueryRequest: + type: object + properties: + tx_hash: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + txTxQueryResponse: + type: object + properties: + hash: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + height: + type: string + format: int64 + tx: + $ref: '#/components/schemas/txTransaction' + tx_result: + $ref: '#/components/schemas/txTransactionResult' + example: + tx: + serialization: serialization + signature: + signature_bytes: "" + signature_type: signature_type + sender: "" + body: + payload_type: payload_type + chain_id: chain_id + payload: "" + fee: fee + description: description + nonce: nonce + tx_result: + code: 0 + data: "" + log: log + gas_used: gas_used + gas_wanted: gas_wanted + events: + - "" + - "" + hash: "" + height: height +x-original-swagger-version: "2.0" diff --git a/core/rpc/http/tx/api_tx_service.go b/core/rpc/http/tx/api_tx_service.go new file mode 100644 index 000000000..36514f560 --- /dev/null +++ b/core/rpc/http/tx/api_tx_service.go @@ -0,0 +1,1080 @@ + +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + "strings" + "fmt" + "github.com/antihax/optional" +) + +// Linger please +var ( + _ context.Context +) + +type TxServiceApiService service +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return TxBroadcastResponse +*/ +func (a *TxServiceApiService) TxServiceBroadcast(ctx context.Context, body TxBroadcastRequest) (TxBroadcastResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxBroadcastResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/broadcast" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxBroadcastResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return TxCallResponse +*/ +func (a *TxServiceApiService) TxServiceCall(ctx context.Context, body TxCallRequest) (TxCallResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxCallResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/call" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxCallResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). +@return TxChainInfoResponse +*/ +func (a *TxServiceApiService) TxServiceChainInfo(ctx context.Context) (TxChainInfoResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxChainInfoResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/chain_info" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxChainInfoResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return TxEstimatePriceResponse +*/ +func (a *TxServiceApiService) TxServiceEstimatePrice(ctx context.Context, body TxEstimatePriceRequest) (TxEstimatePriceResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxEstimatePriceResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/estimate_price" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxEstimatePriceResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param identifier + * @param optional nil or *TxServiceApiTxServiceGetAccountOpts - Optional Parameters: + * @param "Status" (optional.String) - Mapped to URL query parameter `status`. +@return TxGetAccountResponse +*/ + +type TxServiceApiTxServiceGetAccountOpts struct { + Status optional.String +} + +func (a *TxServiceApiService) TxServiceGetAccount(ctx context.Context, identifier string, localVarOptionals *TxServiceApiTxServiceGetAccountOpts) (TxGetAccountResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxGetAccountResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/accounts/{identifier}" + localVarPath = strings.Replace(localVarPath, "{"+"identifier"+"}", fmt.Sprintf("%v", identifier), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Status.IsSet() { + localVarQueryParams.Add("status", parameterToString(localVarOptionals.Status.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxGetAccountResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). +@return TxGetConfigResponse +*/ +func (a *TxServiceApiService) TxServiceGetConfig(ctx context.Context) (TxGetConfigResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxGetConfigResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/config" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxGetConfigResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param dbid +@return TxGetSchemaResponse +*/ +func (a *TxServiceApiService) TxServiceGetSchema(ctx context.Context, dbid string) (TxGetSchemaResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxGetSchemaResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/databases/{dbid}/schema" + localVarPath = strings.Replace(localVarPath, "{"+"dbid"+"}", fmt.Sprintf("%v", dbid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxGetSchemaResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param owner +@return TxListDatabasesResponse +*/ +func (a *TxServiceApiService) TxServiceListDatabases(ctx context.Context, owner string) (TxListDatabasesResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxListDatabasesResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/{owner}/databases" + localVarPath = strings.Replace(localVarPath, "{"+"owner"+"}", fmt.Sprintf("%v", owner), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxListDatabasesResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *TxServiceApiTxServicePingOpts - Optional Parameters: + * @param "Message" (optional.String) - +@return TxPingResponse +*/ + +type TxServiceApiTxServicePingOpts struct { + Message optional.String +} + +func (a *TxServiceApiService) TxServicePing(ctx context.Context, localVarOptionals *TxServiceApiTxServicePingOpts) (TxPingResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxPingResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/ping" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Message.IsSet() { + localVarQueryParams.Add("message", parameterToString(localVarOptionals.Message.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxPingResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return TxQueryResponse +*/ +func (a *TxServiceApiService) TxServiceQuery(ctx context.Context, body TxQueryRequest) (TxQueryResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxQueryResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/query" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxQueryResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} +/* +TxServiceApiService + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param body +@return TxTxQueryResponse +*/ +func (a *TxServiceApiService) TxServiceTxQuery(ctx context.Context, body TxTxQueryRequest) (TxTxQueryResponse, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TxTxQueryResponse + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/api/v1/tx_query" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TxTxQueryResponse + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 0 { + var v RpcStatus + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} diff --git a/core/rpc/http/tx/client.go b/core/rpc/http/tx/client.go new file mode 100644 index 000000000..93cfcdbe7 --- /dev/null +++ b/core/rpc/http/tx/client.go @@ -0,0 +1,473 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the kwil/tx/v1/account.proto API vversion not set +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + + TxServiceApi *TxServiceApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.TxServiceApi = (*TxServiceApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { + if body != nil { + return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") + } + body = &bytes.Buffer{} + body.WriteString(formParams.Encode()) + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { + if strings.Contains(contentType, "application/xml") { + if err = xml.Unmarshal(b, v); err != nil { + return err + } + return nil + } else if strings.Contains(contentType, "application/json") { + if err = json.Unmarshal(b, v); err != nil { + return err + } + return nil + } + return errors.New("undefined response type") +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if s, ok := body.(*string); ok { + _, err = bodyBuf.WriteString(*s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} + +// GenericSwaggerError Provides access to the body, error and model on returned errors. +type GenericSwaggerError struct { + body []byte + error string + model interface{} +} + +// Error returns non-empty string if there was an error. +func (e GenericSwaggerError) Error() string { + return e.error +} + +// Body returns the raw bytes of the response +func (e GenericSwaggerError) Body() []byte { + return e.body +} + +// Model returns the unpacked model of the error +func (e GenericSwaggerError) Model() interface{} { + return e.model +} diff --git a/core/rpc/http/tx/configuration.go b/core/rpc/http/tx/configuration.go new file mode 100644 index 000000000..24be88ace --- /dev/null +++ b/core/rpc/http/tx/configuration.go @@ -0,0 +1,71 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "/", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/core/rpc/http/tx/docs/ExtensionsExtensionConfig.md b/core/rpc/http/tx/docs/ExtensionsExtensionConfig.md new file mode 100644 index 000000000..7f4da5bae --- /dev/null +++ b/core/rpc/http/tx/docs/ExtensionsExtensionConfig.md @@ -0,0 +1,10 @@ +# ExtensionsExtensionConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Argument** | **string** | | [optional] [default to null] +**Value** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/RpcStatus.md b/core/rpc/http/tx/docs/RpcStatus.md new file mode 100644 index 000000000..174cbd2a2 --- /dev/null +++ b/core/rpc/http/tx/docs/RpcStatus.md @@ -0,0 +1,11 @@ +# RpcStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Code** | **int32** | | [optional] [default to null] +**Message** | **string** | | [optional] [default to null] +**Details** | [**[]map[string]interface{}**](map.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxAccount.md b/core/rpc/http/tx/docs/TxAccount.md new file mode 100644 index 000000000..c229a3d7c --- /dev/null +++ b/core/rpc/http/tx/docs/TxAccount.md @@ -0,0 +1,11 @@ +# TxAccount + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Identifier** | **string** | | [optional] [default to null] +**Balance** | **string** | | [optional] [default to null] +**Nonce** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxAccountStatus.md b/core/rpc/http/tx/docs/TxAccountStatus.md new file mode 100644 index 000000000..b1105ec7b --- /dev/null +++ b/core/rpc/http/tx/docs/TxAccountStatus.md @@ -0,0 +1,8 @@ +# TxAccountStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxAction.md b/core/rpc/http/tx/docs/TxAction.md new file mode 100644 index 000000000..64bb99164 --- /dev/null +++ b/core/rpc/http/tx/docs/TxAction.md @@ -0,0 +1,15 @@ +# TxAction + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Public** | **bool** | | [optional] [default to null] +**Inputs** | **[]string** | | [optional] [default to null] +**Statements** | **[]string** | | [optional] [default to null] +**Mutability** | **string** | | [optional] [default to null] +**Auxiliaries** | **[]string** | | [optional] [default to null] +**Annotations** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxAttribute.md b/core/rpc/http/tx/docs/TxAttribute.md new file mode 100644 index 000000000..bad32bdd0 --- /dev/null +++ b/core/rpc/http/tx/docs/TxAttribute.md @@ -0,0 +1,10 @@ +# TxAttribute + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Type_** | **string** | | [optional] [default to null] +**Value** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxBroadcastRequest.md b/core/rpc/http/tx/docs/TxBroadcastRequest.md new file mode 100644 index 000000000..3eca4423f --- /dev/null +++ b/core/rpc/http/tx/docs/TxBroadcastRequest.md @@ -0,0 +1,9 @@ +# TxBroadcastRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Tx** | [***TxTransaction**](txTransaction.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxBroadcastResponse.md b/core/rpc/http/tx/docs/TxBroadcastResponse.md new file mode 100644 index 000000000..098db6b84 --- /dev/null +++ b/core/rpc/http/tx/docs/TxBroadcastResponse.md @@ -0,0 +1,9 @@ +# TxBroadcastResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TxHash** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxCallRequest.md b/core/rpc/http/tx/docs/TxCallRequest.md new file mode 100644 index 000000000..0f6b9d9ea --- /dev/null +++ b/core/rpc/http/tx/docs/TxCallRequest.md @@ -0,0 +1,11 @@ +# TxCallRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Body** | [***TxCallRequestBody**](txCallRequestBody.md) | | [optional] [default to null] +**AuthType** | **string** | auth_type is the type of authenticator that will be used to derive identifier from the sender. | [optional] [default to null] +**Sender** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxCallRequestBody.md b/core/rpc/http/tx/docs/TxCallRequestBody.md new file mode 100644 index 000000000..9a64ed4da --- /dev/null +++ b/core/rpc/http/tx/docs/TxCallRequestBody.md @@ -0,0 +1,9 @@ +# TxCallRequestBody + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Payload** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxCallResponse.md b/core/rpc/http/tx/docs/TxCallResponse.md new file mode 100644 index 000000000..14bee56d3 --- /dev/null +++ b/core/rpc/http/tx/docs/TxCallResponse.md @@ -0,0 +1,9 @@ +# TxCallResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Result** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxChainInfoResponse.md b/core/rpc/http/tx/docs/TxChainInfoResponse.md new file mode 100644 index 000000000..38b4901d8 --- /dev/null +++ b/core/rpc/http/tx/docs/TxChainInfoResponse.md @@ -0,0 +1,11 @@ +# TxChainInfoResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ChainId** | **string** | | [optional] [default to null] +**Height** | **string** | | [optional] [default to null] +**Hash** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxColumn.md b/core/rpc/http/tx/docs/TxColumn.md new file mode 100644 index 000000000..2d2bd428e --- /dev/null +++ b/core/rpc/http/tx/docs/TxColumn.md @@ -0,0 +1,11 @@ +# TxColumn + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Type_** | **string** | | [optional] [default to null] +**Attributes** | [**[]TxAttribute**](txAttribute.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxEstimatePriceRequest.md b/core/rpc/http/tx/docs/TxEstimatePriceRequest.md new file mode 100644 index 000000000..51bc3763b --- /dev/null +++ b/core/rpc/http/tx/docs/TxEstimatePriceRequest.md @@ -0,0 +1,9 @@ +# TxEstimatePriceRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Tx** | [***TxTransaction**](txTransaction.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxEstimatePriceResponse.md b/core/rpc/http/tx/docs/TxEstimatePriceResponse.md new file mode 100644 index 000000000..dc8094479 --- /dev/null +++ b/core/rpc/http/tx/docs/TxEstimatePriceResponse.md @@ -0,0 +1,9 @@ +# TxEstimatePriceResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Price** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxExtensions.md b/core/rpc/http/tx/docs/TxExtensions.md new file mode 100644 index 000000000..fdf9623eb --- /dev/null +++ b/core/rpc/http/tx/docs/TxExtensions.md @@ -0,0 +1,11 @@ +# TxExtensions + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Initialization** | [**[]ExtensionsExtensionConfig**](ExtensionsExtensionConfig.md) | | [optional] [default to null] +**Alias** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxForeignKey.md b/core/rpc/http/tx/docs/TxForeignKey.md new file mode 100644 index 000000000..61426157a --- /dev/null +++ b/core/rpc/http/tx/docs/TxForeignKey.md @@ -0,0 +1,12 @@ +# TxForeignKey + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ChildKeys** | **[]string** | | [optional] [default to null] +**ParentKeys** | **[]string** | | [optional] [default to null] +**ParentTable** | **string** | | [optional] [default to null] +**Actions** | [**[]TxForeignKeyAction**](txForeignKeyAction.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxForeignKeyAction.md b/core/rpc/http/tx/docs/TxForeignKeyAction.md new file mode 100644 index 000000000..c1c6e00be --- /dev/null +++ b/core/rpc/http/tx/docs/TxForeignKeyAction.md @@ -0,0 +1,10 @@ +# TxForeignKeyAction + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**On** | **string** | | [optional] [default to null] +**Do** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxGetAccountResponse.md b/core/rpc/http/tx/docs/TxGetAccountResponse.md new file mode 100644 index 000000000..273887b0d --- /dev/null +++ b/core/rpc/http/tx/docs/TxGetAccountResponse.md @@ -0,0 +1,9 @@ +# TxGetAccountResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Account** | [***TxAccount**](txAccount.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxGetConfigResponse.md b/core/rpc/http/tx/docs/TxGetConfigResponse.md new file mode 100644 index 000000000..7dd5abdf5 --- /dev/null +++ b/core/rpc/http/tx/docs/TxGetConfigResponse.md @@ -0,0 +1,11 @@ +# TxGetConfigResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ChainCode** | **string** | | [optional] [default to null] +**ProviderAddress** | **string** | | [optional] [default to null] +**PoolAddress** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxGetSchemaResponse.md b/core/rpc/http/tx/docs/TxGetSchemaResponse.md new file mode 100644 index 000000000..b167c468f --- /dev/null +++ b/core/rpc/http/tx/docs/TxGetSchemaResponse.md @@ -0,0 +1,9 @@ +# TxGetSchemaResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Schema** | [***TxSchema**](txSchema.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxIndex.md b/core/rpc/http/tx/docs/TxIndex.md new file mode 100644 index 000000000..924fa891a --- /dev/null +++ b/core/rpc/http/tx/docs/TxIndex.md @@ -0,0 +1,11 @@ +# TxIndex + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Columns** | **[]string** | | [optional] [default to null] +**Type_** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxListDatabasesResponse.md b/core/rpc/http/tx/docs/TxListDatabasesResponse.md new file mode 100644 index 000000000..db3a47b75 --- /dev/null +++ b/core/rpc/http/tx/docs/TxListDatabasesResponse.md @@ -0,0 +1,9 @@ +# TxListDatabasesResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Databases** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxNodeInfoResponse.md b/core/rpc/http/tx/docs/TxNodeInfoResponse.md new file mode 100644 index 000000000..f2aacfa92 --- /dev/null +++ b/core/rpc/http/tx/docs/TxNodeInfoResponse.md @@ -0,0 +1,11 @@ +# TxNodeInfoResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**NodeId** | **string** | | [optional] [default to null] +**PublicKey** | **string** | | [optional] [default to null] +**P2pAddress** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxPingResponse.md b/core/rpc/http/tx/docs/TxPingResponse.md new file mode 100644 index 000000000..0a7c9b1cf --- /dev/null +++ b/core/rpc/http/tx/docs/TxPingResponse.md @@ -0,0 +1,9 @@ +# TxPingResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Message** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxQueryRequest.md b/core/rpc/http/tx/docs/TxQueryRequest.md new file mode 100644 index 000000000..7ddd482eb --- /dev/null +++ b/core/rpc/http/tx/docs/TxQueryRequest.md @@ -0,0 +1,10 @@ +# TxQueryRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Dbid** | **string** | | [optional] [default to null] +**Query** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxQueryResponse.md b/core/rpc/http/tx/docs/TxQueryResponse.md new file mode 100644 index 000000000..0a4fd76d8 --- /dev/null +++ b/core/rpc/http/tx/docs/TxQueryResponse.md @@ -0,0 +1,9 @@ +# TxQueryResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Result** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxSchema.md b/core/rpc/http/tx/docs/TxSchema.md new file mode 100644 index 000000000..59855052c --- /dev/null +++ b/core/rpc/http/tx/docs/TxSchema.md @@ -0,0 +1,13 @@ +# TxSchema + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Owner** | **string** | | [optional] [default to null] +**Name** | **string** | | [optional] [default to null] +**Tables** | [**[]TxTable**](txTable.md) | | [optional] [default to null] +**Actions** | [**[]TxAction**](txAction.md) | | [optional] [default to null] +**Extensions** | [**[]TxExtensions**](txExtensions.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxServiceApi.md b/core/rpc/http/tx/docs/TxServiceApi.md new file mode 100644 index 000000000..0f934530a --- /dev/null +++ b/core/rpc/http/tx/docs/TxServiceApi.md @@ -0,0 +1,310 @@ +# {{classname}} + +All URIs are relative to */* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**TxServiceBroadcast**](TxServiceApi.md#TxServiceBroadcast) | **Post** /api/v1/broadcast | +[**TxServiceCall**](TxServiceApi.md#TxServiceCall) | **Post** /api/v1/call | +[**TxServiceChainInfo**](TxServiceApi.md#TxServiceChainInfo) | **Get** /api/v1/chain_info | +[**TxServiceEstimatePrice**](TxServiceApi.md#TxServiceEstimatePrice) | **Post** /api/v1/estimate_price | +[**TxServiceGetAccount**](TxServiceApi.md#TxServiceGetAccount) | **Get** /api/v1/accounts/{identifier} | +[**TxServiceGetConfig**](TxServiceApi.md#TxServiceGetConfig) | **Get** /api/v1/config | +[**TxServiceGetSchema**](TxServiceApi.md#TxServiceGetSchema) | **Get** /api/v1/databases/{dbid}/schema | +[**TxServiceListDatabases**](TxServiceApi.md#TxServiceListDatabases) | **Get** /api/v1/{owner}/databases | +[**TxServicePing**](TxServiceApi.md#TxServicePing) | **Get** /api/v1/ping | +[**TxServiceQuery**](TxServiceApi.md#TxServiceQuery) | **Post** /api/v1/query | +[**TxServiceTxQuery**](TxServiceApi.md#TxServiceTxQuery) | **Post** /api/v1/tx_query | + +# **TxServiceBroadcast** +> TxBroadcastResponse TxServiceBroadcast(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**TxBroadcastRequest**](TxBroadcastRequest.md)| | + +### Return type + +[**TxBroadcastResponse**](txBroadcastResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceCall** +> TxCallResponse TxServiceCall(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**TxCallRequest**](TxCallRequest.md)| | + +### Return type + +[**TxCallResponse**](txCallResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceChainInfo** +> TxChainInfoResponse TxServiceChainInfo(ctx, ) + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**TxChainInfoResponse**](txChainInfoResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceEstimatePrice** +> TxEstimatePriceResponse TxServiceEstimatePrice(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**TxEstimatePriceRequest**](TxEstimatePriceRequest.md)| | + +### Return type + +[**TxEstimatePriceResponse**](txEstimatePriceResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceGetAccount** +> TxGetAccountResponse TxServiceGetAccount(ctx, identifier, optional) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **identifier** | **string**| | + **optional** | ***TxServiceApiTxServiceGetAccountOpts** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a pointer to a TxServiceApiTxServiceGetAccountOpts struct +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **status** | **optional.String**| Mapped to URL query parameter `status`. | [default to latest] + +### Return type + +[**TxGetAccountResponse**](txGetAccountResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceGetConfig** +> TxGetConfigResponse TxServiceGetConfig(ctx, ) + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**TxGetConfigResponse**](txGetConfigResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceGetSchema** +> TxGetSchemaResponse TxServiceGetSchema(ctx, dbid) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **dbid** | **string**| | + +### Return type + +[**TxGetSchemaResponse**](txGetSchemaResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceListDatabases** +> TxListDatabasesResponse TxServiceListDatabases(ctx, owner) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **owner** | **string**| | + +### Return type + +[**TxListDatabasesResponse**](txListDatabasesResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServicePing** +> TxPingResponse TxServicePing(ctx, optional) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **optional** | ***TxServiceApiTxServicePingOpts** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a pointer to a TxServiceApiTxServicePingOpts struct +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **message** | **optional.String**| | + +### Return type + +[**TxPingResponse**](txPingResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceQuery** +> TxQueryResponse TxServiceQuery(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**TxQueryRequest**](TxQueryRequest.md)| | + +### Return type + +[**TxQueryResponse**](txQueryResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TxServiceTxQuery** +> TxTxQueryResponse TxServiceTxQuery(ctx, body) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. + **body** | [**TxTxQueryRequest**](TxTxQueryRequest.md)| | + +### Return type + +[**TxTxQueryResponse**](txTxQueryResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxSignature.md b/core/rpc/http/tx/docs/TxSignature.md new file mode 100644 index 000000000..1f64be9e2 --- /dev/null +++ b/core/rpc/http/tx/docs/TxSignature.md @@ -0,0 +1,10 @@ +# TxSignature + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**SignatureBytes** | **string** | | [optional] [default to null] +**SignatureType** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTable.md b/core/rpc/http/tx/docs/TxTable.md new file mode 100644 index 000000000..b06cfea75 --- /dev/null +++ b/core/rpc/http/tx/docs/TxTable.md @@ -0,0 +1,12 @@ +# TxTable + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Columns** | [**[]TxColumn**](txColumn.md) | | [optional] [default to null] +**Indexes** | [**[]TxIndex**](txIndex.md) | | [optional] [default to null] +**ForeignKeys** | [**[]TxForeignKey**](txForeignKey.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTransaction.md b/core/rpc/http/tx/docs/TxTransaction.md new file mode 100644 index 000000000..eafc557b5 --- /dev/null +++ b/core/rpc/http/tx/docs/TxTransaction.md @@ -0,0 +1,12 @@ +# TxTransaction + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Body** | [***TxTransactionBody**](txTransactionBody.md) | | [optional] [default to null] +**Signature** | [***TxSignature**](txSignature.md) | | [optional] [default to null] +**Sender** | **string** | | [optional] [default to null] +**Serialization** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTransactionBody.md b/core/rpc/http/tx/docs/TxTransactionBody.md new file mode 100644 index 000000000..5d46d2799 --- /dev/null +++ b/core/rpc/http/tx/docs/TxTransactionBody.md @@ -0,0 +1,14 @@ +# TxTransactionBody + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Payload** | **string** | | [optional] [default to null] +**PayloadType** | **string** | | [optional] [default to null] +**Fee** | **string** | | [optional] [default to null] +**Nonce** | **string** | | [optional] [default to null] +**ChainId** | **string** | | [optional] [default to null] +**Description** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTransactionResult.md b/core/rpc/http/tx/docs/TxTransactionResult.md new file mode 100644 index 000000000..227b81171 --- /dev/null +++ b/core/rpc/http/tx/docs/TxTransactionResult.md @@ -0,0 +1,14 @@ +# TxTransactionResult + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Code** | **int64** | | [optional] [default to null] +**Log** | **string** | | [optional] [default to null] +**GasUsed** | **string** | | [optional] [default to null] +**GasWanted** | **string** | | [optional] [default to null] +**Data** | **string** | Data contains the output of the transaction. | [optional] [default to null] +**Events** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTxQueryRequest.md b/core/rpc/http/tx/docs/TxTxQueryRequest.md new file mode 100644 index 000000000..06feb8b20 --- /dev/null +++ b/core/rpc/http/tx/docs/TxTxQueryRequest.md @@ -0,0 +1,9 @@ +# TxTxQueryRequest + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TxHash** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxTxQueryResponse.md b/core/rpc/http/tx/docs/TxTxQueryResponse.md new file mode 100644 index 000000000..b5afdff6c --- /dev/null +++ b/core/rpc/http/tx/docs/TxTxQueryResponse.md @@ -0,0 +1,12 @@ +# TxTxQueryResponse + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Hash** | **string** | | [optional] [default to null] +**Height** | **string** | | [optional] [default to null] +**Tx** | [***TxTransaction**](txTransaction.md) | | [optional] [default to null] +**TxResult** | [***TxTransactionResult**](txTransactionResult.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/git_push.sh b/core/rpc/http/tx/git_push.sh new file mode 100644 index 000000000..ae01b182a --- /dev/null +++ b/core/rpc/http/tx/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/core/rpc/http/tx/model_extensions_extension_config.go b/core/rpc/http/tx/model_extensions_extension_config.go new file mode 100644 index 000000000..39cafa588 --- /dev/null +++ b/core/rpc/http/tx/model_extensions_extension_config.go @@ -0,0 +1,14 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type ExtensionsExtensionConfig struct { + Argument string `json:"argument,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/core/rpc/http/tx/model_rpc_status.go b/core/rpc/http/tx/model_rpc_status.go new file mode 100644 index 000000000..28f5fd714 --- /dev/null +++ b/core/rpc/http/tx/model_rpc_status.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type RpcStatus struct { + Code int32 `json:"code,omitempty"` + Message string `json:"message,omitempty"` + Details []map[string]interface{} `json:"details,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_account.go b/core/rpc/http/tx/model_tx_account.go new file mode 100644 index 000000000..def17094c --- /dev/null +++ b/core/rpc/http/tx/model_tx_account.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxAccount struct { + Identifier string `json:"identifier,omitempty"` + Balance string `json:"balance,omitempty"` + Nonce string `json:"nonce,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_account_status.go b/core/rpc/http/tx/model_tx_account_status.go new file mode 100644 index 000000000..ed74d16c3 --- /dev/null +++ b/core/rpc/http/tx/model_tx_account_status.go @@ -0,0 +1,17 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxAccountStatus string + +// List of txAccountStatus +const ( + LATEST_TxAccountStatus TxAccountStatus = "latest" + PENDING_TxAccountStatus TxAccountStatus = "pending" +) diff --git a/core/rpc/http/tx/model_tx_action.go b/core/rpc/http/tx/model_tx_action.go new file mode 100644 index 000000000..80c5ebb09 --- /dev/null +++ b/core/rpc/http/tx/model_tx_action.go @@ -0,0 +1,19 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxAction struct { + Name string `json:"name,omitempty"` + Public bool `json:"public,omitempty"` + Inputs []string `json:"inputs,omitempty"` + Statements []string `json:"statements,omitempty"` + Mutability string `json:"mutability,omitempty"` + Auxiliaries []string `json:"auxiliaries,omitempty"` + Annotations []string `json:"annotations,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_attribute.go b/core/rpc/http/tx/model_tx_attribute.go new file mode 100644 index 000000000..37053ffa3 --- /dev/null +++ b/core/rpc/http/tx/model_tx_attribute.go @@ -0,0 +1,14 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxAttribute struct { + Type_ string `json:"type,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_broadcast_request.go b/core/rpc/http/tx/model_tx_broadcast_request.go new file mode 100644 index 000000000..0e6b5a4a4 --- /dev/null +++ b/core/rpc/http/tx/model_tx_broadcast_request.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxBroadcastRequest struct { + Tx *TxTransaction `json:"tx,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_broadcast_response.go b/core/rpc/http/tx/model_tx_broadcast_response.go new file mode 100644 index 000000000..f74c5f457 --- /dev/null +++ b/core/rpc/http/tx/model_tx_broadcast_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxBroadcastResponse struct { + TxHash string `json:"tx_hash,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_call_request.go b/core/rpc/http/tx/model_tx_call_request.go new file mode 100644 index 000000000..7f68600ed --- /dev/null +++ b/core/rpc/http/tx/model_tx_call_request.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxCallRequest struct { + Body *TxCallRequestBody `json:"body,omitempty"` + // auth_type is the type of authenticator that will be used to derive identifier from the sender. + AuthType string `json:"auth_type,omitempty"` + Sender string `json:"sender,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_call_request_body.go b/core/rpc/http/tx/model_tx_call_request_body.go new file mode 100644 index 000000000..1d28c122e --- /dev/null +++ b/core/rpc/http/tx/model_tx_call_request_body.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxCallRequestBody struct { + Payload string `json:"payload,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_call_response.go b/core/rpc/http/tx/model_tx_call_response.go new file mode 100644 index 000000000..fd856c0cc --- /dev/null +++ b/core/rpc/http/tx/model_tx_call_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxCallResponse struct { + Result string `json:"result,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_chain_info_response.go b/core/rpc/http/tx/model_tx_chain_info_response.go new file mode 100644 index 000000000..3a527120a --- /dev/null +++ b/core/rpc/http/tx/model_tx_chain_info_response.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxChainInfoResponse struct { + ChainId string `json:"chain_id,omitempty"` + Height string `json:"height,omitempty"` + Hash string `json:"hash,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_column.go b/core/rpc/http/tx/model_tx_column.go new file mode 100644 index 000000000..1244f5f79 --- /dev/null +++ b/core/rpc/http/tx/model_tx_column.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxColumn struct { + Name string `json:"name,omitempty"` + Type_ string `json:"type,omitempty"` + Attributes []TxAttribute `json:"attributes,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_estimate_price_request.go b/core/rpc/http/tx/model_tx_estimate_price_request.go new file mode 100644 index 000000000..9eff359af --- /dev/null +++ b/core/rpc/http/tx/model_tx_estimate_price_request.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxEstimatePriceRequest struct { + Tx *TxTransaction `json:"tx,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_estimate_price_response.go b/core/rpc/http/tx/model_tx_estimate_price_response.go new file mode 100644 index 000000000..936140a0b --- /dev/null +++ b/core/rpc/http/tx/model_tx_estimate_price_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxEstimatePriceResponse struct { + Price string `json:"price,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_extensions.go b/core/rpc/http/tx/model_tx_extensions.go new file mode 100644 index 000000000..399551f26 --- /dev/null +++ b/core/rpc/http/tx/model_tx_extensions.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxExtensions struct { + Name string `json:"name,omitempty"` + Initialization []ExtensionsExtensionConfig `json:"initialization,omitempty"` + Alias string `json:"alias,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_foreign_key.go b/core/rpc/http/tx/model_tx_foreign_key.go new file mode 100644 index 000000000..6e3a69f81 --- /dev/null +++ b/core/rpc/http/tx/model_tx_foreign_key.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxForeignKey struct { + ChildKeys []string `json:"child_keys,omitempty"` + ParentKeys []string `json:"parent_keys,omitempty"` + ParentTable string `json:"parent_table,omitempty"` + Actions []TxForeignKeyAction `json:"actions,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_foreign_key_action.go b/core/rpc/http/tx/model_tx_foreign_key_action.go new file mode 100644 index 000000000..f882e80cc --- /dev/null +++ b/core/rpc/http/tx/model_tx_foreign_key_action.go @@ -0,0 +1,14 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxForeignKeyAction struct { + On string `json:"on,omitempty"` + Do string `json:"do,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_get_account_response.go b/core/rpc/http/tx/model_tx_get_account_response.go new file mode 100644 index 000000000..16b89b6d3 --- /dev/null +++ b/core/rpc/http/tx/model_tx_get_account_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxGetAccountResponse struct { + Account *TxAccount `json:"account,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_get_config_response.go b/core/rpc/http/tx/model_tx_get_config_response.go new file mode 100644 index 000000000..cfa5ddd1b --- /dev/null +++ b/core/rpc/http/tx/model_tx_get_config_response.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxGetConfigResponse struct { + ChainCode string `json:"chain_code,omitempty"` + ProviderAddress string `json:"provider_address,omitempty"` + PoolAddress string `json:"pool_address,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_get_schema_response.go b/core/rpc/http/tx/model_tx_get_schema_response.go new file mode 100644 index 000000000..e4e739723 --- /dev/null +++ b/core/rpc/http/tx/model_tx_get_schema_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxGetSchemaResponse struct { + Schema *TxSchema `json:"schema,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_index.go b/core/rpc/http/tx/model_tx_index.go new file mode 100644 index 000000000..e01fc180b --- /dev/null +++ b/core/rpc/http/tx/model_tx_index.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxIndex struct { + Name string `json:"name,omitempty"` + Columns []string `json:"columns,omitempty"` + Type_ string `json:"type,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_list_databases_response.go b/core/rpc/http/tx/model_tx_list_databases_response.go new file mode 100644 index 000000000..915350cdd --- /dev/null +++ b/core/rpc/http/tx/model_tx_list_databases_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxListDatabasesResponse struct { + Databases []string `json:"databases,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_node_info_response.go b/core/rpc/http/tx/model_tx_node_info_response.go new file mode 100644 index 000000000..283eaf4a1 --- /dev/null +++ b/core/rpc/http/tx/model_tx_node_info_response.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// NodeInfoResponse is a node's information. +type TxNodeInfoResponse struct { + NodeId string `json:"node_id,omitempty"` + PublicKey string `json:"public_key,omitempty"` + P2pAddress string `json:"p2p_address,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_ping_response.go b/core/rpc/http/tx/model_tx_ping_response.go new file mode 100644 index 000000000..63f7a0c47 --- /dev/null +++ b/core/rpc/http/tx/model_tx_ping_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxPingResponse struct { + Message string `json:"message,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_query_request.go b/core/rpc/http/tx/model_tx_query_request.go new file mode 100644 index 000000000..7716138ca --- /dev/null +++ b/core/rpc/http/tx/model_tx_query_request.go @@ -0,0 +1,14 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxQueryRequest struct { + Dbid string `json:"dbid,omitempty"` + Query string `json:"query,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_query_response.go b/core/rpc/http/tx/model_tx_query_response.go new file mode 100644 index 000000000..aff20b077 --- /dev/null +++ b/core/rpc/http/tx/model_tx_query_response.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxQueryResponse struct { + Result string `json:"result,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_schema.go b/core/rpc/http/tx/model_tx_schema.go new file mode 100644 index 000000000..dc3240410 --- /dev/null +++ b/core/rpc/http/tx/model_tx_schema.go @@ -0,0 +1,17 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxSchema struct { + Owner string `json:"owner,omitempty"` + Name string `json:"name,omitempty"` + Tables []TxTable `json:"tables,omitempty"` + Actions []TxAction `json:"actions,omitempty"` + Extensions []TxExtensions `json:"extensions,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_signature.go b/core/rpc/http/tx/model_tx_signature.go new file mode 100644 index 000000000..3799c85cc --- /dev/null +++ b/core/rpc/http/tx/model_tx_signature.go @@ -0,0 +1,14 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxSignature struct { + SignatureBytes string `json:"signature_bytes,omitempty"` + SignatureType string `json:"signature_type,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_table.go b/core/rpc/http/tx/model_tx_table.go new file mode 100644 index 000000000..5cb993d54 --- /dev/null +++ b/core/rpc/http/tx/model_tx_table.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTable struct { + Name string `json:"name,omitempty"` + Columns []TxColumn `json:"columns,omitempty"` + Indexes []TxIndex `json:"indexes,omitempty"` + ForeignKeys []TxForeignKey `json:"foreign_keys,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_transaction.go b/core/rpc/http/tx/model_tx_transaction.go new file mode 100644 index 000000000..54f4932b5 --- /dev/null +++ b/core/rpc/http/tx/model_tx_transaction.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTransaction struct { + Body *TxTransactionBody `json:"body,omitempty"` + Signature *TxSignature `json:"signature,omitempty"` + Sender string `json:"sender,omitempty"` + Serialization string `json:"serialization,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_transaction_body.go b/core/rpc/http/tx/model_tx_transaction_body.go new file mode 100644 index 000000000..0e7bbb8b6 --- /dev/null +++ b/core/rpc/http/tx/model_tx_transaction_body.go @@ -0,0 +1,18 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTransactionBody struct { + Payload string `json:"payload,omitempty"` + PayloadType string `json:"payload_type,omitempty"` + Fee string `json:"fee,omitempty"` + Nonce string `json:"nonce,omitempty"` + ChainId string `json:"chain_id,omitempty"` + Description string `json:"description,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_transaction_result.go b/core/rpc/http/tx/model_tx_transaction_result.go new file mode 100644 index 000000000..a31c22ac4 --- /dev/null +++ b/core/rpc/http/tx/model_tx_transaction_result.go @@ -0,0 +1,19 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTransactionResult struct { + Code int64 `json:"code,omitempty"` + Log string `json:"log,omitempty"` + GasUsed string `json:"gas_used,omitempty"` + GasWanted string `json:"gas_wanted,omitempty"` + // Data contains the output of the transaction. + Data string `json:"data,omitempty"` + Events []string `json:"events,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_tx_query_request.go b/core/rpc/http/tx/model_tx_tx_query_request.go new file mode 100644 index 000000000..cb66905e1 --- /dev/null +++ b/core/rpc/http/tx/model_tx_tx_query_request.go @@ -0,0 +1,13 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTxQueryRequest struct { + TxHash string `json:"tx_hash,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_tx_query_response.go b/core/rpc/http/tx/model_tx_tx_query_response.go new file mode 100644 index 000000000..333d86289 --- /dev/null +++ b/core/rpc/http/tx/model_tx_tx_query_response.go @@ -0,0 +1,16 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxTxQueryResponse struct { + Hash string `json:"hash,omitempty"` + Height string `json:"height,omitempty"` + Tx *TxTransaction `json:"tx,omitempty"` + TxResult *TxTransactionResult `json:"tx_result,omitempty"` +} diff --git a/core/rpc/http/tx/response.go b/core/rpc/http/tx/response.go new file mode 100644 index 000000000..216e0dd2c --- /dev/null +++ b/core/rpc/http/tx/response.go @@ -0,0 +1,42 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/core/rpc/protobuf/admin/v0/messages.pb.go b/core/rpc/protobuf/admin/v0/messages.pb.go index 455039916..15c34eea9 100644 --- a/core/rpc/protobuf/admin/v0/messages.pb.go +++ b/core/rpc/protobuf/admin/v0/messages.pb.go @@ -20,100 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type PingRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *PingRequest) Reset() { - *x = PingRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PingRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PingRequest) ProtoMessage() {} - -func (x *PingRequest) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. -func (*PingRequest) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{0} -} - -func (x *PingRequest) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -type PingResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *PingResponse) Reset() { - *x = PingResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PingResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PingResponse) ProtoMessage() {} - -func (x *PingResponse) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. -func (*PingResponse) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{1} -} - -func (x *PingResponse) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - type VersionRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -123,7 +29,7 @@ type VersionRequest struct { func (x *VersionRequest) Reset() { *x = VersionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[2] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -136,7 +42,7 @@ func (x *VersionRequest) String() string { func (*VersionRequest) ProtoMessage() {} func (x *VersionRequest) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[2] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -149,7 +55,7 @@ func (x *VersionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionRequest.ProtoReflect.Descriptor instead. func (*VersionRequest) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{2} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{0} } type VersionResponse struct { @@ -163,7 +69,7 @@ type VersionResponse struct { func (x *VersionResponse) Reset() { *x = VersionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[3] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -176,7 +82,7 @@ func (x *VersionResponse) String() string { func (*VersionResponse) ProtoMessage() {} func (x *VersionResponse) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[3] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -189,7 +95,7 @@ func (x *VersionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead. func (*VersionResponse) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{3} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{1} } func (x *VersionResponse) GetVersionString() string { @@ -208,7 +114,7 @@ type StatusRequest struct { func (x *StatusRequest) Reset() { *x = StatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[4] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -221,7 +127,7 @@ func (x *StatusRequest) String() string { func (*StatusRequest) ProtoMessage() {} func (x *StatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[4] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -234,7 +140,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead. func (*StatusRequest) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{4} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{2} } type StatusResponse struct { @@ -242,15 +148,15 @@ type StatusResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Node *NodeInfo `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - Sync *SyncInfo `protobuf:"bytes,2,opt,name=sync,proto3" json:"sync,omitempty"` - Validator *ValidatorInfo `protobuf:"bytes,3,opt,name=validator,proto3" json:"validator,omitempty"` + Node *NodeInfo `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + Sync *SyncInfo `protobuf:"bytes,2,opt,name=sync,proto3" json:"sync,omitempty"` + Validator *Validator `protobuf:"bytes,3,opt,name=validator,proto3" json:"validator,omitempty"` } func (x *StatusResponse) Reset() { *x = StatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[5] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -263,7 +169,7 @@ func (x *StatusResponse) String() string { func (*StatusResponse) ProtoMessage() {} func (x *StatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[5] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -276,7 +182,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{5} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{3} } func (x *StatusResponse) GetNode() *NodeInfo { @@ -293,7 +199,7 @@ func (x *StatusResponse) GetSync() *SyncInfo { return nil } -func (x *StatusResponse) GetValidator() *ValidatorInfo { +func (x *StatusResponse) GetValidator() *Validator { if x != nil { return x.Validator } @@ -318,7 +224,7 @@ type NodeInfo struct { func (x *NodeInfo) Reset() { *x = NodeInfo{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[6] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -331,7 +237,7 @@ func (x *NodeInfo) String() string { func (*NodeInfo) ProtoMessage() {} func (x *NodeInfo) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[6] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -344,7 +250,7 @@ func (x *NodeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use NodeInfo.ProtoReflect.Descriptor instead. func (*NodeInfo) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{6} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{4} } func (x *NodeInfo) GetChainId() string { @@ -418,7 +324,7 @@ type SyncInfo struct { func (x *SyncInfo) Reset() { *x = SyncInfo{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[7] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -431,7 +337,7 @@ func (x *SyncInfo) String() string { func (*SyncInfo) ProtoMessage() {} func (x *SyncInfo) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[7] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -444,7 +350,7 @@ func (x *SyncInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncInfo.ProtoReflect.Descriptor instead. func (*SyncInfo) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{7} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{5} } func (x *SyncInfo) GetAppHash() string { @@ -482,33 +388,32 @@ func (x *SyncInfo) GetSyncing() bool { return false } -type ValidatorInfo struct { +type Validator struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` - PubkeyType string `protobuf:"bytes,2,opt,name=pubkey_type,proto3" json:"pubkey_type,omitempty"` - Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"` + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // ED25519 PubKey + Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` } -func (x *ValidatorInfo) Reset() { - *x = ValidatorInfo{} +func (x *Validator) Reset() { + *x = Validator{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[8] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ValidatorInfo) String() string { +func (x *Validator) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ValidatorInfo) ProtoMessage() {} +func (*Validator) ProtoMessage() {} -func (x *ValidatorInfo) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[8] +func (x *Validator) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -519,26 +424,19 @@ func (x *ValidatorInfo) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ValidatorInfo.ProtoReflect.Descriptor instead. -func (*ValidatorInfo) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{8} +// Deprecated: Use Validator.ProtoReflect.Descriptor instead. +func (*Validator) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{6} } -func (x *ValidatorInfo) GetPubkey() []byte { +func (x *Validator) GetPubkey() []byte { if x != nil { return x.Pubkey } return nil } -func (x *ValidatorInfo) GetPubkeyType() string { - if x != nil { - return x.PubkeyType - } - return "" -} - -func (x *ValidatorInfo) GetPower() int64 { +func (x *Validator) GetPower() int64 { if x != nil { return x.Power } @@ -558,7 +456,7 @@ type Peer struct { func (x *Peer) Reset() { *x = Peer{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[9] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -571,7 +469,7 @@ func (x *Peer) String() string { func (*Peer) ProtoMessage() {} func (x *Peer) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[9] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -584,7 +482,7 @@ func (x *Peer) ProtoReflect() protoreflect.Message { // Deprecated: Use Peer.ProtoReflect.Descriptor instead. func (*Peer) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{9} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{7} } func (x *Peer) GetNode() *NodeInfo { @@ -617,7 +515,7 @@ type PeersRequest struct { func (x *PeersRequest) Reset() { *x = PeersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[10] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -630,7 +528,7 @@ func (x *PeersRequest) String() string { func (*PeersRequest) ProtoMessage() {} func (x *PeersRequest) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[10] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -643,7 +541,7 @@ func (x *PeersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersRequest.ProtoReflect.Descriptor instead. func (*PeersRequest) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{10} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{8} } type PeersResponse struct { @@ -657,7 +555,7 @@ type PeersResponse struct { func (x *PeersResponse) Reset() { *x = PeersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[11] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -670,7 +568,7 @@ func (x *PeersResponse) String() string { func (*PeersResponse) ProtoMessage() {} func (x *PeersResponse) ProtoReflect() protoreflect.Message { - mi := &file_kwil_admin_v0_messages_proto_msgTypes[11] + mi := &file_kwil_admin_v0_messages_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -683,7 +581,7 @@ func (x *PeersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersResponse.ProtoReflect.Descriptor instead. func (*PeersResponse) Descriptor() ([]byte, []int) { - return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{11} + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{9} } func (x *PeersResponse) GetPeers() []*Peer { @@ -693,159 +591,690 @@ func (x *PeersResponse) GetPeers() []*Peer { return nil } -var File_kwil_admin_v0_messages_proto protoreflect.FileDescriptor +// the following are all transactions, and therefore return a tx.BroadcastResponse +type ApproveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_kwil_admin_v0_messages_proto_rawDesc = []byte{ - 0x0a, 0x1c, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x2f, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x22, 0x27, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x28, - 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x38, 0x0a, 0x0f, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, - 0x0e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4e, - 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, - 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x73, 0x79, - 0x6e, 0x63, 0x12, 0x32, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x90, 0x02, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6c, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, - 0x08, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x22, 0xc2, 0x01, 0x0a, 0x08, 0x53, 0x79, - 0x6e, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x65, 0x73, - 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x12, 0x2c, 0x0a, 0x11, - 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, - 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0f, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x22, 0x5f, - 0x0a, 0x0d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6b, 0x65, - 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x75, - 0x62, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x22, - 0x67, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4e, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, - 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x65, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x42, 0x3e, 0x5a, 0x3c, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, - 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, - 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` } -var ( - file_kwil_admin_v0_messages_proto_rawDescOnce sync.Once - file_kwil_admin_v0_messages_proto_rawDescData = file_kwil_admin_v0_messages_proto_rawDesc -) +func (x *ApproveRequest) Reset() { + *x = ApproveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} -func file_kwil_admin_v0_messages_proto_rawDescGZIP() []byte { - file_kwil_admin_v0_messages_proto_rawDescOnce.Do(func() { - file_kwil_admin_v0_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_kwil_admin_v0_messages_proto_rawDescData) - }) - return file_kwil_admin_v0_messages_proto_rawDescData +func (x *ApproveRequest) String() string { + return protoimpl.X.MessageStringOf(x) } -var file_kwil_admin_v0_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 12) -var file_kwil_admin_v0_messages_proto_goTypes = []interface{}{ - (*PingRequest)(nil), // 0: admin.PingRequest - (*PingResponse)(nil), // 1: admin.PingResponse - (*VersionRequest)(nil), // 2: admin.VersionRequest - (*VersionResponse)(nil), // 3: admin.VersionResponse - (*StatusRequest)(nil), // 4: admin.StatusRequest - (*StatusResponse)(nil), // 5: admin.StatusResponse - (*NodeInfo)(nil), // 6: admin.NodeInfo - (*SyncInfo)(nil), // 7: admin.SyncInfo - (*ValidatorInfo)(nil), // 8: admin.ValidatorInfo - (*Peer)(nil), // 9: admin.Peer - (*PeersRequest)(nil), // 10: admin.PeersRequest - (*PeersResponse)(nil), // 11: admin.PeersResponse +func (*ApproveRequest) ProtoMessage() {} + +func (x *ApproveRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var file_kwil_admin_v0_messages_proto_depIdxs = []int32{ - 6, // 0: admin.StatusResponse.node:type_name -> admin.NodeInfo - 7, // 1: admin.StatusResponse.sync:type_name -> admin.SyncInfo - 8, // 2: admin.StatusResponse.validator:type_name -> admin.ValidatorInfo - 6, // 3: admin.Peer.node:type_name -> admin.NodeInfo - 9, // 4: admin.PeersResponse.peers:type_name -> admin.Peer - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + +// Deprecated: Use ApproveRequest.ProtoReflect.Descriptor instead. +func (*ApproveRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{10} } -func init() { file_kwil_admin_v0_messages_proto_init() } -func file_kwil_admin_v0_messages_proto_init() { - if File_kwil_admin_v0_messages_proto != nil { - return +func (x *ApproveRequest) GetPubkey() []byte { + if x != nil { + return x.Pubkey } - if !protoimpl.UnsafeEnabled { - file_kwil_admin_v0_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } + return nil +} + +type JoinRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *JoinRequest) Reset() { + *x = JoinRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JoinRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JoinRequest) ProtoMessage() {} + +func (x *JoinRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } - file_kwil_admin_v0_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JoinRequest.ProtoReflect.Descriptor instead. +func (*JoinRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{11} +} + +type LeaveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *LeaveRequest) Reset() { + *x = LeaveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LeaveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LeaveRequest) ProtoMessage() {} + +func (x *LeaveRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) } - file_kwil_admin_v0_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionRequest); i { - case 0: - return &v.state + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LeaveRequest.ProtoReflect.Descriptor instead. +func (*LeaveRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{12} +} + +type RemoveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` +} + +func (x *RemoveRequest) Reset() { + *x = RemoveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveRequest) ProtoMessage() {} + +func (x *RemoveRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveRequest.ProtoReflect.Descriptor instead. +func (*RemoveRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{13} +} + +func (x *RemoveRequest) GetPubkey() []byte { + if x != nil { + return x.Pubkey + } + return nil +} + +type JoinStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` +} + +func (x *JoinStatusRequest) Reset() { + *x = JoinStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JoinStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JoinStatusRequest) ProtoMessage() {} + +func (x *JoinStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JoinStatusRequest.ProtoReflect.Descriptor instead. +func (*JoinStatusRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{14} +} + +func (x *JoinStatusRequest) GetPubkey() []byte { + if x != nil { + return x.Pubkey + } + return nil +} + +type JoinStatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JoinRequest *PendingJoin `protobuf:"bytes,1,opt,name=join_request,proto3" json:"join_request,omitempty"` +} + +func (x *JoinStatusResponse) Reset() { + *x = JoinStatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JoinStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JoinStatusResponse) ProtoMessage() {} + +func (x *JoinStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JoinStatusResponse.ProtoReflect.Descriptor instead. +func (*JoinStatusResponse) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{15} +} + +func (x *JoinStatusResponse) GetJoinRequest() *PendingJoin { + if x != nil { + return x.JoinRequest + } + return nil +} + +type PendingJoin struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Candidate []byte `protobuf:"bytes,1,opt,name=candidate,proto3" json:"candidate,omitempty"` // ED25519 PubKey + Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` + ExpiresAt int64 `protobuf:"varint,3,opt,name=expires_at,proto3" json:"expires_at,omitempty"` + Board [][]byte `protobuf:"bytes,4,rep,name=board,proto3" json:"board,omitempty"` // all validators + Approved []bool `protobuf:"varint,5,rep,packed,name=approved,proto3" json:"approved,omitempty"` // whether each validator has approved +} + +func (x *PendingJoin) Reset() { + *x = PendingJoin{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PendingJoin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PendingJoin) ProtoMessage() {} + +func (x *PendingJoin) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PendingJoin.ProtoReflect.Descriptor instead. +func (*PendingJoin) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{16} +} + +func (x *PendingJoin) GetCandidate() []byte { + if x != nil { + return x.Candidate + } + return nil +} + +func (x *PendingJoin) GetPower() int64 { + if x != nil { + return x.Power + } + return 0 +} + +func (x *PendingJoin) GetExpiresAt() int64 { + if x != nil { + return x.ExpiresAt + } + return 0 +} + +func (x *PendingJoin) GetBoard() [][]byte { + if x != nil { + return x.Board + } + return nil +} + +func (x *PendingJoin) GetApproved() []bool { + if x != nil { + return x.Approved + } + return nil +} + +type ListValidatorsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListValidatorsRequest) Reset() { + *x = ListValidatorsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListValidatorsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListValidatorsRequest) ProtoMessage() {} + +func (x *ListValidatorsRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListValidatorsRequest.ProtoReflect.Descriptor instead. +func (*ListValidatorsRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{17} +} + +type ListValidatorsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Validators []*Validator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"` +} + +func (x *ListValidatorsResponse) Reset() { + *x = ListValidatorsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListValidatorsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListValidatorsResponse) ProtoMessage() {} + +func (x *ListValidatorsResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListValidatorsResponse.ProtoReflect.Descriptor instead. +func (*ListValidatorsResponse) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{18} +} + +func (x *ListValidatorsResponse) GetValidators() []*Validator { + if x != nil { + return x.Validators + } + return nil +} + +type ListJoinRequestsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListJoinRequestsRequest) Reset() { + *x = ListJoinRequestsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListJoinRequestsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListJoinRequestsRequest) ProtoMessage() {} + +func (x *ListJoinRequestsRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListJoinRequestsRequest.ProtoReflect.Descriptor instead. +func (*ListJoinRequestsRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{19} +} + +type ListJoinRequestsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JoinRequests []*PendingJoin `protobuf:"bytes,1,rep,name=join_requests,proto3" json:"join_requests,omitempty"` +} + +func (x *ListJoinRequestsResponse) Reset() { + *x = ListJoinRequestsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListJoinRequestsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListJoinRequestsResponse) ProtoMessage() {} + +func (x *ListJoinRequestsResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListJoinRequestsResponse.ProtoReflect.Descriptor instead. +func (*ListJoinRequestsResponse) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{20} +} + +func (x *ListJoinRequestsResponse) GetJoinRequests() []*PendingJoin { + if x != nil { + return x.JoinRequests + } + return nil +} + +var File_kwil_admin_v0_messages_proto protoreflect.FileDescriptor + +var file_kwil_admin_v0_messages_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x2f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x38, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4e, 0x6f, 0x64, 0x65, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x73, 0x79, + 0x6e, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, + 0x2e, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x22, + 0x90, 0x02, 0x0a, 0x08, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, + 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, + 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x22, 0xc2, 0x01, 0x0a, 0x08, 0x53, 0x79, 0x6e, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x1a, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x61, 0x70, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x62, + 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x12, 0x2c, 0x0a, 0x11, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x11, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x62, 0x65, + 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x22, 0x39, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x22, 0x67, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x6e, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x22, 0x0e, 0x0a, 0x0c, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x0d, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, + 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, + 0x28, 0x0a, 0x0e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x0d, 0x0a, 0x0b, 0x4a, 0x6f, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x4c, 0x65, 0x61, 0x76, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, + 0x79, 0x22, 0x2b, 0x0a, 0x11, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x4c, + 0x0a, 0x12, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0c, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x0c, + 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x93, 0x01, 0x0a, + 0x0b, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, + 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x09, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x05, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, + 0x65, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x08, 0x52, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, + 0x65, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4a, 0x0a, 0x16, 0x4c, + 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4a, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x54, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, + 0x0a, 0x0d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, + 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, + 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_kwil_admin_v0_messages_proto_rawDescOnce sync.Once + file_kwil_admin_v0_messages_proto_rawDescData = file_kwil_admin_v0_messages_proto_rawDesc +) + +func file_kwil_admin_v0_messages_proto_rawDescGZIP() []byte { + file_kwil_admin_v0_messages_proto_rawDescOnce.Do(func() { + file_kwil_admin_v0_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_kwil_admin_v0_messages_proto_rawDescData) + }) + return file_kwil_admin_v0_messages_proto_rawDescData +} + +var file_kwil_admin_v0_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_kwil_admin_v0_messages_proto_goTypes = []interface{}{ + (*VersionRequest)(nil), // 0: admin.VersionRequest + (*VersionResponse)(nil), // 1: admin.VersionResponse + (*StatusRequest)(nil), // 2: admin.StatusRequest + (*StatusResponse)(nil), // 3: admin.StatusResponse + (*NodeInfo)(nil), // 4: admin.NodeInfo + (*SyncInfo)(nil), // 5: admin.SyncInfo + (*Validator)(nil), // 6: admin.Validator + (*Peer)(nil), // 7: admin.Peer + (*PeersRequest)(nil), // 8: admin.PeersRequest + (*PeersResponse)(nil), // 9: admin.PeersResponse + (*ApproveRequest)(nil), // 10: admin.ApproveRequest + (*JoinRequest)(nil), // 11: admin.JoinRequest + (*LeaveRequest)(nil), // 12: admin.LeaveRequest + (*RemoveRequest)(nil), // 13: admin.RemoveRequest + (*JoinStatusRequest)(nil), // 14: admin.JoinStatusRequest + (*JoinStatusResponse)(nil), // 15: admin.JoinStatusResponse + (*PendingJoin)(nil), // 16: admin.PendingJoin + (*ListValidatorsRequest)(nil), // 17: admin.ListValidatorsRequest + (*ListValidatorsResponse)(nil), // 18: admin.ListValidatorsResponse + (*ListJoinRequestsRequest)(nil), // 19: admin.ListJoinRequestsRequest + (*ListJoinRequestsResponse)(nil), // 20: admin.ListJoinRequestsResponse +} +var file_kwil_admin_v0_messages_proto_depIdxs = []int32{ + 4, // 0: admin.StatusResponse.node:type_name -> admin.NodeInfo + 5, // 1: admin.StatusResponse.sync:type_name -> admin.SyncInfo + 6, // 2: admin.StatusResponse.validator:type_name -> admin.Validator + 4, // 3: admin.Peer.node:type_name -> admin.NodeInfo + 7, // 4: admin.PeersResponse.peers:type_name -> admin.Peer + 16, // 5: admin.JoinStatusResponse.join_request:type_name -> admin.PendingJoin + 6, // 6: admin.ListValidatorsResponse.validators:type_name -> admin.Validator + 16, // 7: admin.ListJoinRequestsResponse.join_requests:type_name -> admin.PendingJoin + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_kwil_admin_v0_messages_proto_init() } +func file_kwil_admin_v0_messages_proto_init() { + if File_kwil_admin_v0_messages_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_kwil_admin_v0_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VersionRequest); i { + case 0: + return &v.state case 1: return &v.sizeCache case 2: @@ -854,7 +1283,7 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } - file_kwil_admin_v0_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_kwil_admin_v0_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VersionResponse); i { case 0: return &v.state @@ -866,7 +1295,7 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } - file_kwil_admin_v0_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_kwil_admin_v0_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusRequest); i { case 0: return &v.state @@ -878,7 +1307,7 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } - file_kwil_admin_v0_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_kwil_admin_v0_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusResponse); i { case 0: return &v.state @@ -890,7 +1319,7 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } - file_kwil_admin_v0_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_kwil_admin_v0_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NodeInfo); i { case 0: return &v.state @@ -902,7 +1331,7 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } - file_kwil_admin_v0_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_kwil_admin_v0_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SyncInfo); i { case 0: return &v.state @@ -914,8 +1343,32 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } + file_kwil_admin_v0_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Validator); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Peer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } file_kwil_admin_v0_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidatorInfo); i { + switch v := v.(*PeersRequest); i { case 0: return &v.state case 1: @@ -927,7 +1380,7 @@ func file_kwil_admin_v0_messages_proto_init() { } } file_kwil_admin_v0_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Peer); i { + switch v := v.(*PeersResponse); i { case 0: return &v.state case 1: @@ -939,7 +1392,7 @@ func file_kwil_admin_v0_messages_proto_init() { } } file_kwil_admin_v0_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersRequest); i { + switch v := v.(*ApproveRequest); i { case 0: return &v.state case 1: @@ -951,7 +1404,115 @@ func file_kwil_admin_v0_messages_proto_init() { } } file_kwil_admin_v0_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersResponse); i { + switch v := v.(*JoinRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LeaveRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinStatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PendingJoin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListValidatorsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListValidatorsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListJoinRequestsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListJoinRequestsResponse); i { case 0: return &v.state case 1: @@ -969,7 +1530,7 @@ func file_kwil_admin_v0_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kwil_admin_v0_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/core/rpc/protobuf/admin/v0/service.pb.go b/core/rpc/protobuf/admin/v0/service.pb.go index a447c9b82..67ce0c846 100644 --- a/core/rpc/protobuf/admin/v0/service.pb.go +++ b/core/rpc/protobuf/admin/v0/service.pb.go @@ -7,6 +7,7 @@ package admpb import ( + v1 "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -27,59 +28,118 @@ var file_kwil_admin_v0_service_proto_rawDesc = []byte{ 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x1a, 0x1c, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x32, 0xc2, 0x02, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x45, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x30, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x51, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x30, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x06, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x49, 0x0a, 0x05, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x12, 0x13, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, - 0x70, 0x65, 0x65, 0x72, 0x73, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, - 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x3b, - 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x1a, 0x1a, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x62, + 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xfd, 0x06, 0x0a, + 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, + 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, + 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x4d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x15, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, + 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x49, 0x0a, 0x05, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x13, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x53, 0x0a, 0x07, 0x41, 0x70, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x15, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, + 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, + 0x4a, 0x0a, 0x04, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x12, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, + 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x4d, 0x0a, 0x05, 0x4c, + 0x65, 0x61, 0x76, 0x65, 0x12, 0x13, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x65, 0x61, + 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x42, + 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x06, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, + 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x60, 0x0a, 0x0a, + 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4a, 0x6f, 0x69, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x30, 0x2f, 0x6a, 0x6f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x69, + 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x12, 0x1c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x71, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x1e, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x6a, 0x6f, 0x69, 0x6e, 0x73, 0x42, 0x3e, 0x5a, 0x3c, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, + 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, + 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var file_kwil_admin_v0_service_proto_goTypes = []interface{}{ - (*PingRequest)(nil), // 0: admin.PingRequest - (*VersionRequest)(nil), // 1: admin.VersionRequest - (*StatusRequest)(nil), // 2: admin.StatusRequest - (*PeersRequest)(nil), // 3: admin.PeersRequest - (*PingResponse)(nil), // 4: admin.PingResponse - (*VersionResponse)(nil), // 5: admin.VersionResponse - (*StatusResponse)(nil), // 6: admin.StatusResponse - (*PeersResponse)(nil), // 7: admin.PeersResponse + (*VersionRequest)(nil), // 0: admin.VersionRequest + (*StatusRequest)(nil), // 1: admin.StatusRequest + (*PeersRequest)(nil), // 2: admin.PeersRequest + (*ApproveRequest)(nil), // 3: admin.ApproveRequest + (*JoinRequest)(nil), // 4: admin.JoinRequest + (*LeaveRequest)(nil), // 5: admin.LeaveRequest + (*RemoveRequest)(nil), // 6: admin.RemoveRequest + (*JoinStatusRequest)(nil), // 7: admin.JoinStatusRequest + (*ListValidatorsRequest)(nil), // 8: admin.ListValidatorsRequest + (*ListJoinRequestsRequest)(nil), // 9: admin.ListJoinRequestsRequest + (*VersionResponse)(nil), // 10: admin.VersionResponse + (*StatusResponse)(nil), // 11: admin.StatusResponse + (*PeersResponse)(nil), // 12: admin.PeersResponse + (*v1.BroadcastResponse)(nil), // 13: tx.BroadcastResponse + (*JoinStatusResponse)(nil), // 14: admin.JoinStatusResponse + (*ListValidatorsResponse)(nil), // 15: admin.ListValidatorsResponse + (*ListJoinRequestsResponse)(nil), // 16: admin.ListJoinRequestsResponse } var file_kwil_admin_v0_service_proto_depIdxs = []int32{ - 0, // 0: admin.AdminService.Ping:input_type -> admin.PingRequest - 1, // 1: admin.AdminService.Version:input_type -> admin.VersionRequest - 2, // 2: admin.AdminService.Status:input_type -> admin.StatusRequest - 3, // 3: admin.AdminService.Peers:input_type -> admin.PeersRequest - 4, // 4: admin.AdminService.Ping:output_type -> admin.PingResponse - 5, // 5: admin.AdminService.Version:output_type -> admin.VersionResponse - 6, // 6: admin.AdminService.Status:output_type -> admin.StatusResponse - 7, // 7: admin.AdminService.Peers:output_type -> admin.PeersResponse - 4, // [4:8] is the sub-list for method output_type - 0, // [0:4] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: admin.AdminService.Version:input_type -> admin.VersionRequest + 1, // 1: admin.AdminService.Status:input_type -> admin.StatusRequest + 2, // 2: admin.AdminService.Peers:input_type -> admin.PeersRequest + 3, // 3: admin.AdminService.Approve:input_type -> admin.ApproveRequest + 4, // 4: admin.AdminService.Join:input_type -> admin.JoinRequest + 5, // 5: admin.AdminService.Leave:input_type -> admin.LeaveRequest + 6, // 6: admin.AdminService.Remove:input_type -> admin.RemoveRequest + 7, // 7: admin.AdminService.JoinStatus:input_type -> admin.JoinStatusRequest + 8, // 8: admin.AdminService.ListValidators:input_type -> admin.ListValidatorsRequest + 9, // 9: admin.AdminService.ListPendingJoins:input_type -> admin.ListJoinRequestsRequest + 10, // 10: admin.AdminService.Version:output_type -> admin.VersionResponse + 11, // 11: admin.AdminService.Status:output_type -> admin.StatusResponse + 12, // 12: admin.AdminService.Peers:output_type -> admin.PeersResponse + 13, // 13: admin.AdminService.Approve:output_type -> tx.BroadcastResponse + 13, // 14: admin.AdminService.Join:output_type -> tx.BroadcastResponse + 13, // 15: admin.AdminService.Leave:output_type -> tx.BroadcastResponse + 13, // 16: admin.AdminService.Remove:output_type -> tx.BroadcastResponse + 14, // 17: admin.AdminService.JoinStatus:output_type -> admin.JoinStatusResponse + 15, // 18: admin.AdminService.ListValidators:output_type -> admin.ListValidatorsResponse + 16, // 19: admin.AdminService.ListPendingJoins:output_type -> admin.ListJoinRequestsResponse + 10, // [10:20] is the sub-list for method output_type + 0, // [0:10] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_kwil_admin_v0_service_proto_init() } diff --git a/core/rpc/protobuf/admin/v0/service_grpc.pb.go b/core/rpc/protobuf/admin/v0/service_grpc.pb.go index 3e6ffbe78..5a8212ea7 100644 --- a/core/rpc/protobuf/admin/v0/service_grpc.pb.go +++ b/core/rpc/protobuf/admin/v0/service_grpc.pb.go @@ -8,6 +8,7 @@ package admpb import ( context "context" + v1 "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -19,20 +20,32 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - AdminService_Ping_FullMethodName = "/admin.AdminService/Ping" - AdminService_Version_FullMethodName = "/admin.AdminService/Version" - AdminService_Status_FullMethodName = "/admin.AdminService/Status" - AdminService_Peers_FullMethodName = "/admin.AdminService/Peers" + AdminService_Version_FullMethodName = "/admin.AdminService/Version" + AdminService_Status_FullMethodName = "/admin.AdminService/Status" + AdminService_Peers_FullMethodName = "/admin.AdminService/Peers" + AdminService_Approve_FullMethodName = "/admin.AdminService/Approve" + AdminService_Join_FullMethodName = "/admin.AdminService/Join" + AdminService_Leave_FullMethodName = "/admin.AdminService/Leave" + AdminService_Remove_FullMethodName = "/admin.AdminService/Remove" + AdminService_JoinStatus_FullMethodName = "/admin.AdminService/JoinStatus" + AdminService_ListValidators_FullMethodName = "/admin.AdminService/ListValidators" + AdminService_ListPendingJoins_FullMethodName = "/admin.AdminService/ListPendingJoins" ) // AdminServiceClient is the client API for AdminService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type AdminServiceClient interface { - Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) Peers(ctx context.Context, in *PeersRequest, opts ...grpc.CallOption) (*PeersResponse, error) + Approve(ctx context.Context, in *ApproveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) + Join(ctx context.Context, in *JoinRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) + Leave(ctx context.Context, in *LeaveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) + Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) + JoinStatus(ctx context.Context, in *JoinStatusRequest, opts ...grpc.CallOption) (*JoinStatusResponse, error) + ListValidators(ctx context.Context, in *ListValidatorsRequest, opts ...grpc.CallOption) (*ListValidatorsResponse, error) + ListPendingJoins(ctx context.Context, in *ListJoinRequestsRequest, opts ...grpc.CallOption) (*ListJoinRequestsResponse, error) } type adminServiceClient struct { @@ -43,15 +56,6 @@ func NewAdminServiceClient(cc grpc.ClientConnInterface) AdminServiceClient { return &adminServiceClient{cc} } -func (c *adminServiceClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { - out := new(PingResponse) - err := c.cc.Invoke(ctx, AdminService_Ping_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *adminServiceClient) Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) { out := new(VersionResponse) err := c.cc.Invoke(ctx, AdminService_Version_FullMethodName, in, out, opts...) @@ -79,14 +83,83 @@ func (c *adminServiceClient) Peers(ctx context.Context, in *PeersRequest, opts . return out, nil } +func (c *adminServiceClient) Approve(ctx context.Context, in *ApproveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) { + out := new(v1.BroadcastResponse) + err := c.cc.Invoke(ctx, AdminService_Approve_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Join(ctx context.Context, in *JoinRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) { + out := new(v1.BroadcastResponse) + err := c.cc.Invoke(ctx, AdminService_Join_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Leave(ctx context.Context, in *LeaveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) { + out := new(v1.BroadcastResponse) + err := c.cc.Invoke(ctx, AdminService_Leave_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*v1.BroadcastResponse, error) { + out := new(v1.BroadcastResponse) + err := c.cc.Invoke(ctx, AdminService_Remove_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) JoinStatus(ctx context.Context, in *JoinStatusRequest, opts ...grpc.CallOption) (*JoinStatusResponse, error) { + out := new(JoinStatusResponse) + err := c.cc.Invoke(ctx, AdminService_JoinStatus_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) ListValidators(ctx context.Context, in *ListValidatorsRequest, opts ...grpc.CallOption) (*ListValidatorsResponse, error) { + out := new(ListValidatorsResponse) + err := c.cc.Invoke(ctx, AdminService_ListValidators_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) ListPendingJoins(ctx context.Context, in *ListJoinRequestsRequest, opts ...grpc.CallOption) (*ListJoinRequestsResponse, error) { + out := new(ListJoinRequestsResponse) + err := c.cc.Invoke(ctx, AdminService_ListPendingJoins_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdminServiceServer is the server API for AdminService service. // All implementations must embed UnimplementedAdminServiceServer // for forward compatibility type AdminServiceServer interface { - Ping(context.Context, *PingRequest) (*PingResponse, error) Version(context.Context, *VersionRequest) (*VersionResponse, error) Status(context.Context, *StatusRequest) (*StatusResponse, error) Peers(context.Context, *PeersRequest) (*PeersResponse, error) + Approve(context.Context, *ApproveRequest) (*v1.BroadcastResponse, error) + Join(context.Context, *JoinRequest) (*v1.BroadcastResponse, error) + Leave(context.Context, *LeaveRequest) (*v1.BroadcastResponse, error) + Remove(context.Context, *RemoveRequest) (*v1.BroadcastResponse, error) + JoinStatus(context.Context, *JoinStatusRequest) (*JoinStatusResponse, error) + ListValidators(context.Context, *ListValidatorsRequest) (*ListValidatorsResponse, error) + ListPendingJoins(context.Context, *ListJoinRequestsRequest) (*ListJoinRequestsResponse, error) mustEmbedUnimplementedAdminServiceServer() } @@ -94,9 +167,6 @@ type AdminServiceServer interface { type UnimplementedAdminServiceServer struct { } -func (UnimplementedAdminServiceServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") -} func (UnimplementedAdminServiceServer) Version(context.Context, *VersionRequest) (*VersionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") } @@ -106,6 +176,27 @@ func (UnimplementedAdminServiceServer) Status(context.Context, *StatusRequest) ( func (UnimplementedAdminServiceServer) Peers(context.Context, *PeersRequest) (*PeersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Peers not implemented") } +func (UnimplementedAdminServiceServer) Approve(context.Context, *ApproveRequest) (*v1.BroadcastResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Approve not implemented") +} +func (UnimplementedAdminServiceServer) Join(context.Context, *JoinRequest) (*v1.BroadcastResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Join not implemented") +} +func (UnimplementedAdminServiceServer) Leave(context.Context, *LeaveRequest) (*v1.BroadcastResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Leave not implemented") +} +func (UnimplementedAdminServiceServer) Remove(context.Context, *RemoveRequest) (*v1.BroadcastResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Remove not implemented") +} +func (UnimplementedAdminServiceServer) JoinStatus(context.Context, *JoinStatusRequest) (*JoinStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method JoinStatus not implemented") +} +func (UnimplementedAdminServiceServer) ListValidators(context.Context, *ListValidatorsRequest) (*ListValidatorsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListValidators not implemented") +} +func (UnimplementedAdminServiceServer) ListPendingJoins(context.Context, *ListJoinRequestsRequest) (*ListJoinRequestsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPendingJoins not implemented") +} func (UnimplementedAdminServiceServer) mustEmbedUnimplementedAdminServiceServer() {} // UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service. @@ -119,24 +210,6 @@ func RegisterAdminServiceServer(s grpc.ServiceRegistrar, srv AdminServiceServer) s.RegisterService(&AdminService_ServiceDesc, srv) } -func _AdminService_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PingRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AdminServiceServer).Ping(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AdminService_Ping_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AdminServiceServer).Ping(ctx, req.(*PingRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _AdminService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(VersionRequest) if err := dec(in); err != nil { @@ -191,6 +264,132 @@ func _AdminService_Peers_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _AdminService_Approve_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApproveRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Approve(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Approve_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Approve(ctx, req.(*ApproveRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Join_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(JoinRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Join(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Join_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Join(ctx, req.(*JoinRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Leave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LeaveRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Leave(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Leave_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Leave(ctx, req.(*LeaveRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Remove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Remove(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Remove_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Remove(ctx, req.(*RemoveRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_JoinStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(JoinStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).JoinStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_JoinStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).JoinStatus(ctx, req.(*JoinStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_ListValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListValidatorsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).ListValidators(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_ListValidators_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).ListValidators(ctx, req.(*ListValidatorsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_ListPendingJoins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListJoinRequestsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).ListPendingJoins(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_ListPendingJoins_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).ListPendingJoins(ctx, req.(*ListJoinRequestsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AdminService_ServiceDesc is the grpc.ServiceDesc for AdminService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -198,10 +397,6 @@ var AdminService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "admin.AdminService", HandlerType: (*AdminServiceServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "Ping", - Handler: _AdminService_Ping_Handler, - }, { MethodName: "Version", Handler: _AdminService_Version_Handler, @@ -214,6 +409,34 @@ var AdminService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Peers", Handler: _AdminService_Peers_Handler, }, + { + MethodName: "Approve", + Handler: _AdminService_Approve_Handler, + }, + { + MethodName: "Join", + Handler: _AdminService_Join_Handler, + }, + { + MethodName: "Leave", + Handler: _AdminService_Leave_Handler, + }, + { + MethodName: "Remove", + Handler: _AdminService_Remove_Handler, + }, + { + MethodName: "JoinStatus", + Handler: _AdminService_JoinStatus_Handler, + }, + { + MethodName: "ListValidators", + Handler: _AdminService_ListValidators_Handler, + }, + { + MethodName: "ListPendingJoins", + Handler: _AdminService_ListPendingJoins_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kwil/admin/v0/service.proto", diff --git a/core/rpc/protobuf/function/v0/messages.pb.go b/core/rpc/protobuf/function/v0/messages.pb.go new file mode 100644 index 000000000..78ae544ae --- /dev/null +++ b/core/rpc/protobuf/function/v0/messages.pb.go @@ -0,0 +1,244 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.23.4 +// source: kwil/function/v0/messages.proto + +package functionpb + +import ( + v1 "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type VerifySignatureRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signature *v1.Signature `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + Msg []byte `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *VerifySignatureRequest) Reset() { + *x = VerifySignatureRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_function_v0_messages_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifySignatureRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifySignatureRequest) ProtoMessage() {} + +func (x *VerifySignatureRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_function_v0_messages_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifySignatureRequest.ProtoReflect.Descriptor instead. +func (*VerifySignatureRequest) Descriptor() ([]byte, []int) { + return file_kwil_function_v0_messages_proto_rawDescGZIP(), []int{0} +} + +func (x *VerifySignatureRequest) GetSignature() *v1.Signature { + if x != nil { + return x.Signature + } + return nil +} + +func (x *VerifySignatureRequest) GetSender() []byte { + if x != nil { + return x.Sender + } + return nil +} + +func (x *VerifySignatureRequest) GetMsg() []byte { + if x != nil { + return x.Msg + } + return nil +} + +type VerifySignatureResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *VerifySignatureResponse) Reset() { + *x = VerifySignatureResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_function_v0_messages_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifySignatureResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifySignatureResponse) ProtoMessage() {} + +func (x *VerifySignatureResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_function_v0_messages_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifySignatureResponse.ProtoReflect.Descriptor instead. +func (*VerifySignatureResponse) Descriptor() ([]byte, []int) { + return file_kwil_function_v0_messages_proto_rawDescGZIP(), []int{1} +} + +func (x *VerifySignatureResponse) GetValid() bool { + if x != nil { + return x.Valid + } + return false +} + +func (x *VerifySignatureResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +var File_kwil_function_v0_messages_proto protoreflect.FileDescriptor + +var file_kwil_function_v0_messages_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x76, 0x30, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1a, 0x6b, 0x77, 0x69, + 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6f, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x78, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x45, 0x0a, 0x17, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, + 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, + 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_kwil_function_v0_messages_proto_rawDescOnce sync.Once + file_kwil_function_v0_messages_proto_rawDescData = file_kwil_function_v0_messages_proto_rawDesc +) + +func file_kwil_function_v0_messages_proto_rawDescGZIP() []byte { + file_kwil_function_v0_messages_proto_rawDescOnce.Do(func() { + file_kwil_function_v0_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_kwil_function_v0_messages_proto_rawDescData) + }) + return file_kwil_function_v0_messages_proto_rawDescData +} + +var file_kwil_function_v0_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_kwil_function_v0_messages_proto_goTypes = []interface{}{ + (*VerifySignatureRequest)(nil), // 0: function.VerifySignatureRequest + (*VerifySignatureResponse)(nil), // 1: function.VerifySignatureResponse + (*v1.Signature)(nil), // 2: tx.Signature +} +var file_kwil_function_v0_messages_proto_depIdxs = []int32{ + 2, // 0: function.VerifySignatureRequest.signature:type_name -> tx.Signature + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_kwil_function_v0_messages_proto_init() } +func file_kwil_function_v0_messages_proto_init() { + if File_kwil_function_v0_messages_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_kwil_function_v0_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifySignatureRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_function_v0_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifySignatureResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_kwil_function_v0_messages_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_kwil_function_v0_messages_proto_goTypes, + DependencyIndexes: file_kwil_function_v0_messages_proto_depIdxs, + MessageInfos: file_kwil_function_v0_messages_proto_msgTypes, + }.Build() + File_kwil_function_v0_messages_proto = out.File + file_kwil_function_v0_messages_proto_rawDesc = nil + file_kwil_function_v0_messages_proto_goTypes = nil + file_kwil_function_v0_messages_proto_depIdxs = nil +} diff --git a/core/rpc/protobuf/function/v0/service.pb.go b/core/rpc/protobuf/function/v0/service.pb.go new file mode 100644 index 000000000..7a2cff763 --- /dev/null +++ b/core/rpc/protobuf/function/v0/service.pb.go @@ -0,0 +1,86 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.23.4 +// source: kwil/function/v0/service.proto + +package functionpb + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var File_kwil_function_v0_service_proto protoreflect.FileDescriptor + +var file_kwil_function_v0_service_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x76, 0x30, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1f, 0x6b, 0x77, 0x69, 0x6c, + 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x30, 0x2f, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x8e, 0x01, 0x0a, 0x0f, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, + 0x0f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x20, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, + 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, + 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, + 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_kwil_function_v0_service_proto_goTypes = []interface{}{ + (*VerifySignatureRequest)(nil), // 0: function.VerifySignatureRequest + (*VerifySignatureResponse)(nil), // 1: function.VerifySignatureResponse +} +var file_kwil_function_v0_service_proto_depIdxs = []int32{ + 0, // 0: function.FunctionService.VerifySignature:input_type -> function.VerifySignatureRequest + 1, // 1: function.FunctionService.VerifySignature:output_type -> function.VerifySignatureResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_kwil_function_v0_service_proto_init() } +func file_kwil_function_v0_service_proto_init() { + if File_kwil_function_v0_service_proto != nil { + return + } + file_kwil_function_v0_messages_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_kwil_function_v0_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_kwil_function_v0_service_proto_goTypes, + DependencyIndexes: file_kwil_function_v0_service_proto_depIdxs, + }.Build() + File_kwil_function_v0_service_proto = out.File + file_kwil_function_v0_service_proto_rawDesc = nil + file_kwil_function_v0_service_proto_goTypes = nil + file_kwil_function_v0_service_proto_depIdxs = nil +} diff --git a/core/rpc/protobuf/function/v0/service_grpc.pb.go b/core/rpc/protobuf/function/v0/service_grpc.pb.go new file mode 100644 index 000000000..e12022254 --- /dev/null +++ b/core/rpc/protobuf/function/v0/service_grpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.23.4 +// source: kwil/function/v0/service.proto + +package functionpb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + FunctionService_VerifySignature_FullMethodName = "/function.FunctionService/VerifySignature" +) + +// FunctionServiceClient is the client API for FunctionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type FunctionServiceClient interface { + VerifySignature(ctx context.Context, in *VerifySignatureRequest, opts ...grpc.CallOption) (*VerifySignatureResponse, error) +} + +type functionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewFunctionServiceClient(cc grpc.ClientConnInterface) FunctionServiceClient { + return &functionServiceClient{cc} +} + +func (c *functionServiceClient) VerifySignature(ctx context.Context, in *VerifySignatureRequest, opts ...grpc.CallOption) (*VerifySignatureResponse, error) { + out := new(VerifySignatureResponse) + err := c.cc.Invoke(ctx, FunctionService_VerifySignature_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FunctionServiceServer is the server API for FunctionService service. +// All implementations must embed UnimplementedFunctionServiceServer +// for forward compatibility +type FunctionServiceServer interface { + VerifySignature(context.Context, *VerifySignatureRequest) (*VerifySignatureResponse, error) + mustEmbedUnimplementedFunctionServiceServer() +} + +// UnimplementedFunctionServiceServer must be embedded to have forward compatible implementations. +type UnimplementedFunctionServiceServer struct { +} + +func (UnimplementedFunctionServiceServer) VerifySignature(context.Context, *VerifySignatureRequest) (*VerifySignatureResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifySignature not implemented") +} +func (UnimplementedFunctionServiceServer) mustEmbedUnimplementedFunctionServiceServer() {} + +// UnsafeFunctionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FunctionServiceServer will +// result in compilation errors. +type UnsafeFunctionServiceServer interface { + mustEmbedUnimplementedFunctionServiceServer() +} + +func RegisterFunctionServiceServer(s grpc.ServiceRegistrar, srv FunctionServiceServer) { + s.RegisterService(&FunctionService_ServiceDesc, srv) +} + +func _FunctionService_VerifySignature_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifySignatureRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FunctionServiceServer).VerifySignature(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FunctionService_VerifySignature_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FunctionServiceServer).VerifySignature(ctx, req.(*VerifySignatureRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// FunctionService_ServiceDesc is the grpc.ServiceDesc for FunctionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FunctionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "function.FunctionService", + HandlerType: (*FunctionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "VerifySignature", + Handler: _FunctionService_VerifySignature_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "kwil/function/v0/service.proto", +} diff --git a/core/rpc/protobuf/tx/v1/call.pb.go b/core/rpc/protobuf/tx/v1/call.pb.go index 013d957e9..009454a35 100644 --- a/core/rpc/protobuf/tx/v1/call.pb.go +++ b/core/rpc/protobuf/tx/v1/call.pb.go @@ -137,8 +137,7 @@ type CallRequest_Body struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` + Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` } func (x *CallRequest_Body) Reset() { @@ -173,13 +172,6 @@ func (*CallRequest_Body) Descriptor() ([]byte, []int) { return file_kwil_tx_v1_call_proto_rawDescGZIP(), []int{0, 0} } -func (x *CallRequest_Body) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - func (x *CallRequest_Body) GetPayload() []byte { if x != nil { return x.Payload @@ -191,25 +183,23 @@ var File_kwil_tx_v1_call_proto protoreflect.FileDescriptor var file_kwil_tx_v1_call_proto_rawDesc = []byte{ 0x0a, 0x15, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6c, - 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x74, 0x78, 0x22, 0xb1, 0x01, 0x0a, 0x0b, + 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x74, 0x78, 0x22, 0x8f, 0x01, 0x0a, 0x0b, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x1a, 0x42, 0x0a, 0x04, 0x42, - 0x6f, 0x64, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, - 0x26, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, - 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, - 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x1a, 0x20, 0x0a, 0x04, 0x42, + 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x26, 0x0a, + 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, + 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/core/rpc/protobuf/tx/v1/dataset.pb.go b/core/rpc/protobuf/tx/v1/dataset.pb.go index dfa059dda..9872ec94b 100644 --- a/core/rpc/protobuf/tx/v1/dataset.pb.go +++ b/core/rpc/protobuf/tx/v1/dataset.pb.go @@ -198,9 +198,10 @@ type Table struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Columns []*Column `protobuf:"bytes,2,rep,name=columns,proto3" json:"columns,omitempty"` - Indexes []*Index `protobuf:"bytes,3,rep,name=indexes,proto3" json:"indexes,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Columns []*Column `protobuf:"bytes,2,rep,name=columns,proto3" json:"columns,omitempty"` + Indexes []*Index `protobuf:"bytes,3,rep,name=indexes,proto3" json:"indexes,omitempty"` + ForeignKeys []*ForeignKey `protobuf:"bytes,4,rep,name=foreign_keys,proto3" json:"foreign_keys,omitempty"` } func (x *Table) Reset() { @@ -256,6 +257,13 @@ func (x *Table) GetIndexes() []*Index { return nil } +func (x *Table) GetForeignKeys() []*ForeignKey { + if x != nil { + return x.ForeignKeys + } + return nil +} + type Column struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -595,6 +603,132 @@ func (x *Extensions) GetAlias() string { return "" } +type ForeignKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ChildKeys []string `protobuf:"bytes,1,rep,name=child_keys,proto3" json:"child_keys,omitempty"` + ParentKeys []string `protobuf:"bytes,2,rep,name=parent_keys,proto3" json:"parent_keys,omitempty"` + ParentTable string `protobuf:"bytes,3,opt,name=parent_table,proto3" json:"parent_table,omitempty"` + Actions []*ForeignKeyAction `protobuf:"bytes,4,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *ForeignKey) Reset() { + *x = ForeignKey{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ForeignKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ForeignKey) ProtoMessage() {} + +func (x *ForeignKey) ProtoReflect() protoreflect.Message { + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ForeignKey.ProtoReflect.Descriptor instead. +func (*ForeignKey) Descriptor() ([]byte, []int) { + return file_kwil_tx_v1_dataset_proto_rawDescGZIP(), []int{9} +} + +func (x *ForeignKey) GetChildKeys() []string { + if x != nil { + return x.ChildKeys + } + return nil +} + +func (x *ForeignKey) GetParentKeys() []string { + if x != nil { + return x.ParentKeys + } + return nil +} + +func (x *ForeignKey) GetParentTable() string { + if x != nil { + return x.ParentTable + } + return "" +} + +func (x *ForeignKey) GetActions() []*ForeignKeyAction { + if x != nil { + return x.Actions + } + return nil +} + +type ForeignKeyAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + On string `protobuf:"bytes,1,opt,name=on,proto3" json:"on,omitempty"` + Do string `protobuf:"bytes,2,opt,name=do,proto3" json:"do,omitempty"` +} + +func (x *ForeignKeyAction) Reset() { + *x = ForeignKeyAction{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ForeignKeyAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ForeignKeyAction) ProtoMessage() {} + +func (x *ForeignKeyAction) ProtoReflect() protoreflect.Message { + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ForeignKeyAction.ProtoReflect.Descriptor instead. +func (*ForeignKeyAction) Descriptor() ([]byte, []int) { + return file_kwil_tx_v1_dataset_proto_rawDescGZIP(), []int{10} +} + +func (x *ForeignKeyAction) GetOn() string { + if x != nil { + return x.On + } + return "" +} + +func (x *ForeignKeyAction) GetDo() string { + if x != nil { + return x.Do + } + return "" +} + type Extensions_ExtensionConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -607,7 +741,7 @@ type Extensions_ExtensionConfig struct { func (x *Extensions_ExtensionConfig) Reset() { *x = Extensions_ExtensionConfig{} if protoimpl.UnsafeEnabled { - mi := &file_kwil_tx_v1_dataset_proto_msgTypes[9] + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -620,7 +754,7 @@ func (x *Extensions_ExtensionConfig) String() string { func (*Extensions_ExtensionConfig) ProtoMessage() {} func (x *Extensions_ExtensionConfig) ProtoReflect() protoreflect.Message { - mi := &file_kwil_tx_v1_dataset_proto_msgTypes[9] + mi := &file_kwil_tx_v1_dataset_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -671,58 +805,75 @@ var file_kwil_tx_v1_dataset_proto_rawDesc = []byte{ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x78, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x66, 0x0a, - 0x05, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x07, 0x63, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x74, 0x78, - 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, - 0x12, 0x23, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x09, 0x2e, 0x74, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x65, 0x73, 0x22, 0x5f, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, + 0x73, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x9a, 0x01, + 0x0a, 0x05, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x07, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x74, + 0x78, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x12, 0x23, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x74, 0x78, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x66, 0x6f, 0x72, 0x65, 0x69, 0x67, + 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, + 0x78, 0x2e, 0x46, 0x6f, 0x72, 0x65, 0x69, 0x67, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x0c, 0x66, 0x6f, + 0x72, 0x65, 0x69, 0x67, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x5f, 0x0a, 0x06, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x74, 0x78, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x09, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x49, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd0, 0x01, + 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, + 0x6d, 0x75, 0x74, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, + 0x61, 0x75, 0x78, 0x69, 0x6c, 0x69, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0b, 0x61, 0x75, 0x78, 0x69, 0x6c, 0x69, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0xc3, 0x01, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x78, - 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x49, 0x0a, - 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, - 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x75, 0x74, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x75, 0x74, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x78, 0x69, 0x6c, - 0x69, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, - 0x78, 0x69, 0x6c, 0x69, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, - 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc3, 0x01, 0x0a, 0x0a, - 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, - 0x0a, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x78, 0x2e, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x1a, 0x43, 0x0a, 0x0f, - 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, - 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x78, + 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x61, + 0x6c, 0x69, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x1a, 0x43, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x69, + 0x67, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x68, 0x69, 0x6c, 0x64, + 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, + 0x78, 0x2e, 0x46, 0x6f, 0x72, 0x65, 0x69, 0x67, 0x6e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x32, 0x0a, 0x10, 0x46, + 0x6f, 0x72, 0x65, 0x69, 0x67, 0x6e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x0e, 0x0a, 0x02, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x6e, 0x12, + 0x0e, 0x0a, 0x02, 0x64, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x64, 0x6f, 0x42, + 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, + 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -737,7 +888,7 @@ func file_kwil_tx_v1_dataset_proto_rawDescGZIP() []byte { return file_kwil_tx_v1_dataset_proto_rawDescData } -var file_kwil_tx_v1_dataset_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_kwil_tx_v1_dataset_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_kwil_tx_v1_dataset_proto_goTypes = []interface{}{ (*GetSchemaRequest)(nil), // 0: tx.GetSchemaRequest (*GetSchemaResponse)(nil), // 1: tx.GetSchemaResponse @@ -748,22 +899,26 @@ var file_kwil_tx_v1_dataset_proto_goTypes = []interface{}{ (*Index)(nil), // 6: tx.Index (*Action)(nil), // 7: tx.Action (*Extensions)(nil), // 8: tx.Extensions - (*Extensions_ExtensionConfig)(nil), // 9: tx.Extensions.ExtensionConfig + (*ForeignKey)(nil), // 9: tx.ForeignKey + (*ForeignKeyAction)(nil), // 10: tx.ForeignKeyAction + (*Extensions_ExtensionConfig)(nil), // 11: tx.Extensions.ExtensionConfig } var file_kwil_tx_v1_dataset_proto_depIdxs = []int32{ - 2, // 0: tx.GetSchemaResponse.schema:type_name -> tx.Schema - 3, // 1: tx.Schema.tables:type_name -> tx.Table - 7, // 2: tx.Schema.actions:type_name -> tx.Action - 8, // 3: tx.Schema.extensions:type_name -> tx.Extensions - 4, // 4: tx.Table.columns:type_name -> tx.Column - 6, // 5: tx.Table.indexes:type_name -> tx.Index - 5, // 6: tx.Column.attributes:type_name -> tx.Attribute - 9, // 7: tx.Extensions.initialization:type_name -> tx.Extensions.ExtensionConfig - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 2, // 0: tx.GetSchemaResponse.schema:type_name -> tx.Schema + 3, // 1: tx.Schema.tables:type_name -> tx.Table + 7, // 2: tx.Schema.actions:type_name -> tx.Action + 8, // 3: tx.Schema.extensions:type_name -> tx.Extensions + 4, // 4: tx.Table.columns:type_name -> tx.Column + 6, // 5: tx.Table.indexes:type_name -> tx.Index + 9, // 6: tx.Table.foreign_keys:type_name -> tx.ForeignKey + 5, // 7: tx.Column.attributes:type_name -> tx.Attribute + 11, // 8: tx.Extensions.initialization:type_name -> tx.Extensions.ExtensionConfig + 10, // 9: tx.ForeignKey.actions:type_name -> tx.ForeignKeyAction + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_kwil_tx_v1_dataset_proto_init() } @@ -881,6 +1036,30 @@ func file_kwil_tx_v1_dataset_proto_init() { } } file_kwil_tx_v1_dataset_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ForeignKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_tx_v1_dataset_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ForeignKeyAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_tx_v1_dataset_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Extensions_ExtensionConfig); i { case 0: return &v.state @@ -899,7 +1078,7 @@ func file_kwil_tx_v1_dataset_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kwil_tx_v1_dataset_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/core/rpc/protobuf/tx/v1/info.pb.go b/core/rpc/protobuf/tx/v1/info.pb.go new file mode 100644 index 000000000..783b5a235 --- /dev/null +++ b/core/rpc/protobuf/tx/v1/info.pb.go @@ -0,0 +1,220 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.23.4 +// source: kwil/tx/v1/info.proto + +package txpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// NodeInfoRequest requests a node's information. +type NodeInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NodeInfoRequest) Reset() { + *x = NodeInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_tx_v1_info_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfoRequest) ProtoMessage() {} + +func (x *NodeInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_tx_v1_info_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfoRequest.ProtoReflect.Descriptor instead. +func (*NodeInfoRequest) Descriptor() ([]byte, []int) { + return file_kwil_tx_v1_info_proto_rawDescGZIP(), []int{0} +} + +// NodeInfoResponse is a node's information. +type NodeInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NodeId string `protobuf:"bytes,1,opt,name=node_id,proto3" json:"node_id,omitempty"` + PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,proto3" json:"public_key,omitempty"` + P2PAddress string `protobuf:"bytes,3,opt,name=p2p_address,proto3" json:"p2p_address,omitempty"` +} + +func (x *NodeInfoResponse) Reset() { + *x = NodeInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_tx_v1_info_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfoResponse) ProtoMessage() {} + +func (x *NodeInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_tx_v1_info_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfoResponse.ProtoReflect.Descriptor instead. +func (*NodeInfoResponse) Descriptor() ([]byte, []int) { + return file_kwil_tx_v1_info_proto_rawDescGZIP(), []int{1} +} + +func (x *NodeInfoResponse) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *NodeInfoResponse) GetPublicKey() []byte { + if x != nil { + return x.PublicKey + } + return nil +} + +func (x *NodeInfoResponse) GetP2PAddress() string { + if x != nil { + return x.P2PAddress + } + return "" +} + +var File_kwil_tx_v1_info_proto protoreflect.FileDescriptor + +var file_kwil_tx_v1_info_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x66, + 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x74, 0x78, 0x22, 0x11, 0x0a, 0x0f, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6e, + 0x0a, 0x10, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, + 0x70, 0x32, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x32, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x3a, + 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, + 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, + 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_kwil_tx_v1_info_proto_rawDescOnce sync.Once + file_kwil_tx_v1_info_proto_rawDescData = file_kwil_tx_v1_info_proto_rawDesc +) + +func file_kwil_tx_v1_info_proto_rawDescGZIP() []byte { + file_kwil_tx_v1_info_proto_rawDescOnce.Do(func() { + file_kwil_tx_v1_info_proto_rawDescData = protoimpl.X.CompressGZIP(file_kwil_tx_v1_info_proto_rawDescData) + }) + return file_kwil_tx_v1_info_proto_rawDescData +} + +var file_kwil_tx_v1_info_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_kwil_tx_v1_info_proto_goTypes = []interface{}{ + (*NodeInfoRequest)(nil), // 0: tx.NodeInfoRequest + (*NodeInfoResponse)(nil), // 1: tx.NodeInfoResponse +} +var file_kwil_tx_v1_info_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_kwil_tx_v1_info_proto_init() } +func file_kwil_tx_v1_info_proto_init() { + if File_kwil_tx_v1_info_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_kwil_tx_v1_info_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NodeInfoRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_tx_v1_info_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NodeInfoResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_kwil_tx_v1_info_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_kwil_tx_v1_info_proto_goTypes, + DependencyIndexes: file_kwil_tx_v1_info_proto_depIdxs, + MessageInfos: file_kwil_tx_v1_info_proto_msgTypes, + }.Build() + File_kwil_tx_v1_info_proto = out.File + file_kwil_tx_v1_info_proto_rawDesc = nil + file_kwil_tx_v1_info_proto_goTypes = nil + file_kwil_tx_v1_info_proto_depIdxs = nil +} diff --git a/core/rpc/protobuf/tx/v1/service.pb.go b/core/rpc/protobuf/tx/v1/service.pb.go index cc0986626..b1a6bdc1d 100644 --- a/core/rpc/protobuf/tx/v1/service.pb.go +++ b/core/rpc/protobuf/tx/v1/service.pb.go @@ -42,157 +42,98 @@ var file_kwil_tx_v1_service_proto_rawDesc = []byte{ 0x6f, 0x1a, 0x18, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x1a, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, - 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x78, 0x5f, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x6b, 0x77, 0x69, 0x6c, 0x2f, - 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xff, 0x0c, 0x0a, 0x09, 0x54, 0x78, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x56, 0x0a, 0x09, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x61, - 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, - 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, - 0x74, 0x12, 0x67, 0x0a, 0x0d, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 0x18, 0x2e, 0x74, 0x78, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, - 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, - 0x78, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, - 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x73, 0x74, 0x69, - 0x6d, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x05, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x12, 0x10, 0x2e, 0x74, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, - 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x12, 0x62, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x7d, 0x12, 0x3f, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x0f, - 0x2e, 0x74, 0x78, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x10, 0x2e, 0x74, 0x78, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x67, 0x0a, 0x0d, 0x4c, 0x69, 0x73, - 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x18, 0x2e, 0x74, 0x78, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x78, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x7b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x73, 0x12, 0x61, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, - 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x62, 0x69, 0x64, 0x7d, 0x2f, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x75, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x2e, 0x74, 0x78, 0x2e, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x78, 0x2e, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, - 0x2a, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x70, 0x72, 0x6f, - 0x76, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x67, 0x0a, 0x0d, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x18, 0x2e, - 0x74, 0x78, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x6f, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x78, 0x2e, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x12, 0x6b, 0x0a, 0x0e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, - 0x6f, 0x72, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x19, 0x2e, 0x74, 0x78, 0x2e, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x74, 0x78, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6c, 0x65, 0x61, - 0x76, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x13, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x74, 0x78, 0x2e, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x78, 0x2e, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x28, 0x12, 0x26, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x2f, 0x7b, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x7d, 0x12, 0x74, 0x0a, 0x11, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, - 0x12, 0x1c, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, - 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x12, 0x42, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x0f, 0x2e, 0x74, 0x78, 0x2e, 0x43, - 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x2e, - 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x63, 0x61, 0x6c, 0x6c, 0x12, 0x4f, 0x0a, 0x07, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x12, 0x12, 0x2e, 0x74, 0x78, 0x2e, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x78, 0x2e, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x78, - 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x6f, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1a, 0x2e, 0x74, 0x78, 0x2e, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x74, 0x78, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, - 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, - 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x1a, 0x19, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x78, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xc2, 0x07, + 0x0a, 0x09, 0x54, 0x78, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x54, 0x0a, 0x09, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, + 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x12, 0x56, 0x0a, 0x09, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x14, + 0x2e, 0x74, 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, + 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x16, 0x3a, 0x01, 0x2a, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x67, 0x0a, 0x0d, 0x45, 0x73, 0x74, + 0x69, 0x6d, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x74, 0x78, 0x2e, + 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x78, 0x2e, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, + 0x74, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x12, 0x46, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x10, 0x2e, 0x74, 0x78, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, + 0x74, 0x78, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x62, 0x0a, 0x0a, 0x47, 0x65, + 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, + 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x7d, 0x12, 0x3f, + 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x0f, 0x2e, 0x74, 0x78, 0x2e, 0x50, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x12, + 0x50, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x2e, 0x74, + 0x78, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x67, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x73, 0x12, 0x18, 0x2e, 0x74, 0x78, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, + 0x78, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, + 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x7d, + 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x09, 0x47, 0x65, + 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x14, 0x2e, 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x74, 0x78, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12, 0x1f, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, + 0x7b, 0x64, 0x62, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x42, 0x0a, + 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x0f, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x2e, 0x43, 0x61, 0x6c, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, + 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x61, 0x6c, + 0x6c, 0x12, 0x4f, 0x0a, 0x07, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x2e, 0x74, + 0x78, 0x2e, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x13, 0x2e, 0x74, 0x78, 0x2e, 0x54, 0x78, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, + 0x22, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x78, 0x5f, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, + 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_kwil_tx_v1_service_proto_goTypes = []interface{}{ - (*ChainInfoRequest)(nil), // 0: tx.ChainInfoRequest - (*BroadcastRequest)(nil), // 1: tx.BroadcastRequest - (*EstimatePriceRequest)(nil), // 2: tx.EstimatePriceRequest - (*QueryRequest)(nil), // 3: tx.QueryRequest - (*GetAccountRequest)(nil), // 4: tx.GetAccountRequest - (*PingRequest)(nil), // 5: tx.PingRequest - (*GetConfigRequest)(nil), // 6: tx.GetConfigRequest - (*ListDatabasesRequest)(nil), // 7: tx.ListDatabasesRequest - (*GetSchemaRequest)(nil), // 8: tx.GetSchemaRequest - (*ValidatorApprovalRequest)(nil), // 9: tx.ValidatorApprovalRequest - (*ValidatorJoinRequest)(nil), // 10: tx.ValidatorJoinRequest - (*ValidatorLeaveRequest)(nil), // 11: tx.ValidatorLeaveRequest - (*ValidatorJoinStatusRequest)(nil), // 12: tx.ValidatorJoinStatusRequest - (*CurrentValidatorsRequest)(nil), // 13: tx.CurrentValidatorsRequest - (*CallRequest)(nil), // 14: tx.CallRequest - (*TxQueryRequest)(nil), // 15: tx.TxQueryRequest - (*VerifySignatureRequest)(nil), // 16: tx.VerifySignatureRequest - (*ChainInfoResponse)(nil), // 17: tx.ChainInfoResponse - (*BroadcastResponse)(nil), // 18: tx.BroadcastResponse - (*EstimatePriceResponse)(nil), // 19: tx.EstimatePriceResponse - (*QueryResponse)(nil), // 20: tx.QueryResponse - (*GetAccountResponse)(nil), // 21: tx.GetAccountResponse - (*PingResponse)(nil), // 22: tx.PingResponse - (*GetConfigResponse)(nil), // 23: tx.GetConfigResponse - (*ListDatabasesResponse)(nil), // 24: tx.ListDatabasesResponse - (*GetSchemaResponse)(nil), // 25: tx.GetSchemaResponse - (*ValidatorApprovalResponse)(nil), // 26: tx.ValidatorApprovalResponse - (*ValidatorJoinResponse)(nil), // 27: tx.ValidatorJoinResponse - (*ValidatorLeaveResponse)(nil), // 28: tx.ValidatorLeaveResponse - (*ValidatorJoinStatusResponse)(nil), // 29: tx.ValidatorJoinStatusResponse - (*CurrentValidatorsResponse)(nil), // 30: tx.CurrentValidatorsResponse - (*CallResponse)(nil), // 31: tx.CallResponse - (*TxQueryResponse)(nil), // 32: tx.TxQueryResponse - (*VerifySignatureResponse)(nil), // 33: tx.VerifySignatureResponse + (*ChainInfoRequest)(nil), // 0: tx.ChainInfoRequest + (*BroadcastRequest)(nil), // 1: tx.BroadcastRequest + (*EstimatePriceRequest)(nil), // 2: tx.EstimatePriceRequest + (*QueryRequest)(nil), // 3: tx.QueryRequest + (*GetAccountRequest)(nil), // 4: tx.GetAccountRequest + (*PingRequest)(nil), // 5: tx.PingRequest + (*GetConfigRequest)(nil), // 6: tx.GetConfigRequest + (*ListDatabasesRequest)(nil), // 7: tx.ListDatabasesRequest + (*GetSchemaRequest)(nil), // 8: tx.GetSchemaRequest + (*CallRequest)(nil), // 9: tx.CallRequest + (*TxQueryRequest)(nil), // 10: tx.TxQueryRequest + (*ChainInfoResponse)(nil), // 11: tx.ChainInfoResponse + (*BroadcastResponse)(nil), // 12: tx.BroadcastResponse + (*EstimatePriceResponse)(nil), // 13: tx.EstimatePriceResponse + (*QueryResponse)(nil), // 14: tx.QueryResponse + (*GetAccountResponse)(nil), // 15: tx.GetAccountResponse + (*PingResponse)(nil), // 16: tx.PingResponse + (*GetConfigResponse)(nil), // 17: tx.GetConfigResponse + (*ListDatabasesResponse)(nil), // 18: tx.ListDatabasesResponse + (*GetSchemaResponse)(nil), // 19: tx.GetSchemaResponse + (*CallResponse)(nil), // 20: tx.CallResponse + (*TxQueryResponse)(nil), // 21: tx.TxQueryResponse } var file_kwil_tx_v1_service_proto_depIdxs = []int32{ 0, // 0: tx.TxService.ChainInfo:input_type -> tx.ChainInfoRequest @@ -204,33 +145,21 @@ var file_kwil_tx_v1_service_proto_depIdxs = []int32{ 6, // 6: tx.TxService.GetConfig:input_type -> tx.GetConfigRequest 7, // 7: tx.TxService.ListDatabases:input_type -> tx.ListDatabasesRequest 8, // 8: tx.TxService.GetSchema:input_type -> tx.GetSchemaRequest - 9, // 9: tx.TxService.ApproveValidator:input_type -> tx.ValidatorApprovalRequest - 10, // 10: tx.TxService.ValidatorJoin:input_type -> tx.ValidatorJoinRequest - 11, // 11: tx.TxService.ValidatorLeave:input_type -> tx.ValidatorLeaveRequest - 12, // 12: tx.TxService.ValidatorJoinStatus:input_type -> tx.ValidatorJoinStatusRequest - 13, // 13: tx.TxService.CurrentValidators:input_type -> tx.CurrentValidatorsRequest - 14, // 14: tx.TxService.Call:input_type -> tx.CallRequest - 15, // 15: tx.TxService.TxQuery:input_type -> tx.TxQueryRequest - 16, // 16: tx.TxService.VerifySignature:input_type -> tx.VerifySignatureRequest - 17, // 17: tx.TxService.ChainInfo:output_type -> tx.ChainInfoResponse - 18, // 18: tx.TxService.Broadcast:output_type -> tx.BroadcastResponse - 19, // 19: tx.TxService.EstimatePrice:output_type -> tx.EstimatePriceResponse - 20, // 20: tx.TxService.Query:output_type -> tx.QueryResponse - 21, // 21: tx.TxService.GetAccount:output_type -> tx.GetAccountResponse - 22, // 22: tx.TxService.Ping:output_type -> tx.PingResponse - 23, // 23: tx.TxService.GetConfig:output_type -> tx.GetConfigResponse - 24, // 24: tx.TxService.ListDatabases:output_type -> tx.ListDatabasesResponse - 25, // 25: tx.TxService.GetSchema:output_type -> tx.GetSchemaResponse - 26, // 26: tx.TxService.ApproveValidator:output_type -> tx.ValidatorApprovalResponse - 27, // 27: tx.TxService.ValidatorJoin:output_type -> tx.ValidatorJoinResponse - 28, // 28: tx.TxService.ValidatorLeave:output_type -> tx.ValidatorLeaveResponse - 29, // 29: tx.TxService.ValidatorJoinStatus:output_type -> tx.ValidatorJoinStatusResponse - 30, // 30: tx.TxService.CurrentValidators:output_type -> tx.CurrentValidatorsResponse - 31, // 31: tx.TxService.Call:output_type -> tx.CallResponse - 32, // 32: tx.TxService.TxQuery:output_type -> tx.TxQueryResponse - 33, // 33: tx.TxService.VerifySignature:output_type -> tx.VerifySignatureResponse - 17, // [17:34] is the sub-list for method output_type - 0, // [0:17] is the sub-list for method input_type + 9, // 9: tx.TxService.Call:input_type -> tx.CallRequest + 10, // 10: tx.TxService.TxQuery:input_type -> tx.TxQueryRequest + 11, // 11: tx.TxService.ChainInfo:output_type -> tx.ChainInfoResponse + 12, // 12: tx.TxService.Broadcast:output_type -> tx.BroadcastResponse + 13, // 13: tx.TxService.EstimatePrice:output_type -> tx.EstimatePriceResponse + 14, // 14: tx.TxService.Query:output_type -> tx.QueryResponse + 15, // 15: tx.TxService.GetAccount:output_type -> tx.GetAccountResponse + 16, // 16: tx.TxService.Ping:output_type -> tx.PingResponse + 17, // 17: tx.TxService.GetConfig:output_type -> tx.GetConfigResponse + 18, // 18: tx.TxService.ListDatabases:output_type -> tx.ListDatabasesResponse + 19, // 19: tx.TxService.GetSchema:output_type -> tx.GetSchemaResponse + 20, // 20: tx.TxService.Call:output_type -> tx.CallResponse + 21, // 21: tx.TxService.TxQuery:output_type -> tx.TxQueryResponse + 11, // [11:22] is the sub-list for method output_type + 0, // [0:11] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -251,9 +180,7 @@ func file_kwil_tx_v1_service_proto_init() { file_kwil_tx_v1_list_proto_init() file_kwil_tx_v1_dataset_proto_init() file_kwil_tx_v1_call_proto_init() - file_kwil_tx_v1_validator_proto_init() file_kwil_tx_v1_tx_query_proto_init() - file_kwil_tx_v1_signature_proto_init() type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/core/rpc/protobuf/tx/v1/service.pb.gw.go b/core/rpc/protobuf/tx/v1/service.pb.gw.go index 6ada3d544..9d96cdacb 100644 --- a/core/rpc/protobuf/tx/v1/service.pb.gw.go +++ b/core/rpc/protobuf/tx/v1/service.pb.gw.go @@ -379,178 +379,6 @@ func local_request_TxService_GetSchema_0(ctx context.Context, marshaler runtime. } -func request_TxService_ApproveValidator_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorApprovalRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.ApproveValidator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_ApproveValidator_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorApprovalRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ApproveValidator(ctx, &protoReq) - return msg, metadata, err - -} - -func request_TxService_ValidatorJoin_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorJoinRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.ValidatorJoin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_ValidatorJoin_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorJoinRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ValidatorJoin(ctx, &protoReq) - return msg, metadata, err - -} - -func request_TxService_ValidatorLeave_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorLeaveRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.ValidatorLeave(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_ValidatorLeave_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorLeaveRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ValidatorLeave(ctx, &protoReq) - return msg, metadata, err - -} - -func request_TxService_ValidatorJoinStatus_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorJoinStatusRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["pubkey"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pubkey") - } - - protoReq.Pubkey, err = runtime.Bytes(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pubkey", err) - } - - msg, err := client.ValidatorJoinStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_ValidatorJoinStatus_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidatorJoinStatusRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["pubkey"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "pubkey") - } - - protoReq.Pubkey, err = runtime.Bytes(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "pubkey", err) - } - - msg, err := server.ValidatorJoinStatus(ctx, &protoReq) - return msg, metadata, err - -} - -func request_TxService_CurrentValidators_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq CurrentValidatorsRequest - var metadata runtime.ServerMetadata - - msg, err := client.CurrentValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_CurrentValidators_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq CurrentValidatorsRequest - var metadata runtime.ServerMetadata - - msg, err := server.CurrentValidators(ctx, &protoReq) - return msg, metadata, err - -} - func request_TxService_Call_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CallRequest var metadata runtime.ServerMetadata @@ -619,40 +447,6 @@ func local_request_TxService_TxQuery_0(ctx context.Context, marshaler runtime.Ma } -func request_TxService_VerifySignature_0(ctx context.Context, marshaler runtime.Marshaler, client TxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifySignatureRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.VerifySignature(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_TxService_VerifySignature_0(ctx context.Context, marshaler runtime.Marshaler, server TxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifySignatureRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.VerifySignature(ctx, &protoReq) - return msg, metadata, err - -} - // RegisterTxServiceHandlerServer registers the http handlers for service TxService to "mux". // UnaryRPC :call TxServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -884,131 +678,6 @@ func RegisterTxServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, }) - mux.Handle("POST", pattern_TxService_ApproveValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/ApproveValidator", runtime.WithHTTPPathPattern("/api/v1/approve_validator")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_ApproveValidator_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ApproveValidator_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_TxService_ValidatorJoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/ValidatorJoin", runtime.WithHTTPPathPattern("/api/v1/validator_join")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_ValidatorJoin_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorJoin_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_TxService_ValidatorLeave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/ValidatorLeave", runtime.WithHTTPPathPattern("/api/v1/validator_leave")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_ValidatorLeave_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorLeave_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_TxService_ValidatorJoinStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/ValidatorJoinStatus", runtime.WithHTTPPathPattern("/api/v1/validator_join_status/{pubkey}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_ValidatorJoinStatus_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorJoinStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_TxService_CurrentValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/CurrentValidators", runtime.WithHTTPPathPattern("/api/v1/current_validators")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_CurrentValidators_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_CurrentValidators_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("POST", pattern_TxService_Call_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1059,31 +728,6 @@ func RegisterTxServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, }) - mux.Handle("POST", pattern_TxService_VerifySignature_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/tx.TxService/VerifySignature", runtime.WithHTTPPathPattern("/api/v1/verify_signature")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_TxService_VerifySignature_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_VerifySignature_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -1323,116 +967,6 @@ func RegisterTxServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) - mux.Handle("POST", pattern_TxService_ApproveValidator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/ApproveValidator", runtime.WithHTTPPathPattern("/api/v1/approve_validator")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_ApproveValidator_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ApproveValidator_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_TxService_ValidatorJoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/ValidatorJoin", runtime.WithHTTPPathPattern("/api/v1/validator_join")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_ValidatorJoin_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorJoin_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_TxService_ValidatorLeave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/ValidatorLeave", runtime.WithHTTPPathPattern("/api/v1/validator_leave")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_ValidatorLeave_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorLeave_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_TxService_ValidatorJoinStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/ValidatorJoinStatus", runtime.WithHTTPPathPattern("/api/v1/validator_join_status/{pubkey}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_ValidatorJoinStatus_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_ValidatorJoinStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_TxService_CurrentValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/CurrentValidators", runtime.WithHTTPPathPattern("/api/v1/current_validators")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_CurrentValidators_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_CurrentValidators_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("POST", pattern_TxService_Call_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1477,28 +1011,6 @@ func RegisterTxServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) - mux.Handle("POST", pattern_TxService_VerifySignature_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/tx.TxService/VerifySignature", runtime.WithHTTPPathPattern("/api/v1/verify_signature")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_TxService_VerifySignature_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_TxService_VerifySignature_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -1521,21 +1033,9 @@ var ( pattern_TxService_GetSchema_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "databases", "dbid", "schema"}, "")) - pattern_TxService_ApproveValidator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "approve_validator"}, "")) - - pattern_TxService_ValidatorJoin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "validator_join"}, "")) - - pattern_TxService_ValidatorLeave_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "validator_leave"}, "")) - - pattern_TxService_ValidatorJoinStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "validator_join_status", "pubkey"}, "")) - - pattern_TxService_CurrentValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "current_validators"}, "")) - pattern_TxService_Call_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "call"}, "")) pattern_TxService_TxQuery_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tx_query"}, "")) - - pattern_TxService_VerifySignature_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "verify_signature"}, "")) ) var ( @@ -1557,19 +1057,7 @@ var ( forward_TxService_GetSchema_0 = runtime.ForwardResponseMessage - forward_TxService_ApproveValidator_0 = runtime.ForwardResponseMessage - - forward_TxService_ValidatorJoin_0 = runtime.ForwardResponseMessage - - forward_TxService_ValidatorLeave_0 = runtime.ForwardResponseMessage - - forward_TxService_ValidatorJoinStatus_0 = runtime.ForwardResponseMessage - - forward_TxService_CurrentValidators_0 = runtime.ForwardResponseMessage - forward_TxService_Call_0 = runtime.ForwardResponseMessage forward_TxService_TxQuery_0 = runtime.ForwardResponseMessage - - forward_TxService_VerifySignature_0 = runtime.ForwardResponseMessage ) diff --git a/core/rpc/protobuf/tx/v1/service_grpc.pb.go b/core/rpc/protobuf/tx/v1/service_grpc.pb.go index 9806e4adb..bc7355d46 100644 --- a/core/rpc/protobuf/tx/v1/service_grpc.pb.go +++ b/core/rpc/protobuf/tx/v1/service_grpc.pb.go @@ -19,23 +19,17 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - TxService_ChainInfo_FullMethodName = "/tx.TxService/ChainInfo" - TxService_Broadcast_FullMethodName = "/tx.TxService/Broadcast" - TxService_EstimatePrice_FullMethodName = "/tx.TxService/EstimatePrice" - TxService_Query_FullMethodName = "/tx.TxService/Query" - TxService_GetAccount_FullMethodName = "/tx.TxService/GetAccount" - TxService_Ping_FullMethodName = "/tx.TxService/Ping" - TxService_GetConfig_FullMethodName = "/tx.TxService/GetConfig" - TxService_ListDatabases_FullMethodName = "/tx.TxService/ListDatabases" - TxService_GetSchema_FullMethodName = "/tx.TxService/GetSchema" - TxService_ApproveValidator_FullMethodName = "/tx.TxService/ApproveValidator" - TxService_ValidatorJoin_FullMethodName = "/tx.TxService/ValidatorJoin" - TxService_ValidatorLeave_FullMethodName = "/tx.TxService/ValidatorLeave" - TxService_ValidatorJoinStatus_FullMethodName = "/tx.TxService/ValidatorJoinStatus" - TxService_CurrentValidators_FullMethodName = "/tx.TxService/CurrentValidators" - TxService_Call_FullMethodName = "/tx.TxService/Call" - TxService_TxQuery_FullMethodName = "/tx.TxService/TxQuery" - TxService_VerifySignature_FullMethodName = "/tx.TxService/VerifySignature" + TxService_ChainInfo_FullMethodName = "/tx.TxService/ChainInfo" + TxService_Broadcast_FullMethodName = "/tx.TxService/Broadcast" + TxService_EstimatePrice_FullMethodName = "/tx.TxService/EstimatePrice" + TxService_Query_FullMethodName = "/tx.TxService/Query" + TxService_GetAccount_FullMethodName = "/tx.TxService/GetAccount" + TxService_Ping_FullMethodName = "/tx.TxService/Ping" + TxService_GetConfig_FullMethodName = "/tx.TxService/GetConfig" + TxService_ListDatabases_FullMethodName = "/tx.TxService/ListDatabases" + TxService_GetSchema_FullMethodName = "/tx.TxService/GetSchema" + TxService_Call_FullMethodName = "/tx.TxService/Call" + TxService_TxQuery_FullMethodName = "/tx.TxService/TxQuery" ) // TxServiceClient is the client API for TxService service. @@ -51,14 +45,8 @@ type TxServiceClient interface { GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) ListDatabases(ctx context.Context, in *ListDatabasesRequest, opts ...grpc.CallOption) (*ListDatabasesResponse, error) GetSchema(ctx context.Context, in *GetSchemaRequest, opts ...grpc.CallOption) (*GetSchemaResponse, error) - ApproveValidator(ctx context.Context, in *ValidatorApprovalRequest, opts ...grpc.CallOption) (*ValidatorApprovalResponse, error) - ValidatorJoin(ctx context.Context, in *ValidatorJoinRequest, opts ...grpc.CallOption) (*ValidatorJoinResponse, error) - ValidatorLeave(ctx context.Context, in *ValidatorLeaveRequest, opts ...grpc.CallOption) (*ValidatorLeaveResponse, error) - ValidatorJoinStatus(ctx context.Context, in *ValidatorJoinStatusRequest, opts ...grpc.CallOption) (*ValidatorJoinStatusResponse, error) - CurrentValidators(ctx context.Context, in *CurrentValidatorsRequest, opts ...grpc.CallOption) (*CurrentValidatorsResponse, error) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) TxQuery(ctx context.Context, in *TxQueryRequest, opts ...grpc.CallOption) (*TxQueryResponse, error) - VerifySignature(ctx context.Context, in *VerifySignatureRequest, opts ...grpc.CallOption) (*VerifySignatureResponse, error) } type txServiceClient struct { @@ -150,51 +138,6 @@ func (c *txServiceClient) GetSchema(ctx context.Context, in *GetSchemaRequest, o return out, nil } -func (c *txServiceClient) ApproveValidator(ctx context.Context, in *ValidatorApprovalRequest, opts ...grpc.CallOption) (*ValidatorApprovalResponse, error) { - out := new(ValidatorApprovalResponse) - err := c.cc.Invoke(ctx, TxService_ApproveValidator_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *txServiceClient) ValidatorJoin(ctx context.Context, in *ValidatorJoinRequest, opts ...grpc.CallOption) (*ValidatorJoinResponse, error) { - out := new(ValidatorJoinResponse) - err := c.cc.Invoke(ctx, TxService_ValidatorJoin_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *txServiceClient) ValidatorLeave(ctx context.Context, in *ValidatorLeaveRequest, opts ...grpc.CallOption) (*ValidatorLeaveResponse, error) { - out := new(ValidatorLeaveResponse) - err := c.cc.Invoke(ctx, TxService_ValidatorLeave_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *txServiceClient) ValidatorJoinStatus(ctx context.Context, in *ValidatorJoinStatusRequest, opts ...grpc.CallOption) (*ValidatorJoinStatusResponse, error) { - out := new(ValidatorJoinStatusResponse) - err := c.cc.Invoke(ctx, TxService_ValidatorJoinStatus_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *txServiceClient) CurrentValidators(ctx context.Context, in *CurrentValidatorsRequest, opts ...grpc.CallOption) (*CurrentValidatorsResponse, error) { - out := new(CurrentValidatorsResponse) - err := c.cc.Invoke(ctx, TxService_CurrentValidators_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *txServiceClient) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) { out := new(CallResponse) err := c.cc.Invoke(ctx, TxService_Call_FullMethodName, in, out, opts...) @@ -213,15 +156,6 @@ func (c *txServiceClient) TxQuery(ctx context.Context, in *TxQueryRequest, opts return out, nil } -func (c *txServiceClient) VerifySignature(ctx context.Context, in *VerifySignatureRequest, opts ...grpc.CallOption) (*VerifySignatureResponse, error) { - out := new(VerifySignatureResponse) - err := c.cc.Invoke(ctx, TxService_VerifySignature_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // TxServiceServer is the server API for TxService service. // All implementations must embed UnimplementedTxServiceServer // for forward compatibility @@ -235,14 +169,8 @@ type TxServiceServer interface { GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) ListDatabases(context.Context, *ListDatabasesRequest) (*ListDatabasesResponse, error) GetSchema(context.Context, *GetSchemaRequest) (*GetSchemaResponse, error) - ApproveValidator(context.Context, *ValidatorApprovalRequest) (*ValidatorApprovalResponse, error) - ValidatorJoin(context.Context, *ValidatorJoinRequest) (*ValidatorJoinResponse, error) - ValidatorLeave(context.Context, *ValidatorLeaveRequest) (*ValidatorLeaveResponse, error) - ValidatorJoinStatus(context.Context, *ValidatorJoinStatusRequest) (*ValidatorJoinStatusResponse, error) - CurrentValidators(context.Context, *CurrentValidatorsRequest) (*CurrentValidatorsResponse, error) Call(context.Context, *CallRequest) (*CallResponse, error) TxQuery(context.Context, *TxQueryRequest) (*TxQueryResponse, error) - VerifySignature(context.Context, *VerifySignatureRequest) (*VerifySignatureResponse, error) mustEmbedUnimplementedTxServiceServer() } @@ -277,30 +205,12 @@ func (UnimplementedTxServiceServer) ListDatabases(context.Context, *ListDatabase func (UnimplementedTxServiceServer) GetSchema(context.Context, *GetSchemaRequest) (*GetSchemaResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSchema not implemented") } -func (UnimplementedTxServiceServer) ApproveValidator(context.Context, *ValidatorApprovalRequest) (*ValidatorApprovalResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ApproveValidator not implemented") -} -func (UnimplementedTxServiceServer) ValidatorJoin(context.Context, *ValidatorJoinRequest) (*ValidatorJoinResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ValidatorJoin not implemented") -} -func (UnimplementedTxServiceServer) ValidatorLeave(context.Context, *ValidatorLeaveRequest) (*ValidatorLeaveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ValidatorLeave not implemented") -} -func (UnimplementedTxServiceServer) ValidatorJoinStatus(context.Context, *ValidatorJoinStatusRequest) (*ValidatorJoinStatusResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ValidatorJoinStatus not implemented") -} -func (UnimplementedTxServiceServer) CurrentValidators(context.Context, *CurrentValidatorsRequest) (*CurrentValidatorsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CurrentValidators not implemented") -} func (UnimplementedTxServiceServer) Call(context.Context, *CallRequest) (*CallResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Call not implemented") } func (UnimplementedTxServiceServer) TxQuery(context.Context, *TxQueryRequest) (*TxQueryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TxQuery not implemented") } -func (UnimplementedTxServiceServer) VerifySignature(context.Context, *VerifySignatureRequest) (*VerifySignatureResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method VerifySignature not implemented") -} func (UnimplementedTxServiceServer) mustEmbedUnimplementedTxServiceServer() {} // UnsafeTxServiceServer may be embedded to opt out of forward compatibility for this service. @@ -476,96 +386,6 @@ func _TxService_GetSchema_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } -func _TxService_ApproveValidator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidatorApprovalRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).ApproveValidator(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_ApproveValidator_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).ApproveValidator(ctx, req.(*ValidatorApprovalRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TxService_ValidatorJoin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidatorJoinRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).ValidatorJoin(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_ValidatorJoin_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).ValidatorJoin(ctx, req.(*ValidatorJoinRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TxService_ValidatorLeave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidatorLeaveRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).ValidatorLeave(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_ValidatorLeave_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).ValidatorLeave(ctx, req.(*ValidatorLeaveRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TxService_ValidatorJoinStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidatorJoinStatusRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).ValidatorJoinStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_ValidatorJoinStatus_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).ValidatorJoinStatus(ctx, req.(*ValidatorJoinStatusRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TxService_CurrentValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CurrentValidatorsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).CurrentValidators(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_CurrentValidators_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).CurrentValidators(ctx, req.(*CurrentValidatorsRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _TxService_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CallRequest) if err := dec(in); err != nil { @@ -602,24 +422,6 @@ func _TxService_TxQuery_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } -func _TxService_VerifySignature_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(VerifySignatureRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TxServiceServer).VerifySignature(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: TxService_VerifySignature_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TxServiceServer).VerifySignature(ctx, req.(*VerifySignatureRequest)) - } - return interceptor(ctx, in, info, handler) -} - // TxService_ServiceDesc is the grpc.ServiceDesc for TxService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -663,26 +465,6 @@ var TxService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetSchema", Handler: _TxService_GetSchema_Handler, }, - { - MethodName: "ApproveValidator", - Handler: _TxService_ApproveValidator_Handler, - }, - { - MethodName: "ValidatorJoin", - Handler: _TxService_ValidatorJoin_Handler, - }, - { - MethodName: "ValidatorLeave", - Handler: _TxService_ValidatorLeave_Handler, - }, - { - MethodName: "ValidatorJoinStatus", - Handler: _TxService_ValidatorJoinStatus_Handler, - }, - { - MethodName: "CurrentValidators", - Handler: _TxService_CurrentValidators_Handler, - }, { MethodName: "Call", Handler: _TxService_Call_Handler, @@ -691,10 +473,6 @@ var TxService_ServiceDesc = grpc.ServiceDesc{ MethodName: "TxQuery", Handler: _TxService_TxQuery_Handler, }, - { - MethodName: "VerifySignature", - Handler: _TxService_VerifySignature_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "kwil/tx/v1/service.proto", diff --git a/core/rpc/protobuf/tx/v1/signature.pb.go b/core/rpc/protobuf/tx/v1/signature.pb.go index 49edc3292..eed8714e8 100644 --- a/core/rpc/protobuf/tx/v1/signature.pb.go +++ b/core/rpc/protobuf/tx/v1/signature.pb.go @@ -75,124 +75,6 @@ func (x *Signature) GetSignatureType() string { return "" } -type VerifySignatureRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Signature *Signature `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - Msg []byte `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"` -} - -func (x *VerifySignatureRequest) Reset() { - *x = VerifySignatureRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_kwil_tx_v1_signature_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VerifySignatureRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VerifySignatureRequest) ProtoMessage() {} - -func (x *VerifySignatureRequest) ProtoReflect() protoreflect.Message { - mi := &file_kwil_tx_v1_signature_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VerifySignatureRequest.ProtoReflect.Descriptor instead. -func (*VerifySignatureRequest) Descriptor() ([]byte, []int) { - return file_kwil_tx_v1_signature_proto_rawDescGZIP(), []int{1} -} - -func (x *VerifySignatureRequest) GetSignature() *Signature { - if x != nil { - return x.Signature - } - return nil -} - -func (x *VerifySignatureRequest) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil -} - -func (x *VerifySignatureRequest) GetMsg() []byte { - if x != nil { - return x.Msg - } - return nil -} - -type VerifySignatureResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *VerifySignatureResponse) Reset() { - *x = VerifySignatureResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_kwil_tx_v1_signature_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VerifySignatureResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VerifySignatureResponse) ProtoMessage() {} - -func (x *VerifySignatureResponse) ProtoReflect() protoreflect.Message { - mi := &file_kwil_tx_v1_signature_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VerifySignatureResponse.ProtoReflect.Descriptor instead. -func (*VerifySignatureResponse) Descriptor() ([]byte, []int) { - return file_kwil_tx_v1_signature_proto_rawDescGZIP(), []int{2} -} - -func (x *VerifySignatureResponse) GetValid() bool { - if x != nil { - return x.Valid - } - return false -} - -func (x *VerifySignatureResponse) GetError() string { - if x != nil { - return x.Error - } - return "" -} - var File_kwil_tx_v1_signature_proto protoreflect.FileDescriptor var file_kwil_tx_v1_signature_proto_rawDesc = []byte{ @@ -203,23 +85,12 @@ var file_kwil_tx_v1_signature_proto_rawDesc = []byte{ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x6f, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, - 0x78, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x10, - 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, - 0x22, 0x45, 0x0a, 0x17, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, - 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, - 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, + 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, + 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -234,19 +105,16 @@ func file_kwil_tx_v1_signature_proto_rawDescGZIP() []byte { return file_kwil_tx_v1_signature_proto_rawDescData } -var file_kwil_tx_v1_signature_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_kwil_tx_v1_signature_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_kwil_tx_v1_signature_proto_goTypes = []interface{}{ - (*Signature)(nil), // 0: tx.Signature - (*VerifySignatureRequest)(nil), // 1: tx.VerifySignatureRequest - (*VerifySignatureResponse)(nil), // 2: tx.VerifySignatureResponse + (*Signature)(nil), // 0: tx.Signature } var file_kwil_tx_v1_signature_proto_depIdxs = []int32{ - 0, // 0: tx.VerifySignatureRequest.signature:type_name -> tx.Signature - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_kwil_tx_v1_signature_proto_init() } @@ -267,30 +135,6 @@ func file_kwil_tx_v1_signature_proto_init() { return nil } } - file_kwil_tx_v1_signature_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifySignatureRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_kwil_tx_v1_signature_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerifySignatureResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -298,7 +142,7 @@ func file_kwil_tx_v1_signature_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kwil_tx_v1_signature_proto_rawDesc, NumEnums: 0, - NumMessages: 3, + NumMessages: 1, NumExtensions: 0, NumServices: 0, }, diff --git a/core/rpc/transport/grpc.go b/core/rpc/transport/grpc.go index 1a590b888..020d4d5f8 100644 --- a/core/rpc/transport/grpc.go +++ b/core/rpc/transport/grpc.go @@ -32,17 +32,9 @@ type TimeOutOption struct { } type GrpcTransport struct { - tlsOpts *TlsOption timeout TimeOutOption } -func NewGrpcTransport(tlsOpts *TlsOption, timeout TimeOutOption) *GrpcTransport { - return &GrpcTransport{ - tlsOpts: tlsOpts, - timeout: timeout, - } -} - func (t *GrpcTransport) Dial(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { options := append([]grpc.DialOption{ grpc.WithBlock(), @@ -72,11 +64,15 @@ func (t *GrpcTransport) Dial(ctx context.Context, address string, opts ...grpc.D return conn, err } - func Dial(ctx context.Context, address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { timeout := TimeOutOption{ Dial: DefaultDialTimeout, Request: DefaultRequestTimeout, } - return NewGrpcTransport(nil, timeout).Dial(ctx, address, opts...) + + t := &GrpcTransport{ + timeout: timeout, + } + + return t.Dial(ctx, address, opts...) } diff --git a/core/types/admin/types.go b/core/types/admin/types.go index 593710159..6f1594651 100644 --- a/core/types/admin/types.go +++ b/core/types/admin/types.go @@ -35,9 +35,8 @@ type SyncInfo struct { // ValidatorInfo describes a validator node. type ValidatorInfo struct { - PubKey types.HexBytes `json:"pubkey"` - PubKeyType string `json:"pubkey_type"` - Power int64 `json:"power"` + PubKey types.HexBytes `json:"pubkey"` + Power int64 `json:"power"` } // Status includes a comprehensive summary of a nodes status, including if the diff --git a/core/types/gateway/gateway.go b/core/types/gateway/gateway.go new file mode 100644 index 000000000..75e291333 --- /dev/null +++ b/core/types/gateway/gateway.go @@ -0,0 +1,21 @@ +package gateway + +import "github.com/kwilteam/kwil-db/core/crypto/auth" + +// GatewayAuth is a request for authentication from the +// kwil gateway. +type GatewayAuth struct { + Nonce string `json:"nonce"` // identifier for authn session + Sender []byte `json:"sender"` // sender public key + Signature *auth.Signature `json:"signature"` +} + +// GatewayAuthParameter defines the result of GET request for gateway(KGW) +// authentication. It's the parameters that will be used to compose the +// message(SIWE like) to sign. +type GatewayAuthParameter struct { + Nonce string `json:"nonce"` + Statement string `json:"statement"` // optional + IssueAt string `json:"issue_at"` + ExpirationTime string `json:"expiration_time"` +} diff --git a/core/types/types.go b/core/types/types.go index 3c8128513..145001b40 100644 --- a/core/types/types.go +++ b/core/types/types.go @@ -22,29 +22,37 @@ const ( // ChainInfo describes the current status of a Kwil blockchain. type ChainInfo struct { - ChainID string - BlockHeight uint64 - BlockHash string + ChainID string `json:"chain_id"` + BlockHeight uint64 `json:"block_height"` + BlockHash string `json:"block_hash"` } type JoinRequest struct { - Candidate []byte // pubkey of the candidate validator - Power int64 // the requested power - ExpiresAt int64 // the block height at which the join request expires - Board [][]byte // slice of pubkeys of all the eligible voting validators - Approved []bool // if they approved + Candidate []byte `json:"candidate"` // pubkey of the candidate validator + Power int64 `json:"power"` // the requested power + ExpiresAt int64 `json:"expires_at"` // the block height at which the join request expires + Board [][]byte `json:"board"` // slice of pubkeys of all the eligible voting validators + Approved []bool `json:"approved"` // slice of bools indicating if the corresponding validator approved } type Validator struct { - PubKey []byte - Power int64 + PubKey []byte `json:"pubkey"` + Power int64 `json:"power"` } // ValidatorRemoveProposal is a proposal from an existing validator (remover) to // remove a validator (the target) from the validator set. type ValidatorRemoveProposal struct { - Target []byte - Remover []byte + Target []byte `json:"target"` // pubkey of the validator to remove + Remover []byte `json:"remover"` // pubkey of the validator proposing the removal +} + +// NodeInfo contains public information about a node. +// It can be used by clients to join as a peer. +type NodeInfo struct { + NodeID string `json:"node_id"` + PublicKey HexBytes `json:"pubkey"` + P2PListenAddress string `json:"p2p_listen_address"` } func (v *Validator) String() string { diff --git a/core/utils/url/errors.go b/core/utils/url/errors.go new file mode 100644 index 000000000..98e374f5d --- /dev/null +++ b/core/utils/url/errors.go @@ -0,0 +1,7 @@ +package url + +import "errors" + +var ( + ErrUnknownScheme = errors.New("unknown scheme") +) diff --git a/core/utils/url/url.go b/core/utils/url/url.go new file mode 100644 index 000000000..64f67ac08 --- /dev/null +++ b/core/utils/url/url.go @@ -0,0 +1,134 @@ +// package url provides url fuctionalities to provide consistent +// parsing for Kwil clients. +package url + +import ( + "fmt" + "net/url" + "os" + "strconv" + "strings" +) + +// URL is a parsed URL. +type URL struct { + // Original is the original URL string. + Original string + // Scheme is the protocol scheme, such as http or tcp. + Scheme Scheme + // Target is either the host, host:port, or unix socket path. + Target string + // Port is the port number, or 0 if not specified. + Port int +} + +// Scheme is a protocol scheme, such as http or tcp. +type Scheme string + +func (s Scheme) valid() bool { + switch s { + case HTTP, HTTPS, TCP, UNIX: + return true + default: + return false + } +} + +func (s Scheme) String() string { + return string(s) +} + +const ( + HTTP Scheme = "http" + HTTPS Scheme = "https" + TCP Scheme = "tcp" + UNIX Scheme = "unix" +) + +// ParseURL parses a URL string into a URL struct. +// URLs can be of the form: +// - http://localhost:8080 +// - tcp://localhost:8080 +// - localhost:8080 +// - localhost +// - unix:///var/run/kwil.sock +// If the URL does not have a scheme, it is assumed to be a tcp address. +func ParseURL(u string) (*URL, error) { + original := u + // if the url does not have a scheme, assume it's a tcp address + hasScheme, err := hasScheme(u) + if err != nil { + return nil, err + } + if !hasScheme { + u = "tcp://" + u + } + + parsed, err := url.Parse(u) + if err != nil { + return nil, err + } + + scheme := Scheme(parsed.Scheme) + if !scheme.valid() { // I don't think this can error, but just in case + return nil, fmt.Errorf("%w: %s", ErrUnknownScheme, scheme) + } + + var target string + switch scheme { + case UNIX: + target, err = expandPath(parsed.Path) + if err != nil { + return nil, err + } + default: + target = parsed.Host + } + + portString := parsed.Port() + if portString == "" { + portString = "0" + } + port, err := strconv.ParseInt(portString, 10, 32) + if err != nil { + return nil, err + } + + return &URL{ + Original: original, + Scheme: scheme, + Target: target, + Port: int(port), + }, nil +} + +// hasScheme returns true if the url has a known scheme. +func hasScheme(u string) (bool, error) { + parsed, err := url.Parse(u) + if err != nil { + return false, err + } + + switch parsed.Scheme { + case "tcp", "unix", "http", "https": + return true, nil + default: + // see if it can be split by :// + split := strings.Split(u, "://") + if len(split) == 2 { + return false, fmt.Errorf("%w: %s", ErrUnknownScheme, parsed.Scheme) + } + return false, nil + } +} + +func expandPath(path string) (string, error) { + if strings.HasPrefix(path, "~") { + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + return strings.Replace(path, "~", home, 1), nil + } + return path, nil +} diff --git a/core/utils/url/url_test.go b/core/utils/url/url_test.go new file mode 100644 index 000000000..50baa0ab2 --- /dev/null +++ b/core/utils/url/url_test.go @@ -0,0 +1,89 @@ +package url_test + +import ( + "testing" + + "github.com/kwilteam/kwil-db/core/utils/url" + "github.com/stretchr/testify/assert" +) + +func TestParseURL(t *testing.T) { + tests := []struct { + name string + url string + want *url.URL + wantErr error + }{ + { + name: "http", + url: "http://localhost:8080", + want: &url.URL{ + Original: "http://localhost:8080", + Scheme: url.HTTP, + Target: "localhost:8080", + Port: 8080, + }, + }, + { + name: "https, no port", + url: "https://localhost", + want: &url.URL{ + Original: "https://localhost", + Scheme: url.HTTPS, + Target: "localhost", + }, + }, + { + name: "tcp", + url: "tcp://localhost:8080", + want: &url.URL{ + Original: "tcp://localhost:8080", + Scheme: url.TCP, + Target: "localhost:8080", + Port: 8080, + }, + }, + { + name: "no scheme", + url: "localhost:8080", + want: &url.URL{ + Original: "localhost:8080", + Scheme: url.TCP, + Target: "localhost:8080", + Port: 8080, + }, + }, + { + name: "unknown scheme", + url: "foo://localhost:8080", + wantErr: url.ErrUnknownScheme, + }, + { + name: "not localhost", + url: "tcp://0.0.0.0:50151", + want: &url.URL{ + Original: "tcp://0.0.0.0:50151", + Scheme: url.TCP, + Target: "0.0.0.0:50151", + Port: 50151, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := url.ParseURL(tt.url) + if tt.wantErr != nil { + if err == nil { + t.Errorf("ParseURL() error = %v, wantErr %v", err, tt.wantErr) + } + return + } + if err != nil { + t.Errorf("ParseURL() error = %v, wantErr %v", err, tt.wantErr) + return + } + + assert.Equal(t, *got, *tt.want) + }) + } +} diff --git a/deployments/compose/kwil/docker-compose.yml b/deployments/compose/kwil/docker-compose.yml index 298e185eb..80923b902 100644 --- a/deployments/compose/kwil/docker-compose.yml +++ b/deployments/compose/kwil/docker-compose.yml @@ -19,12 +19,12 @@ services: kwilnet: ipv4_address: 172.10.100.2 command: | - --root_dir=/app/.kwild + --root-dir=/app/.kwild --log.level=debug - --app.admin_listen_addr=:50151 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 + --app.admin-listen-addr=:50151 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --chain.p2p.external-address=tcp://0.0.0.0:26656 --chain.rpc.laddr=tcp://0.0.0.0:26657 k2: @@ -45,12 +45,12 @@ services: kwilnet: ipv4_address: 172.10.100.3 command: | - --root_dir=/app/.kwild + --root-dir=/app/.kwild --log.level=debug - --app.admin_listen_addr=:50151 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 + --app.admin-listen-addr=:50151 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --chain.p2p.external-address=tcp://0.0.0.0:26656 --chain.rpc.laddr=tcp://0.0.0.0:26657 k3: @@ -71,12 +71,12 @@ services: kwilnet: ipv4_address: 172.10.100.4 command: | - --root_dir=/app/.kwild + --root-dir=/app/.kwild --log.level=debug - --app.admin_listen_addr=:50151 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 + --app.admin-listen-addr=:50151 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --chain.p2p.external-address=tcp://0.0.0.0:26656 --chain.rpc.laddr=tcp://0.0.0.0:26657 diff --git a/go.mod b/go.mod index b56b677e2..40e662961 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ replace ( ) require ( - github.com/alexflint/go-arg v1.4.3 + dario.cat/mergo v1.0.0 github.com/alexliesenfeld/health v0.6.0 github.com/cometbft/cometbft v0.37.2 github.com/cosmos/gogoproto v1.4.11 @@ -21,8 +21,10 @@ require ( github.com/kwilteam/kwil-db/parse v0.0.0 github.com/kwilteam/kwil-extensions v0.0.0-20230727040522-1cfd930226b7 github.com/manifoldco/promptui v0.9.0 + github.com/mitchellh/mapstructure v1.5.0 github.com/near/borsh-go v0.3.1 github.com/olekukonko/tablewriter v0.0.5 + github.com/pelletier/go-toml/v2 v2.0.5 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.14.0 @@ -36,7 +38,7 @@ require ( ) require ( - github.com/alexflint/go-scalar v1.1.0 // indirect + github.com/antihax/optional v1.0.0 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.5.0 // indirect @@ -92,13 +94,11 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/highwayhash v1.0.2 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/onsi/gomega v1.23.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/opencontainers/runc v1.1.7 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -122,11 +122,13 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.13.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231009173412-8bfb1ae86b6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 18936dcf5..d4957002b 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -58,12 +60,10 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= -github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo= -github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA= -github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM= -github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= github.com/alexliesenfeld/health v0.6.0 h1:HRBTCgybNSe4lqGEk7nU82c3bjwh9W+3b46W6UvD4CQ= github.com/alexliesenfeld/health v0.6.0/go.mod h1:N4NDIeQtlWumG+6z1ne1v62eQxktz5ylEgGgH9emdMw= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -500,8 +500,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -574,8 +574,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -585,6 +585,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -646,8 +648,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -655,8 +657,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -740,6 +742,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/internal/abci/cometbft/genesis.go b/internal/abci/cometbft/genesis.go index d88495098..e0a987644 100644 --- a/internal/abci/cometbft/genesis.go +++ b/internal/abci/cometbft/genesis.go @@ -10,21 +10,11 @@ import ( // e.g. With "abci" a the chain root directory set in cometbft's config, // this give the paths "abci/config/genesis.json" and "abci/data". const ( - ConfigDir = "config" DataDir = "data" GenesisJSONName = "genesis.json" AddrBookFileName = "addrbook.json" ) -// GenesisPath returns the path of the genesis file given a chain root -// directory. e.g. Given the path to the "abci" folder: -// /config/genesis.json -func GenesisPath(chainRootDir string) string { - abciCfgDir := filepath.Join(chainRootDir, ConfigDir) - return filepath.Join(abciCfgDir, GenesisJSONName) -} - func AddrBookPath(chainRootDir string) string { - abciCfgDir := filepath.Join(chainRootDir, ConfigDir) - return filepath.Join(abciCfgDir, AddrBookFileName) + return filepath.Join(chainRootDir, AddrBookFileName) } diff --git a/internal/abci/utils.go b/internal/abci/utils.go index 96f518b68..721086b10 100644 --- a/internal/abci/utils.go +++ b/internal/abci/utils.go @@ -69,20 +69,69 @@ func abciStatus(status snapshots.Status) abciTypes.ResponseApplySnapshotChunk_Re } } -func PrintPrivKeyInfo(privateKey []byte) { +func PrivKeyInfo(privateKey []byte) *PrivateKeyInfo { priv := ed25519.PrivKey(privateKey) pub := priv.PubKey().(ed25519.PubKey) nodeID := p2p.PubKeyToID(pub) - fmt.Printf("Private key (hex): %s\n", hex.EncodeToString(priv.Bytes())) - fmt.Printf("Private key (base64): %s\n", - base64.StdEncoding.EncodeToString(priv.Bytes())) // "value" in abci/config/node_key.json - fmt.Printf("Public key (base64): %s\n", - base64.StdEncoding.EncodeToString(pub.Bytes())) // "validators.pub_key.value" in abci/config/genesis.json - fmt.Printf("Public key (cometized hex): %v\n", pub.String()) // for reference with some cometbft logs - fmt.Printf("Public key (plain hex): %v\n", hex.EncodeToString(pub.Bytes())) // for reference with some cometbft logs - fmt.Printf("Address (string): %s\n", pub.Address().String()) // "validators.address" in abci/config/genesis.json - fmt.Printf("Node ID: %v\n", nodeID) // same as address, just upper case + return &PrivateKeyInfo{ + PrivateKeyHex: hex.EncodeToString(priv.Bytes()), + PrivateKeyBase64: base64.StdEncoding.EncodeToString(priv.Bytes()), + PublicKeyBase64: base64.StdEncoding.EncodeToString(pub.Bytes()), + PublicKeyCometizedHex: pub.String(), + PublicKeyPlainHex: hex.EncodeToString(pub.Bytes()), + Address: pub.Address().String(), + NodeID: fmt.Sprintf("%v", nodeID), // same as address, just upper case + } +} + +type PrivateKeyInfo struct { + PrivateKeyHex string `json:"private_key_hex"` + PrivateKeyBase64 string `json:"private_key_base64"` + PublicKeyBase64 string `json:"public_key_base64"` + PublicKeyCometizedHex string `json:"public_key_cometized_hex"` + PublicKeyPlainHex string `json:"public_key_plain_hex"` + Address string `json:"address"` + NodeID string `json:"node_id"` +} + +func (p *PrivateKeyInfo) MarshalJSON() ([]byte, error) { + // must use anonymous struct to avoid infinite recursion + return json.Marshal(struct { + PrivateKeyHex string `json:"private_key_hex"` + PrivateKeyBase64 string `json:"private_key_base64"` + PublicKeyBase64 string `json:"public_key_base64"` + PublicKeyCometizedHex string `json:"public_key_cometized_hex"` + PublicKeyPlainHex string `json:"public_key_plain_hex"` + Address string `json:"address"` + NodeID string `json:"node_id"` + }{ + PrivateKeyHex: p.PrivateKeyHex, + PrivateKeyBase64: p.PrivateKeyBase64, + PublicKeyBase64: p.PublicKeyBase64, + PublicKeyCometizedHex: p.PublicKeyCometizedHex, + PublicKeyPlainHex: p.PublicKeyPlainHex, + Address: p.Address, + NodeID: p.NodeID, + }) +} + +func (p *PrivateKeyInfo) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf(`Private key (hex): %s +Private key (base64): %s +Public key (base64): %s +Public key (cometized hex): %v +Public key (plain hex): %v +Address (string): %s +Node ID: %v`, + p.PrivateKeyHex, + p.PrivateKeyBase64, + p.PublicKeyBase64, + p.PublicKeyCometizedHex, + p.PublicKeyPlainHex, + p.Address, + p.NodeID, + )), nil } func GeneratePrivateKey() []byte { diff --git a/internal/admin/admin.go b/internal/admin/admin.go deleted file mode 100644 index fbb26d36b..000000000 --- a/internal/admin/admin.go +++ /dev/null @@ -1,96 +0,0 @@ -// Package admin provides a client for communicating with an authenticated -// administrative gRPC service on a running kwild instance. This is presently to -// be used by kwil-admin, but it could be made part of our public API, perhaps -// in the client (SDK) package, once fleshed out a little more. -package admin - -import ( - "context" - - "github.com/kwilteam/kwil-db/core/crypto/auth" - "github.com/kwilteam/kwil-db/core/log" - admClient "github.com/kwilteam/kwil-db/core/rpc/client/admin" - types "github.com/kwilteam/kwil-db/core/types/admin" - - "go.uber.org/zap" -) - -// Client is performs node administrative actions via the authenticated gRPC -// service on a running kwild node. -type Client struct { - client *admClient.AdminClient - signer auth.Signer // for use in methods that require signing a transaction with a Kwil account - logger log.Logger -} - -// New creates a new admin client. TLS is required so the kwild TLS certificate -// is required. Authentication is done at the protocol level (mTLS), so our own -// key pair is also required. The server must have our client certificate loaded -// in it's own tls.Config.ClientCAs. This client keypair can be thought of as a -// preshared key (like a password or token), but handled automatically by the -// TLS handshake, thus requiring no application level logic such as transmitting -// a pass/token with each request. -func New(host string, kwildCertFile, clientKeyFile, clientCertFile string, opts ...ClientOpt) (c *Client, err error) { - c = &Client{ - logger: log.NewNoOp(), - } - - for _, opt := range opts { - opt(c) - } - - tlsConfig, err := newAuthenticatedTLSConfig(kwildCertFile, clientCertFile, clientKeyFile) - if err != nil { - return nil, err - } - c.client, err = admClient.New(host, tlsConfig) - if err != nil { - return nil, err - } - - c.logger = *c.logger.Named("admin").With(zap.String("host", host)) - - return c, nil -} - -func (c *Client) Close() error { - return c.client.Close() -} - -func (c *Client) Ping(ctx context.Context) (string, error) { - return c.client.Ping(ctx) -} - -func (c *Client) Version(ctx context.Context) (string, error) { - return c.client.Version(ctx) -} - -func (c *Client) Status(ctx context.Context) (*types.Status, error) { - return c.client.Status(ctx) -} - -func (c *Client) Peers(ctx context.Context) ([]*types.PeerInfo, error) { - return c.client.Peers(ctx) -} - -/* TODO: validator actions that work via server-side transaction authoring - rather that client-side authoring followed by broadcast via the public tx - service. - -func (c *Client) ApproveValidator(ctx context.Context, joiner []byte) ([]byte, error) { - _, err := crypto.Ed25519PublicKeyFromBytes(joiner) if err != nil { - return nil, fmt.Errorf("invalid candidate validator public key: %w", err) - } - - ... -} - -func (c *Client) ValidatorJoin(ctx context.Context) ([]byte, error) { - ... -} - -func (c *Client) ValidatorLeave(ctx context.Context) ([]byte, error) { return - ... -} - -*/ diff --git a/internal/admin/opts.go b/internal/admin/opts.go deleted file mode 100644 index 5271d0bd5..000000000 --- a/internal/admin/opts.go +++ /dev/null @@ -1,20 +0,0 @@ -package admin - -import ( - "github.com/kwilteam/kwil-db/core/crypto/auth" - "github.com/kwilteam/kwil-db/core/log" -) - -type ClientOpt func(*Client) - -func WithLogger(logger log.Logger) ClientOpt { - return func(c *Client) { - c.logger = logger - } -} - -func WithSigner(signer auth.Signer) ClientOpt { - return func(c *Client) { - c.signer = signer - } -} diff --git a/internal/admin/tls.go b/internal/admin/tls.go deleted file mode 100644 index 19d3bb13e..000000000 --- a/internal/admin/tls.go +++ /dev/null @@ -1,26 +0,0 @@ -package admin - -import ( - "crypto/tls" - - "github.com/kwilteam/kwil-db/core/rpc/transport" -) - -// newAuthenticatedTLSConfig creates a new tls.Config for an -// mutually-authenticated TLS (mTLS) client. In addition to the server's -// certificate file, the client's own key pair is required to support protocol -// level client authentication. -func newAuthenticatedTLSConfig(kwildCertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) { - cfg, err := transport.NewClientTLSConfigFromFile(kwildCertFile) - if err != nil { - return nil, err - } - - authCert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile) - if err != nil { - return nil, err - } - cfg.Certificates = append(cfg.Certificates, authCert) - - return cfg, nil -} diff --git a/internal/services/grpc/admin/v0/service.go b/internal/services/grpc/admin/v0/service.go index c63989f22..33146722d 100644 --- a/internal/services/grpc/admin/v0/service.go +++ b/internal/services/grpc/admin/v0/service.go @@ -1,19 +1,50 @@ package admin import ( + "bytes" "context" + "encoding/hex" + "math/big" + "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" + txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" types "github.com/kwilteam/kwil-db/core/types/admin" + "github.com/kwilteam/kwil-db/core/types/transactions" + "github.com/kwilteam/kwil-db/internal/validators" "github.com/kwilteam/kwil-db/internal/version" + "go.uber.org/zap" + spb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/anypb" ) -// Node specifies the methods required for the admin service to access -// information from the network node. -type Node interface { +// BlockchainTransactor specifies the methods required for the admin service to +// interact with the blockchain. +type BlockchainTransactor interface { Status(context.Context) (*types.Status, error) Peers(context.Context) ([]*types.PeerInfo, error) + BroadcastTx(ctx context.Context, tx []byte, sync uint8) (code uint32, txHash []byte, err error) +} + +// NodeApplication is the abci application that is running on the node. +type NodeApplication interface { + ChainID() string + // AccountInfo returns the unconfirmed account info for the given identifier. + AccountInfo(ctx context.Context, identifier []byte) (balance *big.Int, nonce int64, err error) +} + +// ValidatorReader reads data about the validator store. +type ValidatorReader interface { + CurrentValidators(ctx context.Context) ([]*validators.Validator, error) + ActiveVotes(ctx context.Context) ([]*validators.JoinRequest, []*validators.ValidatorRemoveProposal, error) + // JoinStatus(ctx context.Context, joiner []byte) ([]*JoinRequest, error) + PriceJoin(ctx context.Context) (*big.Int, error) + PriceLeave(ctx context.Context) (*big.Int, error) + PriceApprove(ctx context.Context) (*big.Int, error) + PriceRemove(ctx context.Context) (*big.Int, error) } type AdminSvcOpt func(*Service) @@ -27,16 +58,25 @@ func WithLogger(logger log.Logger) AdminSvcOpt { // Service is the implementation of the admpb.AdminServiceServer methods. type Service struct { admpb.UnimplementedAdminServiceServer - node Node + blockchain BlockchainTransactor // node is the local node that can accept transactions. + nodeApp NodeApplication + validators ValidatorReader log log.Logger + + signer auth.Signer // signer is an ed25519 signer derived from the nodes private key. } +var _ admpb.AdminServiceServer = (*Service)(nil) + // NewService constructs a new Service. -func NewService(node Node, opts ...AdminSvcOpt) *Service { +func NewService(blockchain BlockchainTransactor, node NodeApplication, validators ValidatorReader, signer auth.Signer, opts ...AdminSvcOpt) *Service { s := &Service{ - node: node, - log: log.NewNoOp(), + blockchain: blockchain, + nodeApp: node, + validators: validators, + signer: signer, + log: log.NewNoOp(), } for _, opt := range opts { @@ -46,11 +86,6 @@ func NewService(node Node, opts ...AdminSvcOpt) *Service { return s } -// Ping responds to any ping request with "pong". -func (svc *Service) Ping(ctx context.Context, req *admpb.PingRequest) (*admpb.PingResponse, error) { - return &admpb.PingResponse{Message: "pong"}, nil -} - // Version reports the compile-time kwild version. func (svc *Service) Version(ctx context.Context, req *admpb.VersionRequest) (*admpb.VersionResponse, error) { return &admpb.VersionResponse{ @@ -71,11 +106,10 @@ func convertNodeInfo(ni *types.NodeInfo) *admpb.NodeInfo { } } -func convertValidatorInfo(vi *types.ValidatorInfo) *admpb.ValidatorInfo { - return &admpb.ValidatorInfo{ - Pubkey: vi.PubKey, - PubkeyType: vi.PubKeyType, - Power: vi.Power, +func convertValidatorInfo(vi *types.ValidatorInfo) *admpb.Validator { + return &admpb.Validator{ + Pubkey: vi.PubKey, + Power: vi.Power, } } @@ -90,7 +124,7 @@ func convertSyncInfo(si *types.SyncInfo) *admpb.SyncInfo { } func (svc *Service) Status(ctx context.Context, req *admpb.StatusRequest) (*admpb.StatusResponse, error) { - status, err := svc.node.Status(ctx) + status, err := svc.blockchain.Status(ctx) if err != nil { return nil, err } @@ -102,7 +136,7 @@ func (svc *Service) Status(ctx context.Context, req *admpb.StatusRequest) (*admp } func (svc *Service) Peers(ctx context.Context, req *admpb.PeersRequest) (*admpb.PeersResponse, error) { - peers, err := svc.node.Peers(ctx) + peers, err := svc.blockchain.Peers(ctx) if err != nil { return nil, err } @@ -119,4 +153,176 @@ func (svc *Service) Peers(ctx context.Context, req *admpb.PeersRequest) (*admpb. }, nil } -// Peers(context.Context, *PeersRequest) (*PeersResponse, error) +// sendTx makes a transaction and sends it to the local node. +func (s *Service) sendTx(ctx context.Context, payload transactions.Payload, price *big.Int) (*txpb.BroadcastResponse, error) { + // Get the latest nonce for the account, if it exists. + _, nonce, err := s.nodeApp.AccountInfo(ctx, s.signer.Identity()) + if err != nil { + return nil, err + } + + tx, err := transactions.CreateTransaction(payload, s.nodeApp.ChainID(), uint64(nonce+1)) + if err != nil { + return nil, err + } + + tx.Body.Fee = price + + // Sign the transaction. + err = tx.Sign(s.signer) + if err != nil { + return nil, err + } + + encodedTx, err := tx.MarshalBinary() + if err != nil { + return nil, err + } + + // Broadcast the transaction. + code, txHash, err := s.blockchain.BroadcastTx(ctx, encodedTx, 1) + if err != nil { + return nil, err + } + + if txCode := transactions.TxCode(code); txCode != transactions.CodeOk { + stat := &spb.Status{ + Code: int32(codes.InvalidArgument), + Message: "broadcast error", + } + if details, err := anypb.New(&txpb.BroadcastErrorDetails{ + Code: code, // e.g. invalid nonce, wrong chain, etc. + Hash: hex.EncodeToString(txHash), + Message: txCode.String(), + }); err != nil { + s.log.Error("failed to marshal broadcast error details", zap.Error(err)) + } else { + stat.Details = append(stat.Details, details) + } + return nil, status.ErrorProto(stat) + } + + return &txpb.BroadcastResponse{ + TxHash: txHash, + }, nil + +} + +func (s *Service) Approve(ctx context.Context, req *admpb.ApproveRequest) (*txpb.BroadcastResponse, error) { + price, err := s.validators.PriceApprove(ctx) + if err != nil { + return nil, err + } + + return s.sendTx(ctx, &transactions.ValidatorApprove{ + Candidate: req.Pubkey, + }, price) +} + +func (s *Service) Join(ctx context.Context, req *admpb.JoinRequest) (*txpb.BroadcastResponse, error) { + price, err := s.validators.PriceJoin(ctx) + if err != nil { + return nil, err + } + + return s.sendTx(ctx, &transactions.ValidatorJoin{ + Power: 1, + }, price) +} + +func (s *Service) Remove(ctx context.Context, req *admpb.RemoveRequest) (*txpb.BroadcastResponse, error) { + price, err := s.validators.PriceRemove(ctx) + if err != nil { + return nil, err + } + + return s.sendTx(ctx, &transactions.ValidatorRemove{ + Validator: req.Pubkey, + }, price) +} + +func (s *Service) JoinStatus(ctx context.Context, req *admpb.JoinStatusRequest) (*admpb.JoinStatusResponse, error) { + joiner := req.Pubkey + allJoins, _, err := s.validators.ActiveVotes(ctx) + if err != nil { + s.log.Error("failed to retrieve active join requests", zap.Error(err)) + return nil, status.Errorf(codes.Internal, "failed to retrieve active join requests") + } + for _, ji := range allJoins { + if bytes.Equal(ji.Candidate, joiner) { + return &admpb.JoinStatusResponse{ + JoinRequest: convertJoinRequest(ji), + }, nil + } + } + + vals, err := s.validators.CurrentValidators(ctx) + if err != nil { + s.log.Error("failed to retrieve current validators", zap.Error(err)) + return nil, status.Errorf(codes.Internal, "failed to retrieve current validators") + } + for _, vi := range vals { + if bytes.Equal(vi.PubKey, joiner) { + return nil, status.Errorf(codes.NotFound, "already a validator") // maybe FailedPrecondition? + } + } + + return nil, status.Errorf(codes.NotFound, "no active join request") +} + +func convertJoinRequest(join *validators.JoinRequest) *admpb.PendingJoin { + resp := &admpb.PendingJoin{ + Candidate: join.Candidate, + Power: join.Power, + ExpiresAt: join.ExpiresAt, + Board: join.Board, + Approved: join.Approved, + } + return resp +} + +func (s *Service) Leave(ctx context.Context, req *admpb.LeaveRequest) (*txpb.BroadcastResponse, error) { + price, err := s.validators.PriceLeave(ctx) + if err != nil { + return nil, err + } + + return s.sendTx(ctx, &transactions.ValidatorLeave{}, price) +} + +func (s *Service) ListValidators(ctx context.Context, req *admpb.ListValidatorsRequest) (*admpb.ListValidatorsResponse, error) { + vals, err := s.validators.CurrentValidators(ctx) + if err != nil { + s.log.Error("failed to retrieve current validators", zap.Error(err)) + return nil, status.Errorf(codes.Internal, "failed to retrieve current validators") + } + + pbValidators := make([]*admpb.Validator, len(vals)) + for i, vi := range vals { + pbValidators[i] = &admpb.Validator{ + Pubkey: vi.PubKey, + Power: vi.Power, + } + } + + return &admpb.ListValidatorsResponse{ + Validators: pbValidators, + }, nil +} + +func (s *Service) ListPendingJoins(ctx context.Context, req *admpb.ListJoinRequestsRequest) (*admpb.ListJoinRequestsResponse, error) { + joins, _, err := s.validators.ActiveVotes(ctx) + if err != nil { + s.log.Error("failed to retrieve active join requests", zap.Error(err)) + return nil, status.Errorf(codes.Internal, "failed to retrieve active join requests") + } + + pbJoins := make([]*admpb.PendingJoin, len(joins)) + for i, ji := range joins { + pbJoins[i] = convertJoinRequest(ji) + } + + return &admpb.ListJoinRequestsResponse{ + JoinRequests: pbJoins, + }, nil +} diff --git a/internal/services/grpc/txsvc/v1/sig_verify.go b/internal/services/grpc/function/v0/service.go similarity index 51% rename from internal/services/grpc/txsvc/v1/sig_verify.go rename to internal/services/grpc/function/v0/service.go index 70d7d2e64..2c79cc65d 100644 --- a/internal/services/grpc/txsvc/v1/sig_verify.go +++ b/internal/services/grpc/function/v0/service.go @@ -1,18 +1,25 @@ -package txsvc +// package function/v0 implements a grpc server for the Kwil function service. +// the function service is used to remotely execute logic that is determined by +// compile time parameters. +package v0 import ( "context" "github.com/kwilteam/kwil-db/core/crypto/auth" - txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" + functionpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/function/v0" "github.com/kwilteam/kwil-db/internal/ident" ) +type FunctionService struct { + functionpb.UnimplementedFunctionServiceServer +} + // VerifySignature checks the signature with the given public key and message. // This only verifies the signature against known kwil-db singing schema, which // is determined by the signature's type. -func (s *Service) VerifySignature(_ context.Context, - req *txpb.VerifySignatureRequest) (*txpb.VerifySignatureResponse, error) { +func (FunctionService) VerifySignature(_ context.Context, + req *functionpb.VerifySignatureRequest) (*functionpb.VerifySignatureResponse, error) { convSignature := auth.Signature{ Signature: req.Signature.SignatureBytes, Type: req.Signature.SignatureType, @@ -20,13 +27,13 @@ func (s *Service) VerifySignature(_ context.Context, err := ident.VerifySignature(req.Sender, req.Msg, &convSignature) if err != nil { - return &txpb.VerifySignatureResponse{ + return &functionpb.VerifySignatureResponse{ Valid: false, Error: err.Error(), }, nil } - return &txpb.VerifySignatureResponse{ + return &functionpb.VerifySignatureResponse{ Valid: true, Error: "", }, nil diff --git a/internal/services/grpc/txsvc/v1/convert.go b/internal/services/grpc/txsvc/v1/convert.go index 69eed8376..fe21a1ad8 100644 --- a/internal/services/grpc/txsvc/v1/convert.go +++ b/internal/services/grpc/txsvc/v1/convert.go @@ -25,9 +25,10 @@ func convertTablesFromEngine(tables []*engineTypes.Table) []*txpb.Table { convTables := make([]*txpb.Table, len(tables)) for i, table := range tables { convTable := &txpb.Table{ - Name: table.Name, - Columns: convertColumnsFromEngine(table.Columns), - Indexes: convertIndexesFromEngine(table.Indexes), + Name: table.Name, + Columns: convertColumnsFromEngine(table.Columns), + Indexes: convertIndexesFromEngine(table.Indexes), + ForeignKeys: convertForeignKeysFromEngine(table.ForeignKeys), } convTables[i] = convTable } @@ -116,3 +117,27 @@ func convertModifiersFromEngine(mods []engineTypes.Modifier) (mutability string, return mutability, auxiliaries, nil } + +func convertForeignKeysFromEngine(foreignKeys []*engineTypes.ForeignKey) []*txpb.ForeignKey { + + convForeignKeys := make([]*txpb.ForeignKey, len(foreignKeys)) + for i, foreignKey := range foreignKeys { + convertedActions := make([]*txpb.ForeignKeyAction, len(foreignKey.Actions)) + + for j, action := range foreignKey.Actions { + convertedActions[j] = &txpb.ForeignKeyAction{ + On: action.On.String(), + Do: action.Do.String(), + } + } + + convForeignKeys[i] = &txpb.ForeignKey{ + ChildKeys: foreignKey.ChildKeys, + ParentKeys: foreignKey.ParentKeys, + ParentTable: foreignKey.ParentTable, + Actions: convertedActions, + } + } + + return convForeignKeys +} diff --git a/internal/services/grpc/txsvc/v1/validator.go b/internal/services/grpc/txsvc/v1/validator.go deleted file mode 100644 index e02b58ef7..000000000 --- a/internal/services/grpc/txsvc/v1/validator.go +++ /dev/null @@ -1,74 +0,0 @@ -package txsvc - -import ( - "bytes" - "context" - - txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" - vmgr "github.com/kwilteam/kwil-db/internal/validators" - "go.uber.org/zap" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (s *Service) CurrentValidators(ctx context.Context, _ *txpb.CurrentValidatorsRequest) (*txpb.CurrentValidatorsResponse, error) { - vals, err := s.vstore.CurrentValidators(ctx) - if err != nil { - s.log.Error("failed to retrieve current validators", zap.Error(err)) - return nil, status.Errorf(codes.Internal, "failed to retrieve current validators") - } - - pbValidators := make([]*txpb.Validator, len(vals)) - for i, vi := range vals { - pbValidators[i] = &txpb.Validator{ - Pubkey: vi.PubKey, - Power: vi.Power, - } - } - - return &txpb.CurrentValidatorsResponse{ - Validators: pbValidators, - }, nil -} - -func convertJoinRequest(join *vmgr.JoinRequest) *txpb.ValidatorJoinStatusResponse { - resp := &txpb.ValidatorJoinStatusResponse{ - Power: join.Power, - } - for i, approved := range join.Approved { - val := join.Board[i] - if approved { - resp.ApprovedValidators = append(resp.ApprovedValidators, val) - } else { - resp.PendingValidators = append(resp.PendingValidators, val) - } - } - return resp -} - -func (s *Service) ValidatorJoinStatus(ctx context.Context, req *txpb.ValidatorJoinStatusRequest) (*txpb.ValidatorJoinStatusResponse, error) { - joiner := req.Pubkey - allJoins, _, err := s.vstore.ActiveVotes(ctx) - if err != nil { - s.log.Error("failed to retrieve active join requests", zap.Error(err)) - return nil, status.Errorf(codes.Internal, "failed to retrieve active join requests") - } - for _, ji := range allJoins { - if bytes.Equal(ji.Candidate, joiner) { - return convertJoinRequest(ji), nil - } - } - - vals, err := s.vstore.CurrentValidators(ctx) - if err != nil { - s.log.Error("failed to retrieve current validators", zap.Error(err)) - return nil, status.Errorf(codes.Internal, "failed to retrieve current validators") - } - for _, vi := range vals { - if bytes.Equal(vi.PubKey, joiner) { - return nil, status.Errorf(codes.NotFound, "already a validator") // maybe FailedPrecondition? - } - } - - return nil, status.Errorf(codes.NotFound, "no active join request") -} diff --git a/internal/services/grpc_gateway/gateway.go b/internal/services/grpc_gateway/gateway.go index 5013ec03f..9f7ce3002 100644 --- a/internal/services/grpc_gateway/gateway.go +++ b/internal/services/grpc_gateway/gateway.go @@ -81,12 +81,7 @@ func (g *GatewayServer) Shutdown(ctx context.Context) error { } func registerHelperEndpoints(mux *runtime.ServeMux) error { - // err := mux.HandlePath(http.MethodGet, "/api/v0/swagger.json", swagger.GWSwaggerJSONV0Handler) - // if err != nil { - // return err - // } - - err := mux.HandlePath(http.MethodGet, "/api/v1/swagger.json", swagger.GWSwaggerJSONV1Handler) + err := mux.HandlePath(http.MethodGet, "/api/v1/tx.swagger.json", swagger.GWSwaggerJSONTxV1Handler) if err != nil { return err } diff --git a/internal/services/http/api/embed.go b/internal/services/http/api/embed.go index 6942bae0f..3df8e560b 100644 --- a/internal/services/http/api/embed.go +++ b/internal/services/http/api/embed.go @@ -2,11 +2,8 @@ package api import _ "embed" -// xxx go:embed v0.swagger.json -//var SwaggerV0 []byte - -//go:embed v1.swagger.json -var SwaggerV1 []byte +//go:embed tx/v1.swagger.json +var SwaggerTxV1 []byte //go:embed swaggerui.html var SwaggerUI []byte diff --git a/internal/services/http/api/function/v0.swagger.json b/internal/services/http/api/function/v0.swagger.json new file mode 100644 index 000000000..4adaa3d17 --- /dev/null +++ b/internal/services/http/api/function/v0.swagger.json @@ -0,0 +1,121 @@ +{ + "swagger": "2.0", + "info": { + "title": "kwil/function/v0/messages.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "FunctionService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/api/v1/verify_signature": { + "post": { + "operationId": "FunctionService_VerifySignature", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/functionVerifySignatureResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/functionVerifySignatureRequest" + } + } + ], + "tags": [ + "FunctionService" + ] + } + } + }, + "definitions": { + "functionVerifySignatureRequest": { + "type": "object", + "properties": { + "signature": { + "$ref": "#/definitions/txSignature" + }, + "sender": { + "type": "string", + "format": "byte" + }, + "msg": { + "type": "string", + "format": "byte" + } + } + }, + "functionVerifySignatureResponse": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "error": { + "type": "string" + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "txSignature": { + "type": "object", + "properties": { + "signature_bytes": { + "type": "string", + "format": "byte" + }, + "signature_type": { + "type": "string" + } + } + } + } +} diff --git a/internal/services/http/api/swaggerui.html b/internal/services/http/api/swaggerui.html index 6612ba9c3..c7dfab556 100644 --- a/internal/services/http/api/swaggerui.html +++ b/internal/services/http/api/swaggerui.html @@ -12,26 +12,26 @@
- + diff --git a/internal/services/http/api/v1.swagger.json b/internal/services/http/api/tx/v1.swagger.json similarity index 71% rename from internal/services/http/api/v1.swagger.json rename to internal/services/http/api/tx/v1.swagger.json index ffb02fe74..c0a684dd3 100644 --- a/internal/services/http/api/v1.swagger.json +++ b/internal/services/http/api/tx/v1.swagger.json @@ -59,38 +59,6 @@ ] } }, - "/api/v1/approve_validator": { - "post": { - "operationId": "TxService_ApproveValidator", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txValidatorApprovalResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/txValidatorApprovalRequest" - } - } - ], - "tags": [ - "TxService" - ] - } - }, "/api/v1/broadcast": { "post": { "operationId": "TxService_Broadcast", @@ -199,28 +167,6 @@ ] } }, - "/api/v1/current_validators": { - "get": { - "operationId": "TxService_CurrentValidators", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txCurrentValidatorsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "TxService" - ] - } - }, "/api/v1/databases/{dbid}/schema": { "get": { "operationId": "TxService_GetSchema", @@ -377,134 +323,6 @@ ] } }, - "/api/v1/validator_join": { - "post": { - "operationId": "TxService_ValidatorJoin", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txValidatorJoinResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/txValidatorJoinRequest" - } - } - ], - "tags": [ - "TxService" - ] - } - }, - "/api/v1/validator_join_status/{pubkey}": { - "get": { - "operationId": "TxService_ValidatorJoinStatus", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txValidatorJoinStatusResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "pubkey", - "description": "ED25519 PubKey", - "in": "path", - "required": true, - "type": "string", - "format": "byte" - } - ], - "tags": [ - "TxService" - ] - } - }, - "/api/v1/validator_leave": { - "post": { - "operationId": "TxService_ValidatorLeave", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txValidatorLeaveResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/txValidatorLeaveRequest" - } - } - ], - "tags": [ - "TxService" - ] - } - }, - "/api/v1/verify_signature": { - "post": { - "operationId": "TxService_VerifySignature", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/txVerifySignatureResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/txVerifySignatureRequest" - } - } - ], - "tags": [ - "TxService" - ] - } - }, "/api/v1/{owner}/databases": { "get": { "operationId": "TxService_ListDatabases", @@ -686,9 +504,6 @@ "txCallRequestBody": { "type": "object", "properties": { - "description": { - "type": "string" - }, "payload": { "type": "string", "format": "byte" @@ -737,18 +552,6 @@ } } }, - "txCurrentValidatorsResponse": { - "type": "object", - "properties": { - "validators": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/txValidator" - } - } - } - }, "txEstimatePriceRequest": { "type": "object", "properties": { @@ -783,6 +586,44 @@ } } }, + "txForeignKey": { + "type": "object", + "properties": { + "child_keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "parent_keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "parent_table": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/txForeignKeyAction" + } + } + } + }, + "txForeignKeyAction": { + "type": "object", + "properties": { + "on": { + "type": "string" + }, + "do": { + "type": "string" + } + } + }, "txGetAccountResponse": { "type": "object", "properties": { @@ -870,14 +711,6 @@ } } }, - "txRequestStatus": { - "type": "string", - "enum": [ - "OK", - "ERROR" - ], - "default": "OK" - }, "txSchema": { "type": "object", "properties": { @@ -942,6 +775,13 @@ "type": "object", "$ref": "#/definitions/txIndex" } + }, + "foreign_keys": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/txForeignKey" + } } } }, @@ -1020,28 +860,6 @@ } } }, - "txTransactionStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "byte" - }, - "fee": { - "type": "string" - }, - "status": { - "type": "string" - }, - "errors": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "title": "deprecated" - }, "txTxQueryRequest": { "type": "object", "properties": { @@ -1069,124 +887,6 @@ "$ref": "#/definitions/txTransactionResult" } } - }, - "txValidator": { - "type": "object", - "properties": { - "pubkey": { - "type": "string", - "format": "byte", - "title": "ED25519 PubKey" - }, - "power": { - "type": "string", - "format": "int64" - } - } - }, - "txValidatorApprovalRequest": { - "type": "object", - "properties": { - "PubKey": { - "type": "string", - "format": "byte", - "title": "ED25519 PubKey" - } - } - }, - "txValidatorApprovalResponse": { - "type": "object", - "properties": { - "status": { - "$ref": "#/definitions/txRequestStatus" - }, - "log": { - "type": "string" - } - } - }, - "txValidatorJoinRequest": { - "type": "object", - "properties": { - "tx": { - "$ref": "#/definitions/txTransaction" - } - }, - "title": "TODO: these should not wrap Transactions; all of these should just get forwarded to the broadcast endpoint" - }, - "txValidatorJoinResponse": { - "type": "object", - "properties": { - "receipt": { - "$ref": "#/definitions/txTransactionStatus" - } - } - }, - "txValidatorJoinStatusResponse": { - "type": "object", - "properties": { - "approved_validators": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } - }, - "pending_validators": { - "type": "array", - "items": { - "type": "string", - "format": "byte" - } - }, - "power": { - "type": "string", - "format": "int64" - } - } - }, - "txValidatorLeaveRequest": { - "type": "object", - "properties": { - "tx": { - "$ref": "#/definitions/txTransaction" - } - } - }, - "txValidatorLeaveResponse": { - "type": "object", - "properties": { - "receipt": { - "$ref": "#/definitions/txTransactionStatus" - } - } - }, - "txVerifySignatureRequest": { - "type": "object", - "properties": { - "signature": { - "$ref": "#/definitions/txSignature" - }, - "sender": { - "type": "string", - "format": "byte" - }, - "msg": { - "type": "string", - "format": "byte" - } - } - }, - "txVerifySignatureResponse": { - "type": "object", - "properties": { - "valid": { - "type": "boolean" - }, - "error": { - "type": "string" - } - } } } } diff --git a/internal/services/http/swagger/handler.go b/internal/services/http/swagger/handler.go index 5958a6a7b..fda77292d 100644 --- a/internal/services/http/swagger/handler.go +++ b/internal/services/http/swagger/handler.go @@ -9,14 +9,9 @@ import ( swagger "github.com/kwilteam/kwil-db/internal/services/http/api" ) -// func GWSwaggerJSONV0Handler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { -// var t time.Time -// http.ServeContent(w, r, "swagger.json", t, bytes.NewReader(swagger.SwaggerV0)) -// } - -func GWSwaggerJSONV1Handler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { +func GWSwaggerJSONTxV1Handler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { var t time.Time - http.ServeContent(w, r, "swagger.json", t, bytes.NewReader(swagger.SwaggerV1)) + http.ServeContent(w, r, "tx.swagger.json", t, bytes.NewReader(swagger.SwaggerTxV1)) } func GWSwaggerUIHandler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) { diff --git a/proto b/proto index 1011fcf71..c5a892f75 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 1011fcf71d39f980e9963fa949cbc0ff57c78447 +Subproject commit c5a892f75dbd8025a870019010006b6fa31a56a8 diff --git a/scripts/swagger/check_up b/scripts/swagger/check_up new file mode 100644 index 000000000..e60792c56 --- /dev/null +++ b/scripts/swagger/check_up @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# This script ensures that the swagger-codegen generated .go files are up-to-date. + +pushd $(git rev-parse --show-toplevel) > /dev/null + +# Force regenerate of swagger code +task -f pb:tx:v1:swagger +#task -f pb:function:v0:swagger + +STATUS=$(git status core/rpc/http/tx --porcelain) +#STATUS=$(git status core/rpc/http/tx core/rpc/http/function --porcelain) + + +popd > /dev/null + +if [[ -n "$STATUS" ]]; then + echo "Changes detected in core/rpc/http !" + exit 1 +else + echo "No changes detected in the directory." + exit 0 +fi + +popd diff --git a/test/acceptance/docker-compose.yml b/test/acceptance/docker-compose.yml index c22687d12..2327e9724 100644 --- a/test/acceptance/docker-compose.yml +++ b/test/acceptance/docker-compose.yml @@ -17,19 +17,20 @@ services: - type: bind source: ${KWIL_HOME:-./.testnode} target: /app/kwil + - /tmp:/var/run/kwil:rw depends_on: - ext networks: - kwil-act-testnet command: | - --root_dir=/app/kwil + --root-dir=/app/kwil --log.level=${LOG_LEVEL:-info} - --app.extension_endpoints=ext:50051 - --app.admin_listen_addr=:50151 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 - --chain.rpc.listen_addr=tcp://0.0.0.0:26657 + --app.extension-endpoints=ext:50051 + --app.admin-listen-addr=unix:///var/run/kwil/admin.sock + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.rpc.listen-addr=tcp://0.0.0.0:26657 ext: container_name: math_ext diff --git a/test/acceptance/driver.go b/test/acceptance/driver.go index d94907767..cdb1384bc 100644 --- a/test/acceptance/driver.go +++ b/test/acceptance/driver.go @@ -9,5 +9,5 @@ type KwilAcceptanceDriver interface { specifications.DatabaseDropDsl specifications.ExecuteQueryDsl specifications.ExecuteCallDsl - specifications.ValidatorOpsDsl + specifications.InfoDsl } diff --git a/test/acceptance/helper.go b/test/acceptance/helper.go index 3e6a43e50..ad56efecd 100644 --- a/test/acceptance/helper.go +++ b/test/acceptance/helper.go @@ -33,13 +33,14 @@ var ( envFile = getEnv("KACT_ENV_FILE", "./.env") ) -const testChainID = "kwil-test-chain" +const TestChainID = "kwil-test-chain" // ActTestCfg is the config for acceptance test type ActTestCfg struct { - HTTPEndpoint string - GrpcEndpoint string - ChainEndpoint string + HTTPEndpoint string + GrpcEndpoint string + P2PAddress string // cometbft p2p address + AdminClientUnixSocket string SchemaFile string DockerComposeFile string @@ -79,7 +80,7 @@ VISITOR_PUBLIC_KEY=%x content := fmt.Sprintf(envTemplage, e.GrpcEndpoint, e.HTTPEndpoint, - e.ChainEndpoint, + e.P2PAddress, e.CreatorRawPk, e.CreatorPublicKey(), e.VisitorRawPK, @@ -128,6 +129,8 @@ func (r *ActHelper) LoadConfig() { LogLevel: getEnv("KACT_LOG_LEVEL", "info"), HTTPEndpoint: getEnv("KACT_HTTP_ENDPOINT", "http://localhost:8080"), GrpcEndpoint: getEnv("KACT_GRPC_ENDPOINT", "localhost:50051"), + P2PAddress: getEnv("KACT_CHAIN_ENDPOINT", "tcp://0.0.0.0:26656"), + AdminClientUnixSocket: getEnv("KACT_ADMIN_CLIENT_UNIX_SOCKET", "tcp://localhost:50151"), DockerComposeFile: getEnv("KACT_DOCKER_COMPOSE_FILE", "./docker-compose.yml"), DockerComposeOverrideFile: getEnv("KACT_DOCKER_COMPOSE_OVERRIDE_FILE", "./docker-compose.override.yml"), } @@ -174,7 +177,7 @@ func (r *ActHelper) generateNodeConfig() { r.t.Logf("create test temp directory: %s", tmpPath) err := nodecfg.GenerateNodeConfig(&nodecfg.NodeGenerateConfig{ - ChainID: testChainID, + ChainID: TestChainID, BlockInterval: time.Second, // InitialHeight: 0, OutputDir: tmpPath, @@ -282,13 +285,14 @@ func (r *ActHelper) GetDriver(driveType string, user string) KwilAcceptanceDrive func (r *ActHelper) getHTTPClientDriver(signer auth.Signer) KwilAcceptanceDriver { logger := log.New(log.Config{Level: r.cfg.LogLevel}) - options := []client.Option{client.WithSigner(signer, testChainID), - client.WithLogger(logger), - client.WithTLSCert("")} // TODO: handle cert - kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, options...) + kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ + Signer: signer, + ChainID: TestChainID, + Logger: logger, + }) require.NoError(r.t, err, "failed to create http client") - return driver.NewKwildClientDriver(kwilClt, driver.WithLogger(logger)) + return driver.NewKwildClientDriver(kwilClt, logger) } func (r *ActHelper) getGRPCClientDriver(signer auth.Signer) KwilAcceptanceDriver { @@ -298,15 +302,14 @@ func (r *ActHelper) getGRPCClientDriver(signer auth.Signer) KwilAcceptanceDriver gt, err := gRPC.New(context.Background(), r.cfg.GrpcEndpoint, gtOptions...) require.NoError(r.t, err, "failed to create grpc transport") - options := []client.Option{client.WithSigner(signer, ""), - client.WithLogger(logger), - client.WithTLSCert(""), - client.WithRPCClient(gt), - } // TODO: handle cert - kwilClt, err := client.Dial(context.TODO(), r.cfg.GrpcEndpoint, options...) + kwilClt, err := client.WrapClient(context.TODO(), gt, &client.ClientOptions{ + Signer: signer, + Logger: logger, + // we dont care about chain id here + }) require.NoError(r.t, err, "failed to create grpc client") - return driver.NewKwildClientDriver(kwilClt, driver.WithLogger(logger)) + return driver.NewKwildClientDriver(kwilClt, logger) } func (r *ActHelper) getCliDriver(privKey string, identifier []byte) KwilAcceptanceDriver { @@ -315,8 +318,6 @@ func (r *ActHelper) getCliDriver(privKey string, identifier []byte) KwilAcceptan _, currentFilePath, _, _ := runtime.Caller(1) cliBinPath := path.Join(path.Dir(currentFilePath), fmt.Sprintf("../../.build/kwil-cli-%s-%s", runtime.GOOS, runtime.GOARCH)) - adminBinPath := path.Join(path.Dir(currentFilePath), - fmt.Sprintf("../../.build/kwil-admin-%s-%s", runtime.GOOS, runtime.GOARCH)) - return driver.NewKwilCliDriver(cliBinPath, adminBinPath, r.cfg.HTTPEndpoint, privKey, testChainID, identifier, logger) + return driver.NewKwilCliDriver(cliBinPath, r.cfg.HTTPEndpoint, privKey, TestChainID, identifier, logger) } diff --git a/test/acceptance/kwild_test.go b/test/acceptance/kwild_test.go index 5996af25c..4a0b8add8 100644 --- a/test/acceptance/kwild_test.go +++ b/test/acceptance/kwild_test.go @@ -13,7 +13,7 @@ import ( var dev = flag.Bool("dev", false, "run for development purpose (no tests)") var remote = flag.Bool("remote", false, "test against remote node") -var drivers = flag.String("drivers", "http,cli", "comma separated list of drivers to run") +var drivers = flag.String("drivers", "grpc,cli", "comma separated list of drivers to run") // TestKwildAcceptance runs acceptance tests again a single kwild node(and // are not concurrent), using different drivers: clientDriver, cliDriver. @@ -72,8 +72,13 @@ func TestKwildAcceptance(t *testing.T) { // and user should be able to drop database specifications.DatabaseDropSpecification(ctx, t, creatorDriver) + specifications.ExecuteChainInfoSpecification(ctx, t, creatorDriver, acceptance.TestChainID) // there's one node in the network and we're the validator - specifications.CurrentValidatorsSpecification(ctx, t, creatorDriver, 1) + // @brennan I am commenting this out temporarily, but it seems to be _mostly_ useless + // all it does is check that the node is a validator, which is not really a useful test, + // and couples the rest of acceptance to the validator rpcs, which should probably + // be a standalone set of tests anyways + //specifications.CurrentValidatorsSpecification(ctx, t, creatorDriver, 1) // The other network/validator specs require multiple nodes in a network }) diff --git a/test/driver/cli_driver.go b/test/driver/cli_driver.go index ae2af4f4d..ac70d8195 100644 --- a/test/driver/cli_driver.go +++ b/test/driver/cli_driver.go @@ -26,7 +26,6 @@ import ( // KwilCliDriver is a driver for tests using `cmd/kwil-cli` type KwilCliDriver struct { cliBin string // kwil-cli binary path - adminBin string // kwil-admin binary path rpcUrl string privKey string identity []byte @@ -34,10 +33,9 @@ type KwilCliDriver struct { logger log.Logger } -func NewKwilCliDriver(cliBin, adminBin, rpcUrl, privKey, chainID string, identity []byte, logger log.Logger) *KwilCliDriver { +func NewKwilCliDriver(cliBin, rpcUrl, privKey, chainID string, identity []byte, logger log.Logger) *KwilCliDriver { return &KwilCliDriver{ cliBin: cliBin, - adminBin: adminBin, rpcUrl: rpcUrl, privKey: privKey, identity: identity, @@ -59,17 +57,6 @@ func (d *KwilCliDriver) newKwilCliCmd(args ...string) *exec.Cmd { return cmd } -func (d *KwilCliDriver) newKwilAdminCmd(args ...string) *exec.Cmd { - args = append(args, "--rpcserver", d.rpcUrl) - args = append(args, "--output", "json") - - d.logger.Info("admin cmd", zap.String("args", - strings.Join(append([]string{d.adminBin}, args...), " "))) - - cmd := exec.Command(d.adminBin, args...) - return cmd -} - // SupportBatch // kwil-cli does not support batched inputs. func (d *KwilCliDriver) SupportBatch() bool { @@ -291,106 +278,27 @@ func (d *KwilCliDriver) Call(_ context.Context, dbid, action string, inputs []an return parseRespQueryDb(out.Result) } -func (d *KwilCliDriver) ApproveNode(_ context.Context, joinerPubKey []byte) error { - cmd := d.newKwilCliCmd("validator", "approve", hex.EncodeToString(joinerPubKey)) - _, err := mustRun(cmd, d.logger) - if err != nil { - return fmt.Errorf("failed to approve node: %w", err) - } - - return nil -} - -func (d *KwilCliDriver) ValidatorNodeApprove(_ context.Context, joinerPubKey []byte) ([]byte, error) { - cmd := d.newKwilAdminCmd("validators", "approve", hex.EncodeToString(joinerPubKey), d.privKey) - out, err := mustRun(cmd, d.logger) - if err != nil { - return nil, fmt.Errorf("failed to approve validators: %w", err) - } - - txHash, err := parseRespTxHash(out.Result) - if err != nil { - return nil, fmt.Errorf("failed to parse tx hash: %w", err) - } - - return txHash, nil -} - -func (d *KwilCliDriver) ValidatorNodeRemove(ctx context.Context, target []byte) ([]byte, error) { - cmd := d.newKwilAdminCmd("validators", "remove", hex.EncodeToString(target), d.privKey) - out, err := mustRun(cmd, d.logger) - if err != nil { - return nil, fmt.Errorf("failed to approve validators: %w", err) - } - - txHash, err := parseRespTxHash(out.Result) - if err != nil { - return nil, fmt.Errorf("failed to parse tx hash: %w", err) - } - - return txHash, nil -} - -func (d *KwilCliDriver) ValidatorNodeJoin(_ context.Context) ([]byte, error) { - cmd := d.newKwilAdminCmd("validators", "join", d.privKey) +func (d *KwilCliDriver) ChainInfo(_ context.Context) (*types.ChainInfo, error) { + cmd := d.newKwilCliCmd("utils", "chain-info") out, err := mustRun(cmd, d.logger) if err != nil { - return nil, fmt.Errorf("failed to joni as validator: %w", err) + return nil, fmt.Errorf("failed to get chain info: %w", err) } - txHash, err := parseRespTxHash(out.Result) - if err != nil { - return nil, fmt.Errorf("failed to parse tx hash: %w", err) - } - - return txHash, nil -} + d.logger.Debug("chain info", zap.Any("Resp", out.Result)) + var chainInfo types.ChainInfo -func (d *KwilCliDriver) ValidatorNodeLeave(_ context.Context) ([]byte, error) { - cmd := d.newKwilAdminCmd("validators", "leave", d.privKey) - out, err := mustRun(cmd, d.logger) + bts, err := json.Marshal(out.Result) if err != nil { - return nil, fmt.Errorf("failed to leave as validator: %w", err) + return nil, fmt.Errorf("failed to marshal chain info: %w", err) } - txHash, err := parseRespTxHash(out.Result) + err = json.Unmarshal(bts, &chainInfo) if err != nil { - return nil, fmt.Errorf("failed to parse tx hash: %w", err) + return nil, fmt.Errorf("failed to parse chain info: %w", err) } - return txHash, nil -} - -func (d *KwilCliDriver) ValidatorJoinStatus(_ context.Context, pubKey []byte) (*types.JoinRequest, error) { - cmd := d.newKwilAdminCmd("validators", "join-status", hex.EncodeToString(pubKey)) - out, err := mustRun(cmd, d.logger) - if err != nil { - return nil, fmt.Errorf("failed to query validator join status: %w", err) - } - - d.logger.Debug("validator join status", zap.Any("Resp", out.Result)) - joinReq, err := parseRespValJoinRequest(out.Result) - if err != nil { - return nil, fmt.Errorf("failed to parse validator join status: %w", err) - } - - return joinReq, nil -} - -func (d *KwilCliDriver) ValidatorsList(_ context.Context) ([]*types.Validator, error) { - cmd := d.newKwilAdminCmd("validators", "list") - out, err := mustRun(cmd, d.logger) - if err != nil { - return nil, fmt.Errorf("failed to list validators: %w", err) - } - - d.logger.Debug("validator list", zap.Any("Resp", out.Result)) - valSets, err := parseRespValSets(out.Result) - if err != nil { - return nil, fmt.Errorf("failed to parse validator list: %w", err) - } - - return valSets, nil + return &chainInfo, nil } ///////// helper functions @@ -522,85 +430,6 @@ func parseRespQueryDb(data any) (*client.Records, error) { return client.NewRecordsFromMaps(resp), nil } -// respValJoinRequest is customized json format for respValJoinStatus -// NOTE: this is exactly the same as the one in cmd/kwil-admin/message.go -type respValJoinRequest struct { - Candidate string `json:"candidate"` - Power int64 `json:"power"` - Board []string - Approved []bool -} - -// parseRespValJoinRequest parses the validator join request response(json) from the cli response -// NOTE: this could be defined as a `encoding.TextUnmarshaler` interface in `cmd/kwil-cli` -// if we expose the type from `cmd/kwil-cli` -func parseRespValJoinRequest(data any) (*types.JoinRequest, error) { - bts, err := json.Marshal(data) - if err != nil { - return nil, fmt.Errorf("failed to marshal val join request resp: %w", err) - } - - var resp respValJoinRequest - err = json.Unmarshal(bts, &resp) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal val join request: %w", err) - } - - candidateBts, err := hex.DecodeString(resp.Candidate) - if err != nil { - return nil, fmt.Errorf("failed to decode candidate: %w", err) - } - - board := make([][]byte, len(resp.Board)) - for i := range resp.Board { - board[i], err = hex.DecodeString(resp.Board[i]) - if err != nil { - return nil, fmt.Errorf("failed to decode board: %w", err) - } - } - - return &types.JoinRequest{ - Candidate: candidateBts, - Power: resp.Power, - Board: board, - Approved: resp.Approved, - }, nil -} - -// respValInfo represents the validator info response(json) from the cli response -// NOTE: this is exactly the same as the one in cmd/kwil-admin/message.go -type respValInfo struct { - PubKey string `json:"pubkey"` - Power int64 `json:"power"` -} - -func parseRespValSets(data any) ([]*types.Validator, error) { - bts, err := json.Marshal(data) - if err != nil { - return nil, fmt.Errorf("failed to marshal val sets resp: %w", err) - } - - var resp []respValInfo - err = json.Unmarshal(bts, &resp) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal val sets: %w", err) - } - - vals := make([]*types.Validator, len(resp)) - for i := range resp { - pubKey, err := hex.DecodeString(resp[i].PubKey) - if err != nil { - return nil, fmt.Errorf("failed to decode pubkey: %w", err) - } - vals[i] = &types.Validator{ - PubKey: pubKey, - Power: resp[i].Power, - } - } - - return vals, nil -} - // respDBList represent databases belong to an owner in cli // NOTE: this is **NOT** exactly the same as the one in cmd/kwil-cli/message.go type respDBList struct { diff --git a/test/driver/client_driver.go b/test/driver/client_driver.go index 9927a0706..81be8224e 100644 --- a/test/driver/client_driver.go +++ b/test/driver/client_driver.go @@ -30,22 +30,10 @@ type KwildClientDriver struct { logger log.Logger } -type GrpcDriverOpt func(*KwildClientDriver) - -func WithLogger(logger log.Logger) GrpcDriverOpt { - return func(d *KwildClientDriver) { - d.logger = logger - } -} - -func NewKwildClientDriver(clt *client.Client, opts ...GrpcDriverOpt) *KwildClientDriver { +func NewKwildClientDriver(clt *client.Client, logger log.Logger) *KwildClientDriver { driver := &KwildClientDriver{ clt: clt, - logger: log.New(log.Config{}), - } - - for _, opt := range opts { - opt(driver) + logger: logger, } return driver @@ -146,31 +134,10 @@ func (d *KwildClientDriver) QueryDatabase(ctx context.Context, dbid, query strin } func (d *KwildClientDriver) Call(ctx context.Context, dbid, action string, inputs []any, withSignature bool) (*client.Records, error) { - callOpts := make([]client.CallOpt, 0) - callOpts = append(callOpts, client.Authenticated(withSignature)) - return d.clt.CallAction(ctx, dbid, action, inputs, callOpts...) -} - -func (d *KwildClientDriver) ValidatorNodeApprove(ctx context.Context, joinerPubKey []byte) ([]byte, error) { - return d.clt.ApproveValidator(ctx, joinerPubKey) -} - -func (d *KwildClientDriver) ValidatorNodeRemove(ctx context.Context, target []byte) ([]byte, error) { - return d.clt.RemoveValidator(ctx, target) -} - -func (d *KwildClientDriver) ValidatorNodeJoin(ctx context.Context) ([]byte, error) { - return d.clt.ValidatorJoin(ctx) -} - -func (d *KwildClientDriver) ValidatorNodeLeave(ctx context.Context) ([]byte, error) { - return d.clt.ValidatorLeave(ctx) -} -func (d *KwildClientDriver) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { - return d.clt.ValidatorJoinStatus(ctx, pubKey) + return d.clt.CallAction(ctx, dbid, action, inputs) } -func (d *KwildClientDriver) ValidatorsList(ctx context.Context) ([]*types.Validator, error) { - return d.clt.CurrentValidators(ctx) +func (d *KwildClientDriver) ChainInfo(ctx context.Context) (*types.ChainInfo, error) { + return d.clt.ChainInfo(ctx) } diff --git a/test/driver/operator/cli_driver.go b/test/driver/operator/cli_driver.go new file mode 100644 index 000000000..1f2a29be5 --- /dev/null +++ b/test/driver/operator/cli_driver.go @@ -0,0 +1,149 @@ +package operator + +import ( + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/core/types" + "github.com/kwilteam/kwil-db/test/driver" +) + +// OperatorCLIDriver is a driver for the operator using the kwil-admin cli. +type OperatorCLIDriver struct { + Exec ExecFn // execute a command + RpcUrl string // rpc url (either unix socket or tcp) +} + +// ExecFn executes a CLI command for the admin client. +type ExecFn func(ctx context.Context, args ...string) ([]byte, error) + +var _ KwilOperatorDriver = (*OperatorCLIDriver)(nil) + +// runCommand runs a kwil-admin command with the node's rpcserver. +// it returns the generic response. +// It will unmarshal the response into the provided result. +func (o *OperatorCLIDriver) runCommand(ctx context.Context, result any, args ...string) error { + args = append(args, "--rpcserver", o.RpcUrl) + args = append(args, "--output", "json") + + bts, err := o.Exec(ctx, args...) + if err != nil { + return err + } + + // cli returns json response with an error field if there was an error + resp := cliResponse{} + err = json.Unmarshal(bts, &resp) + if err != nil { + return err + } + + if resp.Error != "" { + return errors.New(resp.Error) + } + + // unmarshal the result into the provided result + bts, err = json.Marshal(resp.Result) + if err != nil { + return err + } + + return json.Unmarshal(bts, result) +} + +func (o *OperatorCLIDriver) TxSuccess(ctx context.Context, txHash []byte) error { + var res respTxQuery + err := o.runCommand(ctx, &res, "utils", "query-tx", hex.EncodeToString(txHash)) + if err != nil { + return err + } + + // NOTE: this should not be considered a failure, should retry + if res.Height < 0 { + return driver.ErrTxNotConfirmed + } + + if res.TxResult.Code != 0 { + return fmt.Errorf("tx failed: %s", res.TxResult.Log) + } + return nil +} + +func (o *OperatorCLIDriver) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { + var res types.JoinRequest + err := o.runCommand(ctx, &res, "validators", "join-status", hex.EncodeToString(pubKey)) + if err != nil { + return nil, err + } + + return &res, nil +} + +// commands that return a tx hash return a hex encoded string +func (o *OperatorCLIDriver) ValidatorNodeApprove(ctx context.Context, joinerPubKey []byte) ([]byte, error) { + var res display.TxHashResponse + err := o.runCommand(ctx, &res, "validators", "approve", hex.EncodeToString(joinerPubKey)) + if err != nil { + return nil, err + } + + return hex.DecodeString(res.TxHash) +} + +func (o *OperatorCLIDriver) ValidatorNodeJoin(ctx context.Context) ([]byte, error) { + var res display.TxHashResponse + err := o.runCommand(ctx, &res, "validators", "join") + if err != nil { + return nil, err + } + + return hex.DecodeString(res.TxHash) +} + +func (o *OperatorCLIDriver) ValidatorNodeLeave(ctx context.Context) ([]byte, error) { + var res display.TxHashResponse + err := o.runCommand(ctx, &res, "validators", "leave") + if err != nil { + return nil, err + } + + return hex.DecodeString(res.TxHash) +} + +func (o *OperatorCLIDriver) ValidatorNodeRemove(ctx context.Context, target []byte) ([]byte, error) { + var res display.TxHashResponse + err := o.runCommand(ctx, &res, "validators", "remove", hex.EncodeToString(target)) + if err != nil { + return nil, err + } + + return hex.DecodeString(res.TxHash) +} + +func (o *OperatorCLIDriver) ValidatorsList(ctx context.Context) ([]*types.Validator, error) { + var res []*types.Validator + err := o.runCommand(ctx, &res, "validators", "list") + if err != nil { + return nil, err + } + + return res, nil +} + +type cliResponse struct { + Result any `json:"result"` + Error string `json:"error"` +} + +// respTxQuery represents the tx query response(json) from the cli response +type respTxQuery struct { + Height int64 `json:"height"` + TxResult struct { + Code uint32 `json:"code"` + Log string `json:"log"` + } `json:"tx_result"` +} diff --git a/test/driver/operator/operator.go b/test/driver/operator/operator.go new file mode 100644 index 000000000..a68891532 --- /dev/null +++ b/test/driver/operator/operator.go @@ -0,0 +1,9 @@ +package operator + +import "github.com/kwilteam/kwil-db/test/specifications" + +// KwilOperatorDriver is the interface for a node operator. +type KwilOperatorDriver interface { + specifications.ValidatorOpsDsl // TODO: split into ValidatorJoinDsl, ValidatorApproveDsl, ValidatorLeaveDsl + specifications.ValidatorRemoveDsl +} diff --git a/test/go.mod b/test/go.mod index 05df411ac..289d501ff 100644 --- a/test/go.mod +++ b/test/go.mod @@ -32,6 +32,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.0 // indirect + github.com/antihax/optional v1.0.0 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect github.com/aws/aws-sdk-go-v2/config v1.18.16 // indirect @@ -222,15 +223,15 @@ require ( go.opentelemetry.io/otel/trace v1.15.1 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.13.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/test/go.sum b/test/go.sum index 1282c0650..6bbb6fe34 100644 --- a/test/go.sum +++ b/test/go.sum @@ -85,6 +85,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= @@ -889,8 +890,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -968,8 +969,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1064,13 +1065,13 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1080,8 +1081,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/test/integration/docker-compose.yml b/test/integration/docker-compose.yml index a095b796c..f9174d268 100644 --- a/test/integration/docker-compose.yml +++ b/test/integration/docker-compose.yml @@ -21,14 +21,16 @@ services: ipv4_address: 172.10.100.2 depends_on: - ext1 + # the admin_listen_addr socket HAS to have the same number as the node name (node0 -> admin0.sock) command: | - --root_dir=/app/kwil + --root-dir=/app/kwil --log.level=${LOG_LEVEL:-debug} - --app.extension_endpoints=ext1:50051 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 - --chain.rpc.listen_addr=tcp://0.0.0.0:26657 + --app.extension-endpoints=ext1:50051 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --app.admin-listen-addr=unix:///var/run/kwil/admin.sock + --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.rpc.listen-addr=tcp://0.0.0.0:26657 node1: container_name: node1 @@ -50,13 +52,14 @@ services: depends_on: - ext1 command: | - --root_dir=/app/kwil + --root-dir=/app/kwil --log.level=${LOG_LEVEL:-debug} - --app.extension_endpoints=ext1:50051 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 - --chain.rpc.listen_addr=tcp://0.0.0.0:26657 + --app.extension-endpoints=ext1:50051 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --app.admin-listen-addr=unix:///var/run/kwil/admin.sock + --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.rpc.listen-addr=tcp://0.0.0.0:26657 node2: container_name: node2 @@ -78,13 +81,14 @@ services: depends_on: - ext1 command: | - --root_dir=/app/kwil + --root-dir=/app/kwil --log.level=${LOG_LEVEL:-debug} - --app.extension_endpoints=ext1:50051 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 - --chain.rpc.listen_addr=tcp://0.0.0.0:26657 + --app.extension-endpoints=ext1:50051 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --app.admin-listen-addr=unix:///var/run/kwil/admin.sock + --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.rpc.listen-addr=tcp://0.0.0.0:26657 # This node is used to test the scenario where new node join the network & sync the blocks # Removing the ext dependency as test-container docker compose creates a new project everytime we run @@ -109,13 +113,14 @@ services: depends_on: - ext3 command: | - --root_dir=/app/kwil + --root-dir=/app/kwil --log.level=${LOG_LEVEL:-debug} - --app.extension_endpoints=ext3:50051 - --app.grpc_listen_addr=:50051 - --app.http_listen_addr=:8080 - --chain.p2p.external_address=tcp://0.0.0.0:26656 - --chain.rpc.listen_addr=tcp://0.0.0.0:26657 + --app.extension-endpoints=ext3:50051 + --app.grpc-listen-addr=:50051 + --app.http-listen-addr=:8080 + --chain.p2p.external-address=tcp://0.0.0.0:26656 + --app.admin-listen-addr=unix:///var/run/kwil/admin.sock + --chain.rpc.listen-addr=tcp://0.0.0.0:26657 # this ext is shared by all nodes # we can make a separate ext for each node if we want diff --git a/test/integration/driver.go b/test/integration/driver.go index 510da5b7a..c96b7f3cf 100644 --- a/test/integration/driver.go +++ b/test/integration/driver.go @@ -7,6 +7,4 @@ type KwilIntDriver interface { specifications.DatabaseDropDsl specifications.ExecuteQueryDsl specifications.ExecuteCallDsl - specifications.ValidatorOpsDsl // TODO: split into ValidatorJoinDsl, ValidatorApproveDsl, ValidatorLeaveDsl - specifications.ValidatorRemoveDsl } diff --git a/test/integration/helper.go b/test/integration/helper.go index b808128be..c92ddc75a 100644 --- a/test/integration/helper.go +++ b/test/integration/helper.go @@ -10,6 +10,7 @@ import ( "context" "encoding/hex" "fmt" + "io" "os" "os/signal" "path" @@ -35,6 +36,7 @@ import ( "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" "github.com/kwilteam/kwil-db/test/driver" + "github.com/kwilteam/kwil-db/test/driver/operator" ) var ( @@ -66,6 +68,7 @@ type IntTestConfig struct { HTTPEndpoint string GrpcEndpoint string ChainEndpoint string + AdminRPC string // either tcp or unix. Should be of form unix://var/run/kwil/admin.sock or tcp://localhost:26657 SchemaFile string DockerComposeFile string @@ -160,6 +163,7 @@ func (r *IntHelper) LoadConfig() { LogLevel: getEnv("KIT_LOG_LEVEL", "info"), HTTPEndpoint: getEnv("KIT_HTTP_ENDPOINT", "http://localhost:8080"), GrpcEndpoint: getEnv("KIT_GRPC_ENDPOINT", "localhost:50051"), + AdminRPC: getEnv("KIT_SOCKET_DIR", "unix:///var/run/kwil/admin.sock"), DockerComposeFile: getEnv("KIT_DOCKER_COMPOSE_FILE", "./docker-compose.yml"), DockerComposeOverrideFile: getEnv("KIT_DOCKER_COMPOSE_OVERRIDE_FILE", "./docker-compose.override.yml"), } @@ -342,7 +346,7 @@ func (r *IntHelper) GetUserDriver(ctx context.Context, name string, driverType s pk := r.cfg.CreatorRawPk switch driverType { case "http": - return r.getHTTPClientDriver(signer) + return r.getHTTPClientDriver(signer, r.cfg.HTTPEndpoint) case "grpc": return r.getGRPCClientDriver(signer) case "cli": @@ -353,55 +357,39 @@ func (r *IntHelper) GetUserDriver(ctx context.Context, name string, driverType s } // GetOperatorDriver returns a integration driver connected to the given kwil node, -// using the private key of the operator -func (r *IntHelper) GetOperatorDriver(ctx context.Context, name string, driverType string) KwilIntDriver { - ctr := r.containers[name] - - rpcURL, err := ctr.PortEndpoint(ctx, "50051", "") - require.NoError(r.t, err, "failed to get node url") - gatewayURL, err := ctr.PortEndpoint(ctx, "8080", "") - require.NoError(r.t, err, "failed to get gateway url") - p2pURL, err := ctr.PortEndpoint(ctx, "26656", "tcp") - require.NoError(r.t, err, "failed to get p2p url") - cometBftURL, err := ctr.PortEndpoint(ctx, "26657", "tcp") - require.NoError(r.t, err, "failed to get cometBFT RPC url") - - r.t.Logf(`user RPC URL: "%s" -gateway URL: "%s" -p2p URL: "%s" -cometBFT URL: "%s" -container name: "%s"`, - rpcURL, gatewayURL, cometBftURL, p2pURL, name) - - privKeyB := r.privateKeys[name].Bytes() - privKeyHex := hex.EncodeToString(privKeyB) - privKey, err := crypto.Ed25519PrivateKeyFromBytes(privKeyB) - require.NoError(r.t, err, "invalid private key") - signer := &auth.Ed25519Signer{Ed25519PrivateKey: *privKey} - - pk := privKeyHex +// using the private key of the operator. +// The passed nodeName needs to be the same as the name of the container in docker-compose.yml +func (r *IntHelper) GetOperatorDriver(ctx context.Context, nodeName string, driverType string) operator.KwilOperatorDriver { switch driverType { case "http": - return r.getHTTPClientDriver(signer) + r.t.Fatalf("http driver not supported for node operator") + return nil case "grpc": - return r.getGRPCClientDriver(signer) + r.t.Fatal("grpc driver not supported for node operator") // we can do this, but it is lower priority + return nil case "cli": - return r.getCliDriver(pk, signer.PubKey().Bytes()) + c, ok := r.containers[nodeName] + if !ok { + r.t.Fatalf("container %s not found", nodeName) + } + + return r.getCLIAdminClientDriver(r.cfg.AdminRPC, c) default: panic("unsupported driver type") } } -func (r *IntHelper) getHTTPClientDriver(signer auth.Signer) KwilIntDriver { +func (r *IntHelper) getHTTPClientDriver(signer auth.Signer, httpEndpoint string) KwilIntDriver { logger := log.New(log.Config{Level: r.cfg.LogLevel}) - options := []client.Option{client.WithSigner(signer, testChainID), - client.WithLogger(logger), - client.WithTLSCert("")} // TODO: handle cert - kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, options...) + kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ + Signer: signer, + ChainID: testChainID, + Logger: logger, + }) require.NoError(r.t, err, "failed to create kwil client") - return driver.NewKwildClientDriver(kwilClt, driver.WithLogger(logger)) + return driver.NewKwildClientDriver(kwilClt, logger) } func (r *IntHelper) getGRPCClientDriver(signer auth.Signer) KwilIntDriver { @@ -411,15 +399,41 @@ func (r *IntHelper) getGRPCClientDriver(signer auth.Signer) KwilIntDriver { gt, err := gRPC.New(context.Background(), r.cfg.GrpcEndpoint, gtOptions...) require.NoError(r.t, err, "failed to create grpc transport") - options := []client.Option{client.WithSigner(signer, ""), - client.WithLogger(logger), - client.WithTLSCert(""), - client.WithRPCClient(gt), - } // TODO: handle cert - kwilClt, err := client.Dial(context.TODO(), r.cfg.GrpcEndpoint, options...) + kwilClt, err := client.WrapClient(context.TODO(), gt, &client.ClientOptions{ + Signer: signer, + ChainID: testChainID, + Logger: logger, + }) require.NoError(r.t, err, "failed to create grpc client") - return driver.NewKwildClientDriver(kwilClt, driver.WithLogger(logger)) + return driver.NewKwildClientDriver(kwilClt, logger) +} + +// getCLIAdminClientDriver returns a kwil-admin client driver connected to the given kwil node. +// the adminSvcServer should be either unix:// or tcp:// +func (r *IntHelper) getCLIAdminClientDriver(adminSvcServer string, c *testcontainers.DockerContainer) operator.KwilOperatorDriver { + return &operator.OperatorCLIDriver{ + Exec: func(ctx context.Context, args ...string) ([]byte, error) { + _, reader, err := c.Exec(ctx, append([]string{"/app/kwil-admin"}, args...)) + if err != nil { + return nil, err + } + bts, err := io.ReadAll(reader) + if err != nil { + return nil, err + } + + // docker engine returns an 8 byte header as part of their response + // https://docs.docker.com/engine/api/v1.43/#tag/Container/operation/ContainerAttach + + if len(bts) < 8 { + return nil, fmt.Errorf("invalid response from docker engine") + } + + return bts[8:], nil + }, + RpcUrl: adminSvcServer, + } } func (r *IntHelper) getCliDriver(privKey string, identity []byte) KwilIntDriver { @@ -428,10 +442,8 @@ func (r *IntHelper) getCliDriver(privKey string, identity []byte) KwilIntDriver _, currentFilePath, _, _ := runtime.Caller(1) cliBinPath := path.Join(path.Dir(currentFilePath), fmt.Sprintf("../../.build/kwil-cli-%s-%s", runtime.GOOS, runtime.GOARCH)) - adminBinPath := path.Join(path.Dir(currentFilePath), - fmt.Sprintf("../../.build/kwil-admin-%s-%s", runtime.GOOS, runtime.GOARCH)) - return driver.NewKwilCliDriver(cliBinPath, adminBinPath, r.cfg.HTTPEndpoint, privKey, testChainID, identity, logger) + return driver.NewKwilCliDriver(cliBinPath, r.cfg.HTTPEndpoint, privKey, testChainID, identity, logger) } func (r *IntHelper) NodePrivateKey(name string) ed25519.PrivKey { diff --git a/test/integration/kwild_test.go b/test/integration/kwild_test.go index 0e8c978ed..e65742dad 100644 --- a/test/integration/kwild_test.go +++ b/test/integration/kwild_test.go @@ -73,6 +73,7 @@ func TestKwildValidatorRemoval(t *testing.T) { testDrivers := []string{"cli"} // strings.Split(*drivers, ",") for _, driverType := range testDrivers { + t.Run(driverType+"_driver", func(t *testing.T) { helper := integration.NewIntHelper(t, opts...) helper.Setup(ctx, allServices) @@ -105,8 +106,8 @@ func TestKwildValidatorRemoval(t *testing.T) { func TestKwildValidatorUpdatesIntegration(t *testing.T) { ctx := context.Background() - const expiryBlocks = 15 - const blockInterval = time.Second + const expiryBlocks = 10 + const blockInterval = 500 * time.Millisecond const numVals, numNonVals = 3, 1 opts := []integration.HelperOpt{ integration.WithValidators(numVals), @@ -117,7 +118,7 @@ func TestKwildValidatorUpdatesIntegration(t *testing.T) { expiryWait := 2 * expiryBlocks * blockInterval - testDrivers := strings.Split(*drivers, ",") + testDrivers := []string{"cli"} // strings.Split(*drivers, ",") for _, driverType := range testDrivers { t.Run(driverType+"_driver", func(t *testing.T) { helper := integration.NewIntHelper(t, opts...) diff --git a/test/specifications/dsl.go b/test/specifications/dsl.go index 2e1da9feb..91b72cf0c 100644 --- a/test/specifications/dsl.go +++ b/test/specifications/dsl.go @@ -76,6 +76,12 @@ type TxQueryDsl interface { TxSuccess(ctx context.Context, txHash []byte) error } +// InfoDsl is a dsl for information about the chain and node, according +// to usage in the TxSvc +type InfoDsl interface { + ChainInfo(ctx context.Context) (*types.ChainInfo, error) +} + // ValidatorStatusDsl is the dsl for checking validator status, including // current validator set and active join requests. type ValidatorStatusDsl interface { diff --git a/test/specifications/info.go b/test/specifications/info.go new file mode 100644 index 000000000..51406daed --- /dev/null +++ b/test/specifications/info.go @@ -0,0 +1,20 @@ +package specifications + +import ( + "context" + "testing" +) + +func ExecuteChainInfoSpecification(ctx context.Context, t *testing.T, dsl InfoDsl, chainId string) { + t.Logf("Executing chain info specification") + + info, err := dsl.ChainInfo(ctx) + if err != nil { + t.Fatalf("Failed to get chain info: %v", err) + } + + // I'm not quite sure how to test other fields of ChainInfo, since they are dynamic + if info.ChainID != chainId { + t.Fatalf("Expected chain id %s, got %s", chainId, info.ChainID) + } +} diff --git a/test/stress/hammer.go b/test/stress/hammer.go index 844d1855b..e8d3881e1 100644 --- a/test/stress/hammer.go +++ b/test/stress/hammer.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" "math/rand" + "net/url" "strconv" - "strings" "sync/atomic" "time" @@ -15,10 +15,13 @@ import ( "github.com/kwilteam/kwil-db/core/crypto" "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" - "github.com/kwilteam/kwil-db/core/rpc/client/user/grpc" + rpcClients "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/core/rpc/client/user" + userGrpc "github.com/kwilteam/kwil-db/core/rpc/client/user/grpc" "github.com/kwilteam/kwil-db/core/rpc/client/user/http" "github.com/kwilteam/kwil-db/core/types" "go.uber.org/zap" + "google.golang.org/grpc" ) // runLooped executes a basic function with a specified delay between each call @@ -68,11 +71,22 @@ func hammer(ctx context.Context) error { signer := &auth.EthPersonalSigner{Key: *priv} acctID := signer.Identity() - var rpcClient client.RPCClient - if strings.Contains(host, "http") { - rpcClient, err = http.Dial(host) + var rpcClient user.TxSvcClient + + parsedUrl, err := url.Parse(host) + if err != nil { + return err + } + + if parsedUrl.Scheme == "http" { + rpcClient = http.NewClient(parsedUrl) } else { - rpcClient, err = grpc.New(ctx, host, grpc.WithTlsCert("")) + conn, err := grpc.DialContext(ctx, parsedUrl.String(), rpcClients.DefaultGRPCOpts()...) + if err != nil { + return err + } + + rpcClient = userGrpc.WrapConn(conn) } if err != nil { return err @@ -86,14 +100,14 @@ func hammer(ctx context.Context) error { }) logger = *logger.WithOptions(zap.AddStacktrace(zap.FatalLevel)) trLogger := *logger.WithOptions(zap.AddCallerSkip(1)) - cl, err := client.Dial(ctx, host, client.WithLogger(trLogger), - client.WithRPCClient(&timedClient{rpcTiming, &logger, rpcClient}), - client.WithSigner(signer, ""), // we don't care what the chain ID is - ) + cl, err := client.WrapClient(ctx, &timedClient{rpcTiming, &logger, rpcClient}, &client.ClientOptions{ + Signer: signer, + Logger: trLogger, + }) + if err != nil { return err } - defer cl.Close() ctx, cancel := context.WithCancel(ctx) defer cancel() // any early return cancels other goroutines diff --git a/test/stress/transport.go b/test/stress/transport.go index d18122abc..1a39fa509 100644 --- a/test/stress/transport.go +++ b/test/stress/transport.go @@ -6,10 +6,9 @@ import ( "math/big" "time" - "github.com/kwilteam/kwil-db/core/client" - "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" + "github.com/kwilteam/kwil-db/core/rpc/client/user" "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" ) @@ -17,11 +16,7 @@ import ( type timedClient struct { showReqDur bool logger *log.Logger - cl client.RPCClient -} - -func (tc *timedClient) Close() error { - return tc.cl.Close() + cl user.TxSvcClient } func (tc *timedClient) printDur(t time.Time, method string) { @@ -42,10 +37,6 @@ func (tc *timedClient) TxQuery(ctx context.Context, txHash []byte) (*transaction return tc.cl.TxQuery(ctx, txHash) } -func (tc *timedClient) GetTarget() string { - return tc.cl.GetTarget() -} - func (tc *timedClient) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) { if tc.showReqDur { defer tc.printDur(time.Now(), "GetSchema") @@ -101,20 +92,3 @@ func (tc *timedClient) EstimateCost(ctx context.Context, tx *transactions.Transa } return tc.cl.EstimateCost(ctx, tx) } - -func (tc *timedClient) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { - panic("not implemented") // TODO: Implement -} - -func (tc *timedClient) CurrentValidators(ctx context.Context) ([]*types.Validator, error) { - panic("not implemented") // TODO: Implement -} - -func (tc *timedClient) VerifySignature(ctx context.Context, pubKey []byte, - signature *auth.Signature, message []byte) error { - if tc.showReqDur { - defer tc.printDur(time.Now(), "VerifySignature") - } - return tc.cl.VerifySignature(ctx, pubKey, signature, message) - -} From 7ec660b8880ee67d89a66bd6bc47c13a32e9a2c7 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:07:39 -0600 Subject: [PATCH 02/13] addressed jons feedback, minor formatting update --- .github/workflows/ci.yaml | 2 -- Taskfile-pb.yml | 4 ++-- cmd/kwil-admin/cmds/validators/list-join-requests.go | 12 +++++++++--- scripts/swagger/check_up | 0 4 files changed, 11 insertions(+), 7 deletions(-) mode change 100644 => 100755 scripts/swagger/check_up diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f1441eb1f..1be93a08c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -57,9 +57,7 @@ jobs: ./scripts/proto/check_up - name: Ensure generated swagger Go code is up-to-date - # This script gets a permissions error. I cannot figure out why, @yaiba do you know? The others don't. run: | - chmod +x ./scripts/swagger/check_up ./scripts/swagger/check_up - name: Compile packages, apps, and specs diff --git a/Taskfile-pb.yml b/Taskfile-pb.yml index b8f867b37..7a37dd731 100644 --- a/Taskfile-pb.yml +++ b/Taskfile-pb.yml @@ -6,8 +6,8 @@ tasks: - task: tx:v1 - task: tx:v1:swagger - task: admin:v0 -# - task: function:v0 -# - task: function:v0:swagger + - task: function:v0 + - task: function:v0:swagger tx:v1: desc: Compiles TxService v1 protobuf diff --git a/cmd/kwil-admin/cmds/validators/list-join-requests.go b/cmd/kwil-admin/cmds/validators/list-join-requests.go index d37377002..060f1eb05 100644 --- a/cmd/kwil-admin/cmds/validators/list-join-requests.go +++ b/cmd/kwil-admin/cmds/validators/list-join-requests.go @@ -73,8 +73,10 @@ func (r *respJoinList) MarshalText() ([]byte, error) { // could be ideal to use the SQL table formatting here msg.WriteString(fmt.Sprintf("Pending join requests (%d %s needed):\n", needed, approvalTerm)) - msg.WriteString(" Candidate | Power | Approvals | Expiration Height") - //ref spacing: 22cbbb666c26b2c1f42502df72c32de4d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100 + msg.WriteString(" Candidate | Power | Approvals | Expiration") + // ---------------------------------+-------+-----------+------------- + //ref spacing: 22cbbb666c26b2c1f42502df72c32de4 | | | + // d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100 for _, j := range r.Joins { approvals := 0 for _, a := range j.Approved { @@ -83,7 +85,11 @@ func (r *respJoinList) MarshalText() ([]byte, error) { } } - msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", hex.EncodeToString(j.Candidate), j.Power, approvals, j.ExpiresAt)) + hexPubKey := hex.EncodeToString(j.Candidate) + half := len(hexPubKey) / 2 + msg.WriteString("\n ---------------------------------+-------+-----------+-------------") + msg.WriteString(fmt.Sprintf("\n %s | % 5s | % 9s | %s", hexPubKey[0:half], "", "", "")) + msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", hexPubKey[half:], j.Power, approvals, j.ExpiresAt)) } return msg.Bytes(), nil diff --git a/scripts/swagger/check_up b/scripts/swagger/check_up old mode 100644 new mode 100755 From 1be8b49e64cd0280bf54259066fe928da2324a9b Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:17:47 -0600 Subject: [PATCH 03/13] attemtpin to fix panic found in cli --- cmd/kwil-cli/cmds/database/call.go | 5 +++++ core/client/iter.go | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/cmd/kwil-cli/cmds/database/call.go b/cmd/kwil-cli/cmds/database/call.go index d70906037..3188c6523 100644 --- a/cmd/kwil-cli/cmds/database/call.go +++ b/cmd/kwil-cli/cmds/database/call.go @@ -8,6 +8,7 @@ import ( "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" + "github.com/kwilteam/kwil-db/core/client" "github.com/spf13/cobra" ) @@ -85,6 +86,10 @@ func callCmd() *cobra.Command { display.PrintErr(cmd, fmt.Errorf("error calling action: %w", err)) } + if data == nil { + data = &client.Records{} + } + return display.PrintCmd(cmd, &respRelations{Data: data}) }) }, diff --git a/core/client/iter.go b/core/client/iter.go index 4cb98bc8a..9d95ad172 100644 --- a/core/client/iter.go +++ b/core/client/iter.go @@ -36,6 +36,11 @@ func NewRecordsFromMaps(recs []map[string]any) *Records { func (r *Records) Next() bool { r.index++ + + if r.records == nil { + return false + } + return r.index < len(r.records) } @@ -44,11 +49,20 @@ func (r *Records) Reset() { } func (r *Records) Record() *Record { + if r.records == nil { + return &Record{} + } + return r.records[r.index] } func (r *Records) Export() []map[string]any { + if r.records == nil { + return make([]map[string]any, 0) + } + records := make([]map[string]any, len(r.records)) + for i, record := range r.records { records[i] = *record } @@ -57,7 +71,12 @@ func (r *Records) Export() []map[string]any { } func (r *Records) ExportString() []map[string]string { + if r.records == nil { + return make([]map[string]string, 0) + } + records := make([]map[string]string, len(r.records)) + for i, record := range r.records { records[i] = record.String() } From 38bf2932e0887d4cea852e0f9e82b4eb5a6caeee Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:39:09 -0600 Subject: [PATCH 04/13] made kwils configuration flags reusable (for usage in the admin tool) --- cmd/kwil-admin/cmds/setup/peer.go | 20 +++++-------------- .../cmds/validators/list-join-requests.go | 17 +++++++--------- cmd/kwild/config/config.go | 5 ++--- cmd/kwild/{ => config}/flags.go | 13 ++++-------- cmd/kwild/main.go | 10 +++++++--- cmd/kwild/server/build.go | 3 ++- cmd/kwild/server/server.go | 3 ++- 7 files changed, 29 insertions(+), 42 deletions(-) rename cmd/kwild/{ => config}/flags.go (95%) diff --git a/cmd/kwil-admin/cmds/setup/peer.go b/cmd/kwil-admin/cmds/setup/peer.go index d3a508dcc..c9955ad65 100644 --- a/cmd/kwil-admin/cmds/setup/peer.go +++ b/cmd/kwil-admin/cmds/setup/peer.go @@ -3,7 +3,6 @@ package setup import ( "os" "path/filepath" - "strings" "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-admin/nodecfg" @@ -17,12 +16,12 @@ var ( It will automatically generate required directories and keypairs, and can be given a genesis file and peer list for an existing network.` peerExample = `# Initialize a node as a peer to an existing network -` // TODO: add example +kwil-admin setup peer --root-dir ./kwil-node --genesis /path/to/genesis.json --peers` ) func peerCmd() *cobra.Command { - var out, genesisPath string - var peers []string + cfg := config.EmptyConfig() + var genesisPath string cmd := &cobra.Command{ Use: "peer", @@ -31,7 +30,7 @@ func peerCmd() *cobra.Command { Example: peerExample, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - expandedDir, err := expandPath(out) + expandedDir, err := expandPath(cfg.RootDir) if err != nil { return display.PrintErr(cmd, err) } @@ -59,14 +58,6 @@ func peerCmd() *cobra.Command { } } - cleanedPeers := make([]string, 0) - for _, peer := range peers { - cleanedPeers = append(cleanedPeers, strings.TrimSpace(peer)) - } - - cfg := config.EmptyConfig() - cfg.ChainCfg.P2P.PersistentPeers = strings.Join(cleanedPeers, ",") - _, err = nodecfg.GenerateNodeFiles(expandedDir, cfg) if err != nil { return display.PrintErr(cmd, err) @@ -76,9 +67,8 @@ func peerCmd() *cobra.Command { }, } - cmd.Flags().StringVarP(&out, "output-dir", "o", "./kwild-node", "generated node parent directory [default: ./kwild-node]") cmd.Flags().StringVarP(&genesisPath, "genesis", "g", "", "path to genesis file") - cmd.Flags().StringSliceVarP(&peers, "peer", "p", nil, "peer to connect to (may be given multiple times, or as a comma-separated list)") + config.AddConfigFlags(cmd.Flags(), cfg) return cmd } diff --git a/cmd/kwil-admin/cmds/validators/list-join-requests.go b/cmd/kwil-admin/cmds/validators/list-join-requests.go index 060f1eb05..e7954c06d 100644 --- a/cmd/kwil-admin/cmds/validators/list-join-requests.go +++ b/cmd/kwil-admin/cmds/validators/list-join-requests.go @@ -17,7 +17,8 @@ import ( var ( listJoinRequestsLong = `Command ` + "`" + `list-join-requests` + "`" + ` lists all pending join requests. -Join requests are created when a validator wants to join the validator set. The validator must be approved by 2/3 of the current validator set to be added to the validator set.` +Join requests are created when a validator wants to join the validator set. The validator must be approved by 2/3 of the current validator set to be added to the validator set. +Each join request has an expiration block height, after which it is no longer valid.` listJoinRequestsExample = `# List all pending join requests kwil-admin validators list-join-requests` @@ -73,10 +74,9 @@ func (r *respJoinList) MarshalText() ([]byte, error) { // could be ideal to use the SQL table formatting here msg.WriteString(fmt.Sprintf("Pending join requests (%d %s needed):\n", needed, approvalTerm)) - msg.WriteString(" Candidate | Power | Approvals | Expiration") - // ---------------------------------+-------+-----------+------------- - //ref spacing: 22cbbb666c26b2c1f42502df72c32de4 | | | - // d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100 + msg.WriteString(" Candidate | Power | Approvals | Expiration\n") + msg.WriteString("------------------------------------------------------------------+-------+-----------+------------") + //ref spacing: 22cbbb666c26b2c1f42502df72c32de4d521138a1a2c96121d417a2f341a759c | 1 | 100 | 100 for _, j := range r.Joins { approvals := 0 for _, a := range j.Approved { @@ -85,11 +85,8 @@ func (r *respJoinList) MarshalText() ([]byte, error) { } } - hexPubKey := hex.EncodeToString(j.Candidate) - half := len(hexPubKey) / 2 - msg.WriteString("\n ---------------------------------+-------+-----------+-------------") - msg.WriteString(fmt.Sprintf("\n %s | % 5s | % 9s | %s", hexPubKey[0:half], "", "", "")) - msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", hexPubKey[half:], j.Power, approvals, j.ExpiresAt)) + msg.WriteString(fmt.Sprintf("\n %s | % 5d | % 9d | %d", hex.EncodeToString(j.Candidate), j.Power, approvals, j.ExpiresAt)) + } return msg.Bytes(), nil diff --git a/cmd/kwild/config/config.go b/cmd/kwild/config/config.go index 72fb4c95e..e8fb75486 100644 --- a/cmd/kwild/config/config.go +++ b/cmd/kwild/config/config.go @@ -35,7 +35,6 @@ var DefaultSQLitePath = filepath.Join("data", "kwild.db") // a folder, not a fil type KwildConfig struct { RootDir string - AutoGen bool AppCfg *AppConfig `mapstructure:"app"` ChainCfg *ChainConfig `mapstructure:"chain"` @@ -510,8 +509,8 @@ func (cfg *KwildConfig) sanitizeCfgPaths() { fmt.Println("Private key path:", cfg.AppCfg.PrivateKeyPath) } -func (cfg *KwildConfig) InitPrivateKeyAndGenesis() (privateKey *crypto.Ed25519PrivateKey, genConfig *GenesisConfig, err error) { - return loadGenesisAndPrivateKey(cfg.AutoGen, cfg.AppCfg.PrivateKeyPath, cfg.RootDir) +func (cfg *KwildConfig) InitPrivateKeyAndGenesis(autogen bool) (privateKey *crypto.Ed25519PrivateKey, genConfig *GenesisConfig, err error) { + return loadGenesisAndPrivateKey(autogen, cfg.AppCfg.PrivateKeyPath, cfg.RootDir) } func ExpandPath(path string) (string, error) { diff --git a/cmd/kwild/flags.go b/cmd/kwild/config/flags.go similarity index 95% rename from cmd/kwild/flags.go rename to cmd/kwild/config/flags.go index 5aa50f9b6..de70b4b67 100644 --- a/cmd/kwild/flags.go +++ b/cmd/kwild/config/flags.go @@ -1,14 +1,9 @@ -package main +package config -import ( - "github.com/kwilteam/kwil-db/cmd/kwild/config" +import "github.com/spf13/pflag" - "github.com/spf13/pflag" -) - -func addKwildFlags(flagSet *pflag.FlagSet, cfg *config.KwildConfig) { - flagSet.BoolVarP(&cfg.AutoGen, "autogen", "a", false, - "auto generate private key and genesis file if not exist") +// AddConfigFlags adds all flags from KwildConfig to the given flagSet +func AddConfigFlags(flagSet *pflag.FlagSet, cfg *KwildConfig) { flagSet.StringVarP(&cfg.RootDir, "root-dir", "r", "~/.kwild", "kwild root directory for config and data") // logging diff --git a/cmd/kwild/main.go b/cmd/kwild/main.go index b91ba991b..132a90f2a 100644 --- a/cmd/kwild/main.go +++ b/cmd/kwild/main.go @@ -35,6 +35,7 @@ func main() { func rootCmd() *cobra.Command { flagCfg := config.EmptyConfig() + var autoGen bool cmd := &cobra.Command{ Use: "kwild", @@ -50,7 +51,7 @@ func rootCmd() *cobra.Command { return err } - nodeKey, genesisConfig, err := kwildCfg.InitPrivateKeyAndGenesis() + nodeKey, genesisConfig, err := kwildCfg.InitPrivateKeyAndGenesis(autoGen) if err != nil { return fmt.Errorf("failed to initialize private key and genesis: %w", err) } @@ -70,7 +71,7 @@ func rootCmd() *cobra.Command { cancel() }() - svr, err := server.New(ctx, kwildCfg, genesisConfig, nodeKey) + svr, err := server.New(ctx, kwildCfg, genesisConfig, nodeKey, autoGen) if err != nil { return err } @@ -81,7 +82,10 @@ func rootCmd() *cobra.Command { flagSet := cmd.Flags() flagSet.SortFlags = false - addKwildFlags(flagSet, flagCfg) + config.AddConfigFlags(flagSet, flagCfg) + + flagSet.BoolVarP(&autoGen, "autogen", "a", false, + "auto generate private key and genesis file if not exist") return cmd } diff --git a/cmd/kwild/server/build.go b/cmd/kwild/server/build.go index c7b356248..c84ead277 100644 --- a/cmd/kwild/server/build.go +++ b/cmd/kwild/server/build.go @@ -115,6 +115,7 @@ const ( // coreDependencies holds dependencies that are widely used type coreDependencies struct { ctx context.Context + autogen bool cfg *config.KwildConfig genesisCfg *config.GenesisConfig privKey cmtEd.PrivKey @@ -441,7 +442,7 @@ func buildAdminService(d *coreDependencies, closer *closeFuncs, admsvc admpb.Adm if err != nil { failBuild(err, "failed to load client CAs file") } - } else if d.cfg.AutoGen { + } else if d.autogen { clientCredsFileBase := filepath.Join(d.cfg.RootDir, "auth") clientCertFile, clientKeyFile := clientCredsFileBase+".cert", clientCredsFileBase+".key" err = transport.GenTLSKeyPair(clientCertFile, clientKeyFile, "kwild CA", nil) diff --git a/cmd/kwild/server/server.go b/cmd/kwild/server/server.go index f494799f7..8f6327c71 100644 --- a/cmd/kwild/server/server.go +++ b/cmd/kwild/server/server.go @@ -54,7 +54,7 @@ const ( ) // New builds the kwild server. -func New(ctx context.Context, cfg *config.KwildConfig, genesisCfg *config.GenesisConfig, nodeKey *crypto.Ed25519PrivateKey) (svr *Server, err error) { +func New(ctx context.Context, cfg *config.KwildConfig, genesisCfg *config.GenesisConfig, nodeKey *crypto.Ed25519PrivateKey, autogen bool) (svr *Server, err error) { closers := &closeFuncs{ closers: make([]func() error, 0), } @@ -98,6 +98,7 @@ func New(ctx context.Context, cfg *config.KwildConfig, genesisCfg *config.Genesi deps := &coreDependencies{ ctx: ctx, + autogen: autogen, cfg: cfg, genesisCfg: genesisCfg, privKey: ed25519.PrivKey(nodeKey.Bytes()), From 36e4b790103cf092b78a1af40e5d768a071f8809 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:08:08 -0600 Subject: [PATCH 05/13] removed empty config --- cmd/kwil-admin/cmds/setup/peer.go | 2 +- cmd/kwild/config/config.go | 18 ------------------ cmd/kwild/main.go | 2 +- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/cmd/kwil-admin/cmds/setup/peer.go b/cmd/kwil-admin/cmds/setup/peer.go index c9955ad65..84d5ee136 100644 --- a/cmd/kwil-admin/cmds/setup/peer.go +++ b/cmd/kwil-admin/cmds/setup/peer.go @@ -20,7 +20,7 @@ kwil-admin setup peer --root-dir ./kwil-node --genesis /path/to/genesis.json --p ) func peerCmd() *cobra.Command { - cfg := config.EmptyConfig() + cfg := config.DefaultConfig() var genesisPath string cmd := &cobra.Command{ diff --git a/cmd/kwild/config/config.go b/cmd/kwild/config/config.go index e8fb75486..7e54008c2 100644 --- a/cmd/kwild/config/config.go +++ b/cmd/kwild/config/config.go @@ -445,24 +445,6 @@ func DefaultConfig() *KwildConfig { } } -func EmptyConfig() *KwildConfig { - return &KwildConfig{ - AppCfg: &AppConfig{ - ExtensionEndpoints: []string{}, - }, - ChainCfg: &ChainConfig{ - P2P: &P2PConfig{}, - RPC: &ChainRPCConfig{}, - Mempool: &MempoolConfig{}, - StateSync: &StateSyncConfig{ - RPCServers: []string{}, - }, - Consensus: &ConsensusConfig{}, - }, - Logging: &Logging{}, - } -} - func (cfg *KwildConfig) LogConfig() *log.Config { // Rootify any relative paths. outputPaths := make([]string, 0, len(cfg.Logging.OutputPaths)) diff --git a/cmd/kwild/main.go b/cmd/kwild/main.go index 132a90f2a..344797299 100644 --- a/cmd/kwild/main.go +++ b/cmd/kwild/main.go @@ -34,7 +34,7 @@ func main() { } func rootCmd() *cobra.Command { - flagCfg := config.EmptyConfig() + flagCfg := config.DefaultConfig() var autoGen bool cmd := &cobra.Command{ From b26f07b461cff1f218b52710076b2197c4c37ce8 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 01:33:52 -0600 Subject: [PATCH 06/13] added config dump for admin tool, fixed bug where an empty config is needed for kwild, and renamed client constructors --- cmd/kwil-admin/cmds/common/rpc.go | 2 +- cmd/kwil-admin/cmds/node/cmd.go | 2 +- cmd/kwil-admin/cmds/node/dump-cfg.go | 71 ++++++++++ cmd/kwil-cli/cmds/common/roundtripper.go | 6 +- cmd/kwil-cli/cmds/database/flags.go | 2 +- cmd/kwil-cli/cmds/database/list.go | 54 ++++++-- cmd/kwil-cli/cmds/database/message.go | 51 +++---- cmd/kwil-cli/cmds/database/message_test.go | 84 ++++++++--- cmd/kwild/config/config.go | 36 +++++ cmd/kwild/main.go | 3 +- cmd/kwild/server/build.go | 2 +- core/adminclient/client.go | 4 +- core/client/client.go | 6 +- core/gatewayclient/client.go | 2 +- core/rpc/client/admin/admin.go | 3 + core/rpc/client/admin/grpc/client.go | 19 +++ core/rpc/client/user/grpc/rpc.go | 13 +- core/rpc/client/user/http/client.go | 21 ++- core/rpc/client/user/txsvc.go | 2 +- core/rpc/http/tx/README.md | 1 + core/rpc/http/tx/api/swagger.yaml | 25 +++- core/rpc/http/tx/docs/TxDatasetInfo.md | 11 ++ .../http/tx/docs/TxListDatabasesResponse.md | 2 +- core/rpc/http/tx/model_tx_dataset_info.go | 15 ++ .../tx/model_tx_list_databases_response.go | 2 +- core/rpc/protobuf/admin/v0/messages.pb.go | 130 +++++++++++++++++- core/rpc/protobuf/admin/v0/service.pb.go | 61 ++++---- core/rpc/protobuf/admin/v0/service_grpc.pb.go | 37 +++++ core/rpc/protobuf/tx/v1/list.pb.go | 117 +++++++++++++--- core/types/types.go | 7 + internal/engine/execution/execution_test.go | 4 +- internal/engine/execution/global.go | 29 +++- internal/engine/integration/execution_test.go | 2 +- internal/modules/datasets/interfaces.go | 3 +- internal/modules/datasets/read.go | 3 +- internal/services/grpc/admin/v0/service.go | 17 ++- internal/services/grpc/txsvc/v1/list.go | 11 +- internal/services/grpc/txsvc/v1/service.go | 7 +- internal/services/http/api/tx/v1.swagger.json | 18 ++- proto | 2 +- test/acceptance/helper.go | 2 +- test/acceptance/kwild_test.go | 16 +++ test/driver/cli_driver.go | 36 ++--- test/driver/client_driver.go | 13 +- test/integration/helper.go | 2 +- test/stress/transport.go | 2 +- 46 files changed, 777 insertions(+), 181 deletions(-) create mode 100644 cmd/kwil-admin/cmds/node/dump-cfg.go create mode 100644 core/rpc/http/tx/docs/TxDatasetInfo.md create mode 100644 core/rpc/http/tx/model_tx_dataset_info.go diff --git a/cmd/kwil-admin/cmds/common/rpc.go b/cmd/kwil-admin/cmds/common/rpc.go index 47c5b7fca..2de3b2fe0 100644 --- a/cmd/kwil-admin/cmds/common/rpc.go +++ b/cmd/kwil-admin/cmds/common/rpc.go @@ -51,7 +51,7 @@ func GetAdminSvcClient(ctx context.Context, cmd *cobra.Command) (*adminclient.Ad dialOpt = append(dialOpt, adminclient.WithTLS(kwildTLSCertFile, clientTLSKeyFile, clientTLSCertFile)) } - return adminclient.New(ctx, rpcServer, dialOpt...) + return adminclient.NewClient(ctx, rpcServer, dialOpt...) } const ( diff --git a/cmd/kwil-admin/cmds/node/cmd.go b/cmd/kwil-admin/cmds/node/cmd.go index 2428d0c7d..db0b7f91f 100644 --- a/cmd/kwil-admin/cmds/node/cmd.go +++ b/cmd/kwil-admin/cmds/node/cmd.go @@ -14,7 +14,7 @@ var nodeCmd = &cobra.Command{ func NewNodeCmd() *cobra.Command { nodeCmd.AddCommand( - + dumpCfgCmd(), versionCmd(), statusCmd(), peersCmd(), diff --git a/cmd/kwil-admin/cmds/node/dump-cfg.go b/cmd/kwil-admin/cmds/node/dump-cfg.go new file mode 100644 index 000000000..cc2ba582c --- /dev/null +++ b/cmd/kwil-admin/cmds/node/dump-cfg.go @@ -0,0 +1,71 @@ +package node + +import ( + "context" + "encoding/json" + + "github.com/kwilteam/kwil-db/cmd/common/display" + "github.com/kwilteam/kwil-db/cmd/kwil-admin/cmds/common" + "github.com/kwilteam/kwil-db/cmd/kwild/config" + "github.com/mitchellh/mapstructure" + "github.com/spf13/cobra" +) + +var ( + dumpCfgLong = `Gets the current config from the node.` + dumpCfgExample = `# Get the current config from the node. +kwil node dump-config --rpcserver unix:///tmp/kwil_admin.sock` +) + +func dumpCfgCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "dump-config", + Short: "Gets the current config from the node.", + Long: dumpCfgLong, + Example: dumpCfgExample, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + client, err := common.GetAdminSvcClient(ctx, cmd) + if err != nil { + return display.PrintErr(cmd, err) + } + + cfg, err := client.GetConfig(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + return display.PrintCmd(cmd, &cfgMsg{cfg: cfg}) + }, + } + + common.BindRPCFlags(cmd) + + return cmd +} + +type cfgMsg struct { + cfg *config.KwildConfig +} + +var _ display.MsgFormatter = (*cfgMsg)(nil) + +func (c *cfgMsg) MarshalJSON() ([]byte, error) { + maps := make(map[string]interface{}) + err := mapstructure.Decode(c.cfg, &maps) + if err != nil { + return nil, err + } + + return json.Marshal(maps) +} + +func (c *cfgMsg) MarshalText() ([]byte, error) { + maps := make(map[string]interface{}) + err := mapstructure.Decode(c.cfg, &maps) + if err != nil { + return nil, err + } + + return json.MarshalIndent(maps, "", " ") +} diff --git a/cmd/kwil-cli/cmds/common/roundtripper.go b/cmd/kwil-cli/cmds/common/roundtripper.go index 3adc5086f..1d2beeb41 100644 --- a/cmd/kwil-cli/cmds/common/roundtripper.go +++ b/cmd/kwil-cli/cmds/common/roundtripper.go @@ -50,7 +50,7 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr // if not using the gateway, then we can simply create a regular client and return if flags&UsingGateway == 0 { - client, err := client.Dial(ctx, conf.GrpcURL, &clientConfig) + client, err := client.NewClient(ctx, conf.GrpcURL, &clientConfig) if err != nil { return err } @@ -60,7 +60,7 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr // if we reach here, we are talking to a gateway - client, err := gatewayclient.NewGatewayClient(ctx, conf.GrpcURL, &gatewayclient.GatewayOptions{ + client, err := gatewayclient.NewClient(ctx, conf.GrpcURL, &gatewayclient.GatewayOptions{ ClientOptions: clientConfig, AuthSignFunc: func(message string, signer auth.Signer) (*auth.Signature, error) { assumeYes, err := GetAssumeYesFlag(cmd) @@ -122,7 +122,7 @@ type Client interface { ExecuteAction(ctx context.Context, dbid string, action string, tuples [][]any, opts ...client.TxOpt) (transactions.TxHash, error) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) - ListDatabases(ctx context.Context, owner []byte) ([]string, error) + ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetInfo, error) Ping(ctx context.Context) (string, error) Query(ctx context.Context, dbid string, query string) (*client.Records, error) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) diff --git a/cmd/kwil-cli/cmds/database/flags.go b/cmd/kwil-cli/cmds/database/flags.go index f848b6829..57125dc64 100644 --- a/cmd/kwil-cli/cmds/database/flags.go +++ b/cmd/kwil-cli/cmds/database/flags.go @@ -41,7 +41,7 @@ func getSelectedOwner(cmd *cobra.Command, conf *config.KwilCliConfig) ([]byte, e } else { if conf.PrivateKey == nil { - return nil, fmt.Errorf("no public key provided") + return nil, nil // nil is a valid owner, as it will return all } signer := auth.EthPersonalSigner{Key: *conf.PrivateKey} diff --git a/cmd/kwil-cli/cmds/database/list.go b/cmd/kwil-cli/cmds/database/list.go index 8df7898e3..98bd7697c 100644 --- a/cmd/kwil-cli/cmds/database/list.go +++ b/cmd/kwil-cli/cmds/database/list.go @@ -2,22 +2,37 @@ package database import ( "context" + "encoding/hex" + "errors" + "fmt" "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/cmd/kwil-cli/cmds/common" "github.com/kwilteam/kwil-db/cmd/kwil-cli/config" + "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/spf13/cobra" ) var ( listLong = `List databases owned by a wallet. -An owner can be specified with the --owner flag. If no owner is specified, the locally configured wallet is used.` +An owner can be specified with the ` + "`" + `--owner` + "`" + ` flag. If no owner is specified, then it will return all databases deployed on the network. +If the ` + "`" + `--self` + "`" + ` flag is specified, then the owner will be set to the current configured wallet.` + listExample = `# list databases owned by the wallet "0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64" -kwil-cli database list --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64` +kwil-cli database list --owner 0x9228624C3185FCBcf24c1c9dB76D8Bef5f5DAd64 + +# list all databases deployed on the network +kwil-cli database list + +# list databases owned by the current configured wallet +kwil-cli database list --self` ) func listCmd() *cobra.Command { + var owner string + var self bool + cmd := &cobra.Command{ Use: "list", Short: "List databases owned by a wallet.", @@ -27,26 +42,39 @@ func listCmd() *cobra.Command { SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { return common.DialClient(cmd.Context(), cmd, common.WithoutPrivateKey, func(ctx context.Context, client common.Client, conf *config.KwilCliConfig) error { - owner, err := getSelectedOwner(cmd, conf) - if err != nil { - return display.PrintErr(cmd, err) + if owner != "" && self { + return display.PrintErr(cmd, errors.New("cannot specify both --owner and --self")) } - dbs, err := client.ListDatabases(ctx, owner) - if err != nil { - return display.PrintErr(cmd, err) + var ownerIdent []byte + if self { + if conf.PrivateKey == nil { + return display.PrintErr(cmd, errors.New("must have a configured wallet to use --self")) + } + ownerIdent = (&auth.EthPersonalSigner{Key: *conf.PrivateKey}).Identity() + } else if owner != "" { + var err error + ownerIdent, err = hex.DecodeString(owner) + if err != nil { + return display.PrintErr(cmd, fmt.Errorf("failed to decode hex owner: %w", err)) + } } - resp := &respDBList{ - Databases: dbs, - Owner: owner, + dbs, err := client.ListDatabases(ctx, ownerIdent) + if err != nil { + return display.PrintErr(cmd, err) } - return display.PrintCmd(cmd, resp) + return display.PrintCmd(cmd, &respDBList{ + Info: dbs, + owner: ownerIdent, + }) }) }, } - cmd.Flags().StringP(ownerFlag, "o", "", "The owner of the database") + cmd.Flags().StringVarP(&owner, ownerFlag, "o", "", "the owner of the database") + cmd.Flags().BoolVar(&self, "self", false, "use the current configured wallet as the owner") + return cmd } diff --git a/cmd/kwil-cli/cmds/database/message.go b/cmd/kwil-cli/cmds/database/message.go index ae53fd1d2..023bcd2f8 100644 --- a/cmd/kwil-cli/cmds/database/message.go +++ b/cmd/kwil-cli/cmds/database/message.go @@ -7,8 +7,8 @@ import ( "sort" "github.com/kwilteam/kwil-db/core/client" + "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" - "github.com/kwilteam/kwil-db/core/utils" "github.com/olekukonko/tablewriter" ) @@ -21,45 +21,36 @@ import ( // respDBList represent databases belong to an owner in cli type respDBList struct { - Databases []string `json:"databases"` - Owner []byte `json:"owner"` -} - -type dbInfo struct { - Name string `json:"name"` - Id string `json:"id"` + Info []*types.DatasetInfo + // owner is the owner configured in cli + owner []byte } func (d *respDBList) MarshalJSON() ([]byte, error) { - dbs := make([]dbInfo, len(d.Databases)) - - for i, db := range d.Databases { - dbs[i] = dbInfo{ - Name: db, - Id: utils.GenerateDBID(db, d.Owner), - } - } - - return json.Marshal(struct { - Databases []dbInfo `json:"databases"` - Owner string `json:"owner"` - }{ - Databases: dbs, - Owner: fmt.Sprintf("%x", d.Owner), - }) + return json.Marshal(d.Info) } func (d *respDBList) MarshalText() ([]byte, error) { - if len(d.Databases) == 0 { - return []byte(fmt.Sprintf("No databases found for '%x'.", d.Owner)), nil + if len(d.Info) == 0 { + return []byte(fmt.Sprintf("No databases found for '%x'.", d.owner)), nil } - msg := fmt.Sprintf("Databases belonging to '%x':\n", d.Owner) - for _, db := range d.Databases { - msg += fmt.Sprintf(" - %s (dbid:%s)\n", db, utils.GenerateDBID(db, d.Owner)) + var msg bytes.Buffer + if len(d.owner) == 0 { + msg.WriteString("Databases:\n") + } else { + msg.WriteString(fmt.Sprintf("Databases belonging to '%x':\n", d.owner)) + } + for i, db := range d.Info { + msg.WriteString(fmt.Sprintf(" DBID: %s\n", db.DBID)) + msg.WriteString(fmt.Sprintf(" Name: %s\n", db.Name)) + msg.WriteString(fmt.Sprintf(" Owner: %x", db.Owner)) + if i != len(d.Info)-1 { + msg.WriteString("\n") + } } - return []byte(msg), nil + return msg.Bytes(), nil } // respRelations is a slice of maps that represent the relations(from set theory) diff --git a/cmd/kwil-cli/cmds/database/message_test.go b/cmd/kwil-cli/cmds/database/message_test.go index 24f1e6a4c..68ae46728 100644 --- a/cmd/kwil-cli/cmds/database/message_test.go +++ b/cmd/kwil-cli/cmds/database/message_test.go @@ -1,14 +1,18 @@ package database import ( + "encoding/base64" + "encoding/hex" + "github.com/kwilteam/kwil-db/cmd/common/display" "github.com/kwilteam/kwil-db/core/client" + "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" ) func Example_respDBlist_text_0() { display.Print( - &respDBList{Databases: []string{}, Owner: []byte("owner")}, + &respDBList{Info: []*types.DatasetInfo{}, owner: mustDecodeHex("6f776e6572")}, nil, "text") // Output: // No databases found for '6f776e6572'. @@ -16,33 +20,77 @@ func Example_respDBlist_text_0() { func Example_respDBlist_text() { display.Print( - &respDBList{Databases: []string{"db_a", "db_b"}, Owner: []byte("owner")}, + &respDBList{Info: []*types.DatasetInfo{ + { + Name: "db_a", + Owner: mustDecodeHex("6f776e6572"), + DBID: "xabc", + }, + { + Name: "db_b", + Owner: mustDecodeHex("6f776e6572"), + DBID: "xdef", + }, + }, + owner: mustDecodeHex("6f776e6572")}, nil, "text") // Output: // Databases belonging to '6f776e6572': - // - db_a (dbid:xf1a24857f73e3bbdeaae383338e8fb4bde364e959207bd2327e375ea) - // - db_b (dbid:x63e828a14a11c00b84adc9fc1473c5104557cd857ca81588638bb1f3) + // DBID: xabc + // Name: db_a + // Owner: 6f776e6572 + // DBID: xdef + // Name: db_b + // Owner: 6f776e6572 +} + +func mustDecodeHex(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +func mustDecodeBase64(s string) []byte { + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return b } func Example_respDBlist_json() { + display.Print( - &respDBList{Databases: []string{"db_a", "db_b"}, Owner: []byte("owner")}, + &respDBList{Info: []*types.DatasetInfo{ + { + Name: "db_a", + Owner: mustDecodeBase64("b3duZXI="), + DBID: "xabc", + }, + { + Name: "db_b", + Owner: mustDecodeBase64("b3duZXI="), + DBID: "xdef", + }, + }}, nil, "json") + // Output: // { - // "result": { - // "databases": [ - // { - // "name": "db_a", - // "id": "xf1a24857f73e3bbdeaae383338e8fb4bde364e959207bd2327e375ea" - // }, - // { - // "name": "db_b", - // "id": "x63e828a14a11c00b84adc9fc1473c5104557cd857ca81588638bb1f3" - // } - // ], - // "owner": "6f776e6572" - // }, + // "result": [ + // { + // "name": "db_a", + // "owner": "b3duZXI=", + // "dbid": "xabc" + // }, + // { + // "name": "db_b", + // "owner": "b3duZXI=", + // "dbid": "xdef" + // } + // ], // "error": "" // } } diff --git a/cmd/kwild/config/config.go b/cmd/kwild/config/config.go index 7e54008c2..e497462c5 100644 --- a/cmd/kwild/config/config.go +++ b/cmd/kwild/config/config.go @@ -6,6 +6,7 @@ import ( "bytes" "encoding" "encoding/hex" + "encoding/json" "fmt" "os" "path/filepath" @@ -194,6 +195,21 @@ func (a *KwildConfig) Merge(b *KwildConfig) error { return merge.MergeWithOverwrite(a, b) } +func (a *KwildConfig) MarshalBinary() ([]byte, error) { + mapCfg := make(map[string]interface{}) + mapstructure.Decode(a, &mapCfg) + return json.Marshal(mapCfg) +} + +func (a *KwildConfig) UnmarshalBinary(b []byte) error { + mapCfg := make(map[string]interface{}) + err := json.Unmarshal(b, &mapCfg) + if err != nil { + return err + } + return mapstructure.Decode(mapCfg, a) +} + func defaultMoniker() string { moniker, err := os.Hostname() if err != nil { @@ -445,6 +461,26 @@ func DefaultConfig() *KwildConfig { } } +// EmptyConfig returns a config with all fields set to their zero values. +// This is useful for guaranteeing that all fields are set when merging +func EmptyConfig() *KwildConfig { + return &KwildConfig{ + AppCfg: &AppConfig{ + ExtensionEndpoints: []string{}, + }, + ChainCfg: &ChainConfig{ + P2P: &P2PConfig{}, + RPC: &ChainRPCConfig{}, + Mempool: &MempoolConfig{}, + StateSync: &StateSyncConfig{ + RPCServers: []string{}, + }, + Consensus: &ConsensusConfig{}, + }, + Logging: &Logging{}, + } +} + func (cfg *KwildConfig) LogConfig() *log.Config { // Rootify any relative paths. outputPaths := make([]string, 0, len(cfg.Logging.OutputPaths)) diff --git a/cmd/kwild/main.go b/cmd/kwild/main.go index 344797299..cb706b3f2 100644 --- a/cmd/kwild/main.go +++ b/cmd/kwild/main.go @@ -34,7 +34,8 @@ func main() { } func rootCmd() *cobra.Command { - flagCfg := config.DefaultConfig() + // we use an empty config because this config gets merged later, and should only contain flag values + flagCfg := config.EmptyConfig() var autoGen bool cmd := &cobra.Command{ diff --git a/cmd/kwild/server/build.go b/cmd/kwild/server/build.go index c84ead277..2e87b8592 100644 --- a/cmd/kwild/server/build.go +++ b/cmd/kwild/server/build.go @@ -194,7 +194,7 @@ func buildAdminSvc(d *coreDependencies, transactor admSvc.BlockchainTransactor, signer := auth.Ed25519Signer{Ed25519PrivateKey: *pk} - return admSvc.NewService(transactor, node, validatorStore, &signer, + return admSvc.NewService(transactor, node, validatorStore, &signer, d.cfg, admSvc.WithLogger(*d.log.Named("admin-service")), ) } diff --git a/core/adminclient/client.go b/core/adminclient/client.go index 2b6efa18e..586279e4a 100644 --- a/core/adminclient/client.go +++ b/core/adminclient/client.go @@ -44,10 +44,10 @@ type txClient interface { TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) } -// New creates a new admin client. +// NewClient creates a new admin client. // It can be configured to either use TLS or not, if using gRPC. // The target arg should be either "tcp://localhost:50151", "localhost:50151", or "unix://path/to/socket.sock" -func New(ctx context.Context, target string, opts ...AdminClientOpt) (*AdminClient, error) { +func NewClient(ctx context.Context, target string, opts ...AdminClientOpt) (*AdminClient, error) { c := &AdminClient{ log: log.NewNoOp(), } diff --git a/core/client/client.go b/core/client/client.go index 5920415c1..55bf6f450 100644 --- a/core/client/client.go +++ b/core/client/client.go @@ -35,9 +35,9 @@ type Client struct { noWarnings bool // silence warning logs } -// Dial creates a Kwil client. It will dial the remote host via HTTP, and +// NewClient creates a Kwil client. It will dial the remote host via HTTP, and // verify the chain ID of the remote host against the chain ID passed in. -func Dial(ctx context.Context, target string, options *ClientOptions) (c *Client, err error) { +func NewClient(ctx context.Context, target string, options *ClientOptions) (c *Client, err error) { parsedUrl, err := url.Parse(target) if err != nil { return nil, fmt.Errorf("parse url: %w", err) @@ -228,7 +228,7 @@ func (c *Client) Query(ctx context.Context, dbid string, query string) (*Records return NewRecordsFromMaps(res), nil } -func (c *Client) ListDatabases(ctx context.Context, owner []byte) ([]string, error) { +func (c *Client) ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetInfo, error) { return c.txClient.ListDatabases(ctx, owner) } diff --git a/core/gatewayclient/client.go b/core/gatewayclient/client.go index 69880632b..ce3bbeeea 100644 --- a/core/gatewayclient/client.go +++ b/core/gatewayclient/client.go @@ -33,7 +33,7 @@ type GatewayClient struct { gatewaySigner GatewayAuthSignFunc // a hook for when the gateway authentication is needed } -func NewGatewayClient(ctx context.Context, target string, opts *GatewayOptions) (*GatewayClient, error) { +func NewClient(ctx context.Context, target string, opts *GatewayOptions) (*GatewayClient, error) { options := DefaultOptions() options.Apply(opts) diff --git a/core/rpc/client/admin/admin.go b/core/rpc/client/admin/admin.go index a133f15d4..ae9d199a9 100644 --- a/core/rpc/client/admin/admin.go +++ b/core/rpc/client/admin/admin.go @@ -4,6 +4,7 @@ package admin import ( "context" + "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/core/types" adminTypes "github.com/kwilteam/kwil-db/core/types/admin" ) @@ -19,4 +20,6 @@ type AdminClient interface { Status(ctx context.Context) (*adminTypes.Status, error) Version(ctx context.Context) (string, error) ListPendingJoins(ctx context.Context) ([]*types.JoinRequest, error) + // GetConfig gets the current config from the node. + GetConfig(ctx context.Context) (*config.KwildConfig, error) } diff --git a/core/rpc/client/admin/grpc/client.go b/core/rpc/client/admin/grpc/client.go index 6ba4f5226..17fd8752e 100644 --- a/core/rpc/client/admin/grpc/client.go +++ b/core/rpc/client/admin/grpc/client.go @@ -5,7 +5,9 @@ import ( "context" "time" + "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/core/rpc/client" + adminRPC "github.com/kwilteam/kwil-db/core/rpc/client/admin" admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" "github.com/kwilteam/kwil-db/core/types" adminTypes "github.com/kwilteam/kwil-db/core/types/admin" @@ -17,6 +19,8 @@ type GrpcAdminClient struct { client admpb.AdminServiceClient } +var _ adminRPC.AdminClient = (*GrpcAdminClient)(nil) + // NewAdminClient creates a grpc client for the Kwil admin service. func NewAdminClient(conn *grpc.ClientConn) *GrpcAdminClient { return &GrpcAdminClient{ @@ -159,6 +163,21 @@ func (c *GrpcAdminClient) ListPendingJoins(ctx context.Context) ([]*types.JoinRe return joins, nil } +func (c *GrpcAdminClient) GetConfig(ctx context.Context) (*config.KwildConfig, error) { + resp, err := c.client.GetConfig(ctx, &admpb.GetConfigRequest{}) + if err != nil { + return nil, client.ConvertGRPCErr(err) + } + + cfg := &config.KwildConfig{} + err = cfg.UnmarshalBinary(resp.Config) + if err != nil { + return nil, err + } + + return cfg, nil +} + func convertPendingJoin(join *admpb.PendingJoin) *types.JoinRequest { return &types.JoinRequest{ Candidate: join.Candidate, diff --git a/core/rpc/client/user/grpc/rpc.go b/core/rpc/client/user/grpc/rpc.go index e2204938a..43937c586 100644 --- a/core/rpc/client/user/grpc/rpc.go +++ b/core/rpc/client/user/grpc/rpc.go @@ -172,7 +172,7 @@ type SvcConfig struct { ProviderAddress string } -func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]string, error) { +func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetInfo, error) { res, err := c.TxClient.ListDatabases(ctx, &txpb.ListDatabasesRequest{ Owner: ownerIdentifier, }) @@ -181,7 +181,16 @@ func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]s return nil, fmt.Errorf("failed to list databases: %w", err) } - return res.Databases, nil + datasets := make([]*types.DatasetInfo, len(res.Databases)) + for i, db := range res.Databases { + datasets[i] = &types.DatasetInfo{ + Name: db.Name, + Owner: db.Owner, + DBID: db.Dbid, + } + } + + return datasets, nil } func (c *Client) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) { diff --git a/core/rpc/client/user/http/client.go b/core/rpc/client/user/http/client.go index 60c94890c..ece167f6c 100644 --- a/core/rpc/client/user/http/client.go +++ b/core/rpc/client/user/http/client.go @@ -187,14 +187,29 @@ func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Sche return convertedSchema, nil } -func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]string, error) { - result, res, err := c.conn.TxServiceApi.TxServiceListDatabases(ctx, base64.StdEncoding.EncodeToString(ownerPubKey)) +func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetInfo, error) { + // we need to use b64url since this method uses a query string + result, res, err := c.conn.TxServiceApi.TxServiceListDatabases(ctx, base64.URLEncoding.EncodeToString(ownerPubKey)) if err != nil { return nil, err } defer res.Body.Close() - return result.Databases, nil + datasets := make([]*types.DatasetInfo, 0, len(result.Databases)) + for _, db := range result.Databases { + decodedOwner, err := base64.StdEncoding.DecodeString(db.Owner) + if err != nil { + return nil, err + } + + datasets = append(datasets, &types.DatasetInfo{ + Name: db.Name, + Owner: decodedOwner, + DBID: db.Dbid, + }) + } + + return datasets, nil } func (c *Client) Ping(ctx context.Context) (string, error) { diff --git a/core/rpc/client/user/txsvc.go b/core/rpc/client/user/txsvc.go index 7f8b75345..9e1047ff9 100644 --- a/core/rpc/client/user/txsvc.go +++ b/core/rpc/client/user/txsvc.go @@ -20,7 +20,7 @@ type TxSvcClient interface { EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) - ListDatabases(ctx context.Context, ownerPubKey []byte) ([]string, error) + ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetInfo, error) Ping(ctx context.Context) (string, error) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) diff --git a/core/rpc/http/tx/README.md b/core/rpc/http/tx/README.md index f2bf96edd..0ec973248 100644 --- a/core/rpc/http/tx/README.md +++ b/core/rpc/http/tx/README.md @@ -48,6 +48,7 @@ Class | Method | HTTP request | Description - [TxCallResponse](docs/TxCallResponse.md) - [TxChainInfoResponse](docs/TxChainInfoResponse.md) - [TxColumn](docs/TxColumn.md) + - [TxDatasetInfo](docs/TxDatasetInfo.md) - [TxEstimatePriceRequest](docs/TxEstimatePriceRequest.md) - [TxEstimatePriceResponse](docs/TxEstimatePriceResponse.md) - [TxExtensions](docs/TxExtensions.md) diff --git a/core/rpc/http/tx/api/swagger.yaml b/core/rpc/http/tx/api/swagger.yaml index 90da7bd24..5377e1704 100644 --- a/core/rpc/http/tx/api/swagger.yaml +++ b/core/rpc/http/tx/api/swagger.yaml @@ -468,6 +468,21 @@ components: - type: type value: value type: type + txDatasetInfo: + type: object + properties: + name: + type: string + owner: + pattern: "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + type: string + format: byte + dbid: + type: string + example: + owner: "" + dbid: dbid + name: name txEstimatePriceRequest: type: object properties: @@ -746,11 +761,15 @@ components: databases: type: array items: - type: string + $ref: '#/components/schemas/txDatasetInfo' example: databases: - - databases - - databases + - owner: "" + dbid: dbid + name: name + - owner: "" + dbid: dbid + name: name txPingResponse: type: object properties: diff --git a/core/rpc/http/tx/docs/TxDatasetInfo.md b/core/rpc/http/tx/docs/TxDatasetInfo.md new file mode 100644 index 000000000..20c1d0ec4 --- /dev/null +++ b/core/rpc/http/tx/docs/TxDatasetInfo.md @@ -0,0 +1,11 @@ +# TxDatasetInfo + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | [optional] [default to null] +**Owner** | **string** | | [optional] [default to null] +**Dbid** | **string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/core/rpc/http/tx/docs/TxListDatabasesResponse.md b/core/rpc/http/tx/docs/TxListDatabasesResponse.md index db3a47b75..b7b655a0c 100644 --- a/core/rpc/http/tx/docs/TxListDatabasesResponse.md +++ b/core/rpc/http/tx/docs/TxListDatabasesResponse.md @@ -3,7 +3,7 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**Databases** | **[]string** | | [optional] [default to null] +**Databases** | [**[]TxDatasetInfo**](txDatasetInfo.md) | | [optional] [default to null] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/core/rpc/http/tx/model_tx_dataset_info.go b/core/rpc/http/tx/model_tx_dataset_info.go new file mode 100644 index 000000000..02dc55436 --- /dev/null +++ b/core/rpc/http/tx/model_tx_dataset_info.go @@ -0,0 +1,15 @@ +/* + * kwil/tx/v1/account.proto + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: version not set + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TxDatasetInfo struct { + Name string `json:"name,omitempty"` + Owner string `json:"owner,omitempty"` + Dbid string `json:"dbid,omitempty"` +} diff --git a/core/rpc/http/tx/model_tx_list_databases_response.go b/core/rpc/http/tx/model_tx_list_databases_response.go index 915350cdd..5836928a2 100644 --- a/core/rpc/http/tx/model_tx_list_databases_response.go +++ b/core/rpc/http/tx/model_tx_list_databases_response.go @@ -9,5 +9,5 @@ package swagger type TxListDatabasesResponse struct { - Databases []string `json:"databases,omitempty"` + Databases []TxDatasetInfo `json:"databases,omitempty"` } diff --git a/core/rpc/protobuf/admin/v0/messages.pb.go b/core/rpc/protobuf/admin/v0/messages.pb.go index 15c34eea9..d997cf091 100644 --- a/core/rpc/protobuf/admin/v0/messages.pb.go +++ b/core/rpc/protobuf/admin/v0/messages.pb.go @@ -1105,6 +1105,91 @@ func (x *ListJoinRequestsResponse) GetJoinRequests() []*PendingJoin { return nil } +type GetConfigRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetConfigRequest) Reset() { + *x = GetConfigRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConfigRequest) ProtoMessage() {} + +func (x *GetConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConfigRequest.ProtoReflect.Descriptor instead. +func (*GetConfigRequest) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{21} +} + +type GetConfigResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config []byte `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` // due to the size of the config, and how often it is updated, doing this for now +} + +func (x *GetConfigResponse) Reset() { + *x = GetConfigResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConfigResponse) ProtoMessage() {} + +func (x *GetConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_kwil_admin_v0_messages_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConfigResponse.ProtoReflect.Descriptor instead. +func (*GetConfigResponse) Descriptor() ([]byte, []int) { + return file_kwil_admin_v0_messages_proto_rawDescGZIP(), []int{22} +} + +func (x *GetConfigResponse) GetConfig() []byte { + if x != nil { + return x.Config + } + return nil +} + var File_kwil_admin_v0_messages_proto protoreflect.FileDescriptor var file_kwil_admin_v0_messages_proto_rawDesc = []byte{ @@ -1206,11 +1291,16 @@ var file_kwil_admin_v0_messages_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x0d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, - 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, - 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2b, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, + 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, + 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2f, 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -1225,7 +1315,7 @@ func file_kwil_admin_v0_messages_proto_rawDescGZIP() []byte { return file_kwil_admin_v0_messages_proto_rawDescData } -var file_kwil_admin_v0_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_kwil_admin_v0_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_kwil_admin_v0_messages_proto_goTypes = []interface{}{ (*VersionRequest)(nil), // 0: admin.VersionRequest (*VersionResponse)(nil), // 1: admin.VersionResponse @@ -1248,6 +1338,8 @@ var file_kwil_admin_v0_messages_proto_goTypes = []interface{}{ (*ListValidatorsResponse)(nil), // 18: admin.ListValidatorsResponse (*ListJoinRequestsRequest)(nil), // 19: admin.ListJoinRequestsRequest (*ListJoinRequestsResponse)(nil), // 20: admin.ListJoinRequestsResponse + (*GetConfigRequest)(nil), // 21: admin.GetConfigRequest + (*GetConfigResponse)(nil), // 22: admin.GetConfigResponse } var file_kwil_admin_v0_messages_proto_depIdxs = []int32{ 4, // 0: admin.StatusResponse.node:type_name -> admin.NodeInfo @@ -1523,6 +1615,30 @@ func file_kwil_admin_v0_messages_proto_init() { return nil } } + file_kwil_admin_v0_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetConfigRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_kwil_admin_v0_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetConfigResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1530,7 +1646,7 @@ func file_kwil_admin_v0_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kwil_admin_v0_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 21, + NumMessages: 23, NumExtensions: 0, NumServices: 0, }, diff --git a/core/rpc/protobuf/admin/v0/service.pb.go b/core/rpc/protobuf/admin/v0/service.pb.go index 67ce0c846..7dc916af8 100644 --- a/core/rpc/protobuf/admin/v0/service.pb.go +++ b/core/rpc/protobuf/admin/v0/service.pb.go @@ -31,7 +31,7 @@ var file_kwil_admin_v0_service_proto_rawDesc = []byte{ 0x74, 0x6f, 0x1a, 0x1a, 0x6b, 0x77, 0x69, 0x6c, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xfd, 0x06, 0x0a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xd5, 0x07, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, @@ -87,12 +87,17 @@ var file_kwil_admin_v0_service_proto_rawDesc = []byte{ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x6a, 0x6f, 0x69, 0x6e, 0x73, 0x42, 0x3e, 0x5a, 0x3c, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, - 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, - 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x61, 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x6a, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x56, 0x0a, 0x09, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x17, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, + 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x30, 0x3b, 0x61, + 0x64, 0x6d, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_kwil_admin_v0_service_proto_goTypes = []interface{}{ @@ -106,13 +111,15 @@ var file_kwil_admin_v0_service_proto_goTypes = []interface{}{ (*JoinStatusRequest)(nil), // 7: admin.JoinStatusRequest (*ListValidatorsRequest)(nil), // 8: admin.ListValidatorsRequest (*ListJoinRequestsRequest)(nil), // 9: admin.ListJoinRequestsRequest - (*VersionResponse)(nil), // 10: admin.VersionResponse - (*StatusResponse)(nil), // 11: admin.StatusResponse - (*PeersResponse)(nil), // 12: admin.PeersResponse - (*v1.BroadcastResponse)(nil), // 13: tx.BroadcastResponse - (*JoinStatusResponse)(nil), // 14: admin.JoinStatusResponse - (*ListValidatorsResponse)(nil), // 15: admin.ListValidatorsResponse - (*ListJoinRequestsResponse)(nil), // 16: admin.ListJoinRequestsResponse + (*GetConfigRequest)(nil), // 10: admin.GetConfigRequest + (*VersionResponse)(nil), // 11: admin.VersionResponse + (*StatusResponse)(nil), // 12: admin.StatusResponse + (*PeersResponse)(nil), // 13: admin.PeersResponse + (*v1.BroadcastResponse)(nil), // 14: tx.BroadcastResponse + (*JoinStatusResponse)(nil), // 15: admin.JoinStatusResponse + (*ListValidatorsResponse)(nil), // 16: admin.ListValidatorsResponse + (*ListJoinRequestsResponse)(nil), // 17: admin.ListJoinRequestsResponse + (*GetConfigResponse)(nil), // 18: admin.GetConfigResponse } var file_kwil_admin_v0_service_proto_depIdxs = []int32{ 0, // 0: admin.AdminService.Version:input_type -> admin.VersionRequest @@ -125,18 +132,20 @@ var file_kwil_admin_v0_service_proto_depIdxs = []int32{ 7, // 7: admin.AdminService.JoinStatus:input_type -> admin.JoinStatusRequest 8, // 8: admin.AdminService.ListValidators:input_type -> admin.ListValidatorsRequest 9, // 9: admin.AdminService.ListPendingJoins:input_type -> admin.ListJoinRequestsRequest - 10, // 10: admin.AdminService.Version:output_type -> admin.VersionResponse - 11, // 11: admin.AdminService.Status:output_type -> admin.StatusResponse - 12, // 12: admin.AdminService.Peers:output_type -> admin.PeersResponse - 13, // 13: admin.AdminService.Approve:output_type -> tx.BroadcastResponse - 13, // 14: admin.AdminService.Join:output_type -> tx.BroadcastResponse - 13, // 15: admin.AdminService.Leave:output_type -> tx.BroadcastResponse - 13, // 16: admin.AdminService.Remove:output_type -> tx.BroadcastResponse - 14, // 17: admin.AdminService.JoinStatus:output_type -> admin.JoinStatusResponse - 15, // 18: admin.AdminService.ListValidators:output_type -> admin.ListValidatorsResponse - 16, // 19: admin.AdminService.ListPendingJoins:output_type -> admin.ListJoinRequestsResponse - 10, // [10:20] is the sub-list for method output_type - 0, // [0:10] is the sub-list for method input_type + 10, // 10: admin.AdminService.GetConfig:input_type -> admin.GetConfigRequest + 11, // 11: admin.AdminService.Version:output_type -> admin.VersionResponse + 12, // 12: admin.AdminService.Status:output_type -> admin.StatusResponse + 13, // 13: admin.AdminService.Peers:output_type -> admin.PeersResponse + 14, // 14: admin.AdminService.Approve:output_type -> tx.BroadcastResponse + 14, // 15: admin.AdminService.Join:output_type -> tx.BroadcastResponse + 14, // 16: admin.AdminService.Leave:output_type -> tx.BroadcastResponse + 14, // 17: admin.AdminService.Remove:output_type -> tx.BroadcastResponse + 15, // 18: admin.AdminService.JoinStatus:output_type -> admin.JoinStatusResponse + 16, // 19: admin.AdminService.ListValidators:output_type -> admin.ListValidatorsResponse + 17, // 20: admin.AdminService.ListPendingJoins:output_type -> admin.ListJoinRequestsResponse + 18, // 21: admin.AdminService.GetConfig:output_type -> admin.GetConfigResponse + 11, // [11:22] is the sub-list for method output_type + 0, // [0:11] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name diff --git a/core/rpc/protobuf/admin/v0/service_grpc.pb.go b/core/rpc/protobuf/admin/v0/service_grpc.pb.go index 5a8212ea7..eb2dd8e4f 100644 --- a/core/rpc/protobuf/admin/v0/service_grpc.pb.go +++ b/core/rpc/protobuf/admin/v0/service_grpc.pb.go @@ -30,6 +30,7 @@ const ( AdminService_JoinStatus_FullMethodName = "/admin.AdminService/JoinStatus" AdminService_ListValidators_FullMethodName = "/admin.AdminService/ListValidators" AdminService_ListPendingJoins_FullMethodName = "/admin.AdminService/ListPendingJoins" + AdminService_GetConfig_FullMethodName = "/admin.AdminService/GetConfig" ) // AdminServiceClient is the client API for AdminService service. @@ -46,6 +47,7 @@ type AdminServiceClient interface { JoinStatus(ctx context.Context, in *JoinStatusRequest, opts ...grpc.CallOption) (*JoinStatusResponse, error) ListValidators(ctx context.Context, in *ListValidatorsRequest, opts ...grpc.CallOption) (*ListValidatorsResponse, error) ListPendingJoins(ctx context.Context, in *ListJoinRequestsRequest, opts ...grpc.CallOption) (*ListJoinRequestsResponse, error) + GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) } type adminServiceClient struct { @@ -146,6 +148,15 @@ func (c *adminServiceClient) ListPendingJoins(ctx context.Context, in *ListJoinR return out, nil } +func (c *adminServiceClient) GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) { + out := new(GetConfigResponse) + err := c.cc.Invoke(ctx, AdminService_GetConfig_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdminServiceServer is the server API for AdminService service. // All implementations must embed UnimplementedAdminServiceServer // for forward compatibility @@ -160,6 +171,7 @@ type AdminServiceServer interface { JoinStatus(context.Context, *JoinStatusRequest) (*JoinStatusResponse, error) ListValidators(context.Context, *ListValidatorsRequest) (*ListValidatorsResponse, error) ListPendingJoins(context.Context, *ListJoinRequestsRequest) (*ListJoinRequestsResponse, error) + GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) mustEmbedUnimplementedAdminServiceServer() } @@ -197,6 +209,9 @@ func (UnimplementedAdminServiceServer) ListValidators(context.Context, *ListVali func (UnimplementedAdminServiceServer) ListPendingJoins(context.Context, *ListJoinRequestsRequest) (*ListJoinRequestsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListPendingJoins not implemented") } +func (UnimplementedAdminServiceServer) GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetConfig not implemented") +} func (UnimplementedAdminServiceServer) mustEmbedUnimplementedAdminServiceServer() {} // UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service. @@ -390,6 +405,24 @@ func _AdminService_ListPendingJoins_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _AdminService_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).GetConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_GetConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).GetConfig(ctx, req.(*GetConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AdminService_ServiceDesc is the grpc.ServiceDesc for AdminService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -437,6 +470,10 @@ var AdminService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListPendingJoins", Handler: _AdminService_ListPendingJoins_Handler, }, + { + MethodName: "GetConfig", + Handler: _AdminService_GetConfig_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kwil/admin/v0/service.proto", diff --git a/core/rpc/protobuf/tx/v1/list.pb.go b/core/rpc/protobuf/tx/v1/list.pb.go index 37e30a94b..54f858fad 100644 --- a/core/rpc/protobuf/tx/v1/list.pb.go +++ b/core/rpc/protobuf/tx/v1/list.pb.go @@ -72,7 +72,7 @@ type ListDatabasesResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Databases []string `protobuf:"bytes,1,rep,name=databases,proto3" json:"databases,omitempty"` + Databases []*DatasetInfo `protobuf:"bytes,1,rep,name=databases,proto3" json:"databases,omitempty"` } func (x *ListDatabasesResponse) Reset() { @@ -107,13 +107,76 @@ func (*ListDatabasesResponse) Descriptor() ([]byte, []int) { return file_kwil_tx_v1_list_proto_rawDescGZIP(), []int{1} } -func (x *ListDatabasesResponse) GetDatabases() []string { +func (x *ListDatabasesResponse) GetDatabases() []*DatasetInfo { if x != nil { return x.Databases } return nil } +type DatasetInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Owner []byte `protobuf:"bytes,2,opt,name=owner,proto3" json:"owner,omitempty"` + Dbid string `protobuf:"bytes,3,opt,name=dbid,proto3" json:"dbid,omitempty"` +} + +func (x *DatasetInfo) Reset() { + *x = DatasetInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_kwil_tx_v1_list_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DatasetInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DatasetInfo) ProtoMessage() {} + +func (x *DatasetInfo) ProtoReflect() protoreflect.Message { + mi := &file_kwil_tx_v1_list_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DatasetInfo.ProtoReflect.Descriptor instead. +func (*DatasetInfo) Descriptor() ([]byte, []int) { + return file_kwil_tx_v1_list_proto_rawDescGZIP(), []int{2} +} + +func (x *DatasetInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DatasetInfo) GetOwner() []byte { + if x != nil { + return x.Owner + } + return nil +} + +func (x *DatasetInfo) GetDbid() string { + if x != nil { + return x.Dbid + } + return "" +} + var File_kwil_tx_v1_list_proto protoreflect.FileDescriptor var file_kwil_tx_v1_list_proto_rawDesc = []byte{ @@ -121,15 +184,21 @@ var file_kwil_tx_v1_list_proto_rawDesc = []byte{ 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x74, 0x78, 0x22, 0x2c, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x35, 0x0a, 0x15, 0x4c, 0x69, 0x73, + 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x46, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, - 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, - 0x77, 0x69, 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, - 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x78, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x73, + 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x73, 0x22, 0x4b, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x62, 0x69, 0x64, 0x42, 0x3a, + 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x77, 0x69, + 0x6c, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x6b, 0x77, 0x69, 0x6c, 0x2d, 0x64, 0x62, 0x2f, 0x63, 0x6f, + 0x72, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -144,17 +213,19 @@ func file_kwil_tx_v1_list_proto_rawDescGZIP() []byte { return file_kwil_tx_v1_list_proto_rawDescData } -var file_kwil_tx_v1_list_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_kwil_tx_v1_list_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_kwil_tx_v1_list_proto_goTypes = []interface{}{ (*ListDatabasesRequest)(nil), // 0: tx.ListDatabasesRequest (*ListDatabasesResponse)(nil), // 1: tx.ListDatabasesResponse + (*DatasetInfo)(nil), // 2: tx.DatasetInfo } var file_kwil_tx_v1_list_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 2, // 0: tx.ListDatabasesResponse.databases:type_name -> tx.DatasetInfo + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_kwil_tx_v1_list_proto_init() } @@ -187,6 +258,18 @@ func file_kwil_tx_v1_list_proto_init() { return nil } } + file_kwil_tx_v1_list_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DatasetInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -194,7 +277,7 @@ func file_kwil_tx_v1_list_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_kwil_tx_v1_list_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/core/types/types.go b/core/types/types.go index 145001b40..37374358e 100644 --- a/core/types/types.go +++ b/core/types/types.go @@ -58,3 +58,10 @@ type NodeInfo struct { func (v *Validator) String() string { return fmt.Sprintf("{pubkey = %x, power = %d}", v.PubKey, v.Power) } + +// DatasetInfo contains metadata about a dataset. +type DatasetInfo struct { + Name string `json:"name"` + Owner []byte `json:"owner"` + DBID string `json:"dbid"` +} diff --git a/internal/engine/execution/execution_test.go b/internal/engine/execution/execution_test.go index 4dd234e54..71dc06a95 100644 --- a/internal/engine/execution/execution_test.go +++ b/internal/engine/execution/execution_test.go @@ -177,7 +177,9 @@ func Test_Execution(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, len(datasets)) - require.Equal(t, testdata.TestSchema.Name, datasets[0]) + require.Equal(t, testdata.TestSchema.Name, datasets[0].Name) + require.Equal(t, testdata.TestSchema.Owner, datasets[0].Owner) + require.Equal(t, testdata.TestSchema.DBID(), datasets[0].DBID) }, }, } diff --git a/internal/engine/execution/global.go b/internal/engine/execution/global.go index 0f737bf5f..535fa8798 100644 --- a/internal/engine/execution/global.go +++ b/internal/engine/execution/global.go @@ -7,6 +7,7 @@ import ( "fmt" "sort" + coreTypes "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/internal/engine/types" sql "github.com/kwilteam/kwil-db/internal/sql" ) @@ -154,12 +155,30 @@ func (g *GlobalContext) Execute(ctx context.Context, options *types.ExecutionDat return execCtx.FinalResult, err } -// ListDatasets list datasets deployed by a specific caller -func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]string, error) { - var datasets []string - for _, dataset := range g.datasets { +// ListDatasets list datasets deployed by a specific caller. +// If caller is nil, it will list all datasets. +func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetInfo, error) { + datasets := make([]*coreTypes.DatasetInfo, 0, len(g.datasets)) + + if len(caller) == 0 { + for dbid, dataset := range g.datasets { + datasets = append(datasets, &coreTypes.DatasetInfo{ + Name: dataset.schema.Name, + Owner: dataset.schema.Owner, + DBID: dbid, + }) + } + + return datasets, nil + } + + for dbid, dataset := range g.datasets { if bytes.Equal(dataset.schema.Owner, caller) { - datasets = append(datasets, dataset.schema.Name) + datasets = append(datasets, &coreTypes.DatasetInfo{ + Name: dataset.schema.Name, + Owner: dataset.schema.Owner, + DBID: dbid, + }) } } diff --git a/internal/engine/integration/execution_test.go b/internal/engine/integration/execution_test.go index eca46eed6..443537e09 100644 --- a/internal/engine/integration/execution_test.go +++ b/internal/engine/integration/execution_test.go @@ -45,7 +45,7 @@ func Test_Engine(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, len(dbs)) - require.Equal(t, testdata.TestSchema.Name, dbs[0]) + require.Equal(t, testdata.TestSchema.Name, dbs[0].Name) regDbs, err := reg.List(ctx) require.NoError(t, err) diff --git a/internal/modules/datasets/interfaces.go b/internal/modules/datasets/interfaces.go index 5c69d7108..d6245b258 100644 --- a/internal/modules/datasets/interfaces.go +++ b/internal/modules/datasets/interfaces.go @@ -3,6 +3,7 @@ package datasets import ( "context" + coreTypes "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/internal/accounts" "github.com/kwilteam/kwil-db/internal/engine/types" "github.com/kwilteam/kwil-db/internal/sql" @@ -17,6 +18,6 @@ type Engine interface { DeleteDataset(ctx context.Context, dbid string, caller []byte) error Execute(ctx context.Context, data *types.ExecutionData) (*sql.ResultSet, error) GetSchema(ctx context.Context, dbid string) (*types.Schema, error) - ListDatasets(ctx context.Context, caller []byte) ([]string, error) + ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetInfo, error) Query(ctx context.Context, dbid string, query string) (*sql.ResultSet, error) } diff --git a/internal/modules/datasets/read.go b/internal/modules/datasets/read.go index 5cc8a88e8..3e5438140 100644 --- a/internal/modules/datasets/read.go +++ b/internal/modules/datasets/read.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + coreTypes "github.com/kwilteam/kwil-db/core/types" "github.com/kwilteam/kwil-db/core/types/transactions" engineTypes "github.com/kwilteam/kwil-db/internal/engine/types" "github.com/kwilteam/kwil-db/internal/ident" @@ -61,7 +62,7 @@ func (u *DatasetModule) GetSchema(ctx context.Context, dbid string) (*engineType } // ListOwnedDatabase returns a list of databases owned by a public key. -func (u *DatasetModule) ListOwnedDatabases(ctx context.Context, owner []byte) ([]string, error) { +func (u *DatasetModule) ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetInfo, error) { return u.engine.ListDatasets(ctx, owner) } diff --git a/internal/services/grpc/admin/v0/service.go b/internal/services/grpc/admin/v0/service.go index 33146722d..5a390b486 100644 --- a/internal/services/grpc/admin/v0/service.go +++ b/internal/services/grpc/admin/v0/service.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "math/big" + "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/core/crypto/auth" "github.com/kwilteam/kwil-db/core/log" admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" @@ -62,6 +63,8 @@ type Service struct { nodeApp NodeApplication validators ValidatorReader + cfg *config.KwildConfig + log log.Logger signer auth.Signer // signer is an ed25519 signer derived from the nodes private key. @@ -70,12 +73,13 @@ type Service struct { var _ admpb.AdminServiceServer = (*Service)(nil) // NewService constructs a new Service. -func NewService(blockchain BlockchainTransactor, node NodeApplication, validators ValidatorReader, signer auth.Signer, opts ...AdminSvcOpt) *Service { +func NewService(blockchain BlockchainTransactor, node NodeApplication, validators ValidatorReader, signer auth.Signer, cfg *config.KwildConfig, opts ...AdminSvcOpt) *Service { s := &Service{ blockchain: blockchain, nodeApp: node, validators: validators, signer: signer, + cfg: cfg, log: log.NewNoOp(), } @@ -326,3 +330,14 @@ func (s *Service) ListPendingJoins(ctx context.Context, req *admpb.ListJoinReque JoinRequests: pbJoins, }, nil } + +func (s *Service) GetConfig(ctx context.Context, req *admpb.GetConfigRequest) (*admpb.GetConfigResponse, error) { + bts, err := s.cfg.MarshalBinary() + if err != nil { + return nil, err + } + + return &admpb.GetConfigResponse{ + Config: bts, + }, nil +} diff --git a/internal/services/grpc/txsvc/v1/list.go b/internal/services/grpc/txsvc/v1/list.go index 56caedc64..46db44949 100644 --- a/internal/services/grpc/txsvc/v1/list.go +++ b/internal/services/grpc/txsvc/v1/list.go @@ -12,7 +12,16 @@ func (s *Service) ListDatabases(ctx context.Context, req *txpb.ListDatabasesRequ return nil, err } + pbDatasets := make([]*txpb.DatasetInfo, len(dbs)) + for i, db := range dbs { + pbDatasets[i] = &txpb.DatasetInfo{ + Dbid: db.DBID, + Name: db.Name, + Owner: db.Owner, + } + } + return &txpb.ListDatabasesResponse{ - Databases: dbs, + Databases: pbDatasets, }, nil } diff --git a/internal/services/grpc/txsvc/v1/service.go b/internal/services/grpc/txsvc/v1/service.go index 920645b28..c674668f1 100644 --- a/internal/services/grpc/txsvc/v1/service.go +++ b/internal/services/grpc/txsvc/v1/service.go @@ -7,7 +7,8 @@ import ( cmtCoreTypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/kwilteam/kwil-db/core/log" txpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/tx/v1" - types "github.com/kwilteam/kwil-db/core/types/admin" + coreTypes "github.com/kwilteam/kwil-db/core/types" + adminTypes "github.com/kwilteam/kwil-db/core/types/admin" "github.com/kwilteam/kwil-db/core/types/transactions" "github.com/kwilteam/kwil-db/internal/accounts" engineTypes "github.com/kwilteam/kwil-db/internal/engine/types" @@ -51,7 +52,7 @@ func NewService(engine EngineReader, accountStore AccountReader, vstore Validato type EngineReader interface { Call(ctx context.Context, dbid string, action string, args []any, msg *transactions.CallMessage) ([]map[string]any, error) GetSchema(ctx context.Context, dbid string) (*engineTypes.Schema, error) - ListOwnedDatabases(ctx context.Context, owner []byte) ([]string, error) + ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetInfo, error) PriceDeploy(ctx context.Context, schema *engineTypes.Schema) (price *big.Int, err error) PriceDrop(ctx context.Context, dbid string) (price *big.Int, err error) PriceExecute(ctx context.Context, dbid string, action string, args [][]any) (price *big.Int, err error) @@ -63,7 +64,7 @@ type AccountReader interface { } type BlockchainTransactor interface { - Status(ctx context.Context) (*types.Status, error) + Status(ctx context.Context) (*adminTypes.Status, error) BroadcastTx(ctx context.Context, tx []byte, sync uint8) (code uint32, txHash []byte, err error) TxQuery(ctx context.Context, hash []byte, prove bool) (*cmtCoreTypes.ResultTx, error) // TODO: don't use comet types here } diff --git a/internal/services/http/api/tx/v1.swagger.json b/internal/services/http/api/tx/v1.swagger.json index c0a684dd3..2f22332a6 100644 --- a/internal/services/http/api/tx/v1.swagger.json +++ b/internal/services/http/api/tx/v1.swagger.json @@ -552,6 +552,21 @@ } } }, + "txDatasetInfo": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "owner": { + "type": "string", + "format": "byte" + }, + "dbid": { + "type": "string" + } + } + }, "txEstimatePriceRequest": { "type": "object", "properties": { @@ -678,7 +693,8 @@ "databases": { "type": "array", "items": { - "type": "string" + "type": "object", + "$ref": "#/definitions/txDatasetInfo" } } } diff --git a/proto b/proto index c5a892f75..9a836553c 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit c5a892f75dbd8025a870019010006b6fa31a56a8 +Subproject commit 9a836553c13f1f176c3249849ed5bb489e446f7a diff --git a/test/acceptance/helper.go b/test/acceptance/helper.go index ad56efecd..5f7e3be6d 100644 --- a/test/acceptance/helper.go +++ b/test/acceptance/helper.go @@ -285,7 +285,7 @@ func (r *ActHelper) GetDriver(driveType string, user string) KwilAcceptanceDrive func (r *ActHelper) getHTTPClientDriver(signer auth.Signer) KwilAcceptanceDriver { logger := log.New(log.Config{Level: r.cfg.LogLevel}) - kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ + kwilClt, err := client.NewClient(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ Signer: signer, ChainID: TestChainID, Logger: logger, diff --git a/test/acceptance/kwild_test.go b/test/acceptance/kwild_test.go index 4a0b8add8..638f00fa9 100644 --- a/test/acceptance/kwild_test.go +++ b/test/acceptance/kwild_test.go @@ -3,8 +3,10 @@ package acceptance_test import ( "context" "flag" + "fmt" "strings" "testing" + "time" "github.com/kwilteam/kwil-db/test/acceptance" "github.com/kwilteam/kwil-db/test/specifications" @@ -46,11 +48,15 @@ func TestKwildAcceptance(t *testing.T) { // When user deployed database //specifications.DatabaseDeployInvalidSql1Specification(ctx, t, creatorDriver) + start := time.Now() specifications.DatabaseDeployInvalidExtensionSpecification(ctx, t, creatorDriver) + fmt.Println("DatabaseDeployInvalidExtensionSpecification took", time.Since(start)) specifications.DatabaseDeploySpecification(ctx, t, creatorDriver) + fmt.Println("DatabaseDeploySpecification took", time.Since(start)) //Then user should be able to execute database specifications.ExecuteOwnerActionSpecification(ctx, t, creatorDriver) + fmt.Println("ExecuteOwnerActionSpecification took", time.Since(start)) // TODO: This test doesn't looks good, the spec suppose to expect // only one parameter, the driver. @@ -59,20 +65,28 @@ func TestKwildAcceptance(t *testing.T) { dbid := creatorDriver.DBID(db.Name) visitorDriver := helper.GetDriver(driverType, "visitor") specifications.ExecuteOwnerActionFailSpecification(ctx, t, visitorDriver, dbid) + fmt.Println("ExecuteOwnerActionFailSpecification took", time.Since(start)) specifications.ExecuteDBInsertSpecification(ctx, t, creatorDriver) + fmt.Println("ExecuteDBInsertSpecification took", time.Since(start)) specifications.ExecuteCallSpecification(ctx, t, creatorDriver, visitorDriver) + fmt.Println("ExecuteCallSpecification took", time.Since(start)) specifications.ExecuteDBUpdateSpecification(ctx, t, creatorDriver) + fmt.Println("ExecuteDBUpdateSpecification took", time.Since(start)) specifications.ExecuteDBDeleteSpecification(ctx, t, creatorDriver) + fmt.Println("ExecuteDBDeleteSpecification took", time.Since(start)) // test that the loaded extensions works specifications.ExecuteExtensionSpecification(ctx, t, creatorDriver) + fmt.Println("ExecuteExtensionSpecification took", time.Since(start)) // and user should be able to drop database specifications.DatabaseDropSpecification(ctx, t, creatorDriver) + fmt.Println("DatabaseDropSpecification took", time.Since(start)) specifications.ExecuteChainInfoSpecification(ctx, t, creatorDriver, acceptance.TestChainID) + fmt.Println("ExecuteChainInfoSpecification took", time.Since(start)) // there's one node in the network and we're the validator // @brennan I am commenting this out temporarily, but it seems to be _mostly_ useless // all it does is check that the node is a validator, which is not really a useful test, @@ -83,4 +97,6 @@ func TestKwildAcceptance(t *testing.T) { // The other network/validator specs require multiple nodes in a network }) } + + t.FailNow() } diff --git a/test/driver/cli_driver.go b/test/driver/cli_driver.go index ac70d8195..1b7da9cda 100644 --- a/test/driver/cli_driver.go +++ b/test/driver/cli_driver.go @@ -10,7 +10,6 @@ import ( "os" "os/exec" "path" - "slices" "strings" "time" @@ -67,7 +66,7 @@ func (d *KwilCliDriver) DBID(name string) string { return utils.GenerateDBID(name, d.identity) } -func (d *KwilCliDriver) listDatabase() ([]string, error) { +func (d *KwilCliDriver) listDatabase() ([]*types.DatasetInfo, error) { cmd := d.newKwilCliCmd("database", "list", "--owner", hex.EncodeToString(d.identity)) out, err := mustRun(cmd, d.logger) if err != nil { @@ -96,7 +95,15 @@ func (d *KwilCliDriver) DatabaseExists(_ context.Context, dbid string) error { return err } - if !slices.Contains(dbs, dbid) { + found := false + for _, db := range dbs { + if db.DBID == dbid { + found = true + break + } + } + + if !found { return fmt.Errorf("ListDatabase: database not found: %s", dbid) } @@ -430,34 +437,17 @@ func parseRespQueryDb(data any) (*client.Records, error) { return client.NewRecordsFromMaps(resp), nil } -// respDBList represent databases belong to an owner in cli -// NOTE: this is **NOT** exactly the same as the one in cmd/kwil-cli/message.go -type respDBList struct { - Databases []dbInfo `json:"databases"` - Owner []byte `json:"owner"` -} - -type dbInfo struct { - Name string `json:"name"` - Id string `json:"id"` -} - -func parseRespListDatabases(data any) ([]string, error) { +func parseRespListDatabases(data any) ([]*types.DatasetInfo, error) { bts, err := json.Marshal(data) if err != nil { return nil, fmt.Errorf("failed to marshal list databases resp: %w", err) } - var resp respDBList + var resp []*types.DatasetInfo err = json.Unmarshal(bts, &resp) if err != nil { return nil, fmt.Errorf("failed to unmarshal list databases: %w", err) } - dbs := make([]string, len(resp.Databases)) - for i, db := range resp.Databases { - dbs[i] = db.Id - } - - return dbs, nil + return resp, nil } diff --git a/test/driver/client_driver.go b/test/driver/client_driver.go index 81be8224e..b9b68bfeb 100644 --- a/test/driver/client_driver.go +++ b/test/driver/client_driver.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "fmt" "os" - "slices" "github.com/kwilteam/kwil-db/core/client" "github.com/kwilteam/kwil-db/core/log" @@ -103,8 +102,16 @@ func (d *KwildClientDriver) DatabaseExists(ctx context.Context, dbid string) err return fmt.Errorf("failed to get database list: %w", err) } - if !slices.Contains(dbs, dbSchema.Name) { - return fmt.Errorf("database %s not found", dbid) + found := false + for _, db := range dbs { + if db.DBID == dbid { + found = true + break + } + } + + if !found { + return fmt.Errorf("ListDatabase: database not found: %s", dbid) } return nil diff --git a/test/integration/helper.go b/test/integration/helper.go index c92ddc75a..296489c6f 100644 --- a/test/integration/helper.go +++ b/test/integration/helper.go @@ -382,7 +382,7 @@ func (r *IntHelper) GetOperatorDriver(ctx context.Context, nodeName string, driv func (r *IntHelper) getHTTPClientDriver(signer auth.Signer, httpEndpoint string) KwilIntDriver { logger := log.New(log.Config{Level: r.cfg.LogLevel}) - kwilClt, err := client.Dial(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ + kwilClt, err := client.NewClient(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ Signer: signer, ChainID: testChainID, Logger: logger, diff --git a/test/stress/transport.go b/test/stress/transport.go index 1a39fa509..0659b00a6 100644 --- a/test/stress/transport.go +++ b/test/stress/transport.go @@ -51,7 +51,7 @@ func (tc *timedClient) Query(ctx context.Context, dbid string, query string) ([] return tc.cl.Query(ctx, dbid, query) } -func (tc *timedClient) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]string, error) { +func (tc *timedClient) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetInfo, error) { if tc.showReqDur { defer tc.printDur(time.Now(), "ListDatabases") } From 2c0a8cdc25765fec415a5993f9f8cb0c586aed32 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 01:51:41 -0600 Subject: [PATCH 07/13] addressed jon and gavins feedback. Still have the integration test block mining error --- build/package/docker/kwild.debug.dockerfile | 2 + build/package/docker/kwild.dockerfile | 2 + cmd/kwil-cli/cmds/common/flags.go | 2 +- test/acceptance/kwild_test.go | 16 ------ test/driver/operator/client_driver.go | 59 +++++++++++++++++++++ test/integration/helper.go | 23 ++++++-- test/integration/kwild_test.go | 11 +++- 7 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 test/driver/operator/client_driver.go diff --git a/build/package/docker/kwild.debug.dockerfile b/build/package/docker/kwild.debug.dockerfile index 7738b3507..9bf29c5eb 100644 --- a/build/package/docker/kwild.debug.dockerfile +++ b/build/package/docker/kwild.debug.dockerfile @@ -9,6 +9,8 @@ ARG git_commit ARG go_build_tags WORKDIR /app +RUN mkdir -p /var/run/kwil +RUN chmod 777 /var/run/kwil RUN apk update && apk add git ca-certificates-bundle COPY . . diff --git a/build/package/docker/kwild.dockerfile b/build/package/docker/kwild.dockerfile index 88a9172c2..2334fac84 100644 --- a/build/package/docker/kwild.dockerfile +++ b/build/package/docker/kwild.dockerfile @@ -6,6 +6,8 @@ ARG git_commit ARG go_build_tags WORKDIR /app +RUN mkdir -p /var/run/kwil +RUN chmod 777 /var/run/kwil RUN apk update && apk add git ca-certificates-bundle COPY . . diff --git a/cmd/kwil-cli/cmds/common/flags.go b/cmd/kwil-cli/cmds/common/flags.go index bcd296945..5446f71de 100644 --- a/cmd/kwil-cli/cmds/common/flags.go +++ b/cmd/kwil-cli/cmds/common/flags.go @@ -7,7 +7,7 @@ import "github.com/spf13/cobra" // BindAssumeYesFlag binds the assume yes flag to the passed command // If bound, the command will assume yes for all prompts func BindAssumeYesFlag(cmd *cobra.Command) { - cmd.Flags().BoolP("assume-yes", "Y", false, "Assume yes for all prompts") + cmd.PersistentFlags().BoolP("assume-yes", "Y", false, "Assume yes for all prompts") } // GetAssumeYesFlag returns the value of the assume yes flag diff --git a/test/acceptance/kwild_test.go b/test/acceptance/kwild_test.go index 638f00fa9..4a0b8add8 100644 --- a/test/acceptance/kwild_test.go +++ b/test/acceptance/kwild_test.go @@ -3,10 +3,8 @@ package acceptance_test import ( "context" "flag" - "fmt" "strings" "testing" - "time" "github.com/kwilteam/kwil-db/test/acceptance" "github.com/kwilteam/kwil-db/test/specifications" @@ -48,15 +46,11 @@ func TestKwildAcceptance(t *testing.T) { // When user deployed database //specifications.DatabaseDeployInvalidSql1Specification(ctx, t, creatorDriver) - start := time.Now() specifications.DatabaseDeployInvalidExtensionSpecification(ctx, t, creatorDriver) - fmt.Println("DatabaseDeployInvalidExtensionSpecification took", time.Since(start)) specifications.DatabaseDeploySpecification(ctx, t, creatorDriver) - fmt.Println("DatabaseDeploySpecification took", time.Since(start)) //Then user should be able to execute database specifications.ExecuteOwnerActionSpecification(ctx, t, creatorDriver) - fmt.Println("ExecuteOwnerActionSpecification took", time.Since(start)) // TODO: This test doesn't looks good, the spec suppose to expect // only one parameter, the driver. @@ -65,28 +59,20 @@ func TestKwildAcceptance(t *testing.T) { dbid := creatorDriver.DBID(db.Name) visitorDriver := helper.GetDriver(driverType, "visitor") specifications.ExecuteOwnerActionFailSpecification(ctx, t, visitorDriver, dbid) - fmt.Println("ExecuteOwnerActionFailSpecification took", time.Since(start)) specifications.ExecuteDBInsertSpecification(ctx, t, creatorDriver) - fmt.Println("ExecuteDBInsertSpecification took", time.Since(start)) specifications.ExecuteCallSpecification(ctx, t, creatorDriver, visitorDriver) - fmt.Println("ExecuteCallSpecification took", time.Since(start)) specifications.ExecuteDBUpdateSpecification(ctx, t, creatorDriver) - fmt.Println("ExecuteDBUpdateSpecification took", time.Since(start)) specifications.ExecuteDBDeleteSpecification(ctx, t, creatorDriver) - fmt.Println("ExecuteDBDeleteSpecification took", time.Since(start)) // test that the loaded extensions works specifications.ExecuteExtensionSpecification(ctx, t, creatorDriver) - fmt.Println("ExecuteExtensionSpecification took", time.Since(start)) // and user should be able to drop database specifications.DatabaseDropSpecification(ctx, t, creatorDriver) - fmt.Println("DatabaseDropSpecification took", time.Since(start)) specifications.ExecuteChainInfoSpecification(ctx, t, creatorDriver, acceptance.TestChainID) - fmt.Println("ExecuteChainInfoSpecification took", time.Since(start)) // there's one node in the network and we're the validator // @brennan I am commenting this out temporarily, but it seems to be _mostly_ useless // all it does is check that the node is a validator, which is not really a useful test, @@ -97,6 +83,4 @@ func TestKwildAcceptance(t *testing.T) { // The other network/validator specs require multiple nodes in a network }) } - - t.FailNow() } diff --git a/test/driver/operator/client_driver.go b/test/driver/operator/client_driver.go new file mode 100644 index 000000000..49ce34caf --- /dev/null +++ b/test/driver/operator/client_driver.go @@ -0,0 +1,59 @@ +package operator + +import ( + "context" + "fmt" + + "github.com/kwilteam/kwil-db/core/adminclient" + "github.com/kwilteam/kwil-db/core/types" + "github.com/kwilteam/kwil-db/core/types/transactions" + "github.com/kwilteam/kwil-db/test/driver" +) + +type AdminClientDriver struct { + Client *adminclient.AdminClient +} + +var _ KwilOperatorDriver = (*AdminClientDriver)(nil) + +func (a *AdminClientDriver) TxSuccess(ctx context.Context, txHash []byte) error { + resp, err := a.Client.TxQuery(ctx, txHash) + if err != nil { + return fmt.Errorf("failed to query: %w", err) + } + + if resp.TxResult.Code != transactions.CodeOk.Uint32() { + return fmt.Errorf("transaction not ok, %s", resp.TxResult.Log) + } + + // NOTE: THIS should not be considered a failure, should retry + if resp.Height < 0 { + return driver.ErrTxNotConfirmed + } + + return nil +} + +func (a *AdminClientDriver) ValidatorJoinStatus(ctx context.Context, pubKey []byte) (*types.JoinRequest, error) { + return a.Client.JoinStatus(ctx, pubKey) +} + +func (a *AdminClientDriver) ValidatorNodeApprove(ctx context.Context, joinerPubKey []byte) ([]byte, error) { + return a.Client.Approve(ctx, joinerPubKey) +} + +func (a *AdminClientDriver) ValidatorNodeJoin(ctx context.Context) ([]byte, error) { + return a.Client.Join(ctx) +} + +func (a *AdminClientDriver) ValidatorNodeLeave(ctx context.Context) ([]byte, error) { + return a.Client.Leave(ctx) +} + +func (a *AdminClientDriver) ValidatorNodeRemove(ctx context.Context, target []byte) ([]byte, error) { + return a.Client.Remove(ctx, target) +} + +func (a *AdminClientDriver) ValidatorsList(ctx context.Context) ([]*types.Validator, error) { + return a.Client.ListValidators(ctx) +} diff --git a/test/integration/helper.go b/test/integration/helper.go index 296489c6f..6abb04876 100644 --- a/test/integration/helper.go +++ b/test/integration/helper.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "github.com/kwilteam/kwil-db/core/adminclient" gRPC "github.com/kwilteam/kwil-db/core/rpc/client/user/grpc" "github.com/cometbft/cometbft/crypto/ed25519" @@ -346,7 +347,7 @@ func (r *IntHelper) GetUserDriver(ctx context.Context, name string, driverType s pk := r.cfg.CreatorRawPk switch driverType { case "http": - return r.getHTTPClientDriver(signer, r.cfg.HTTPEndpoint) + return r.getHTTPClientDriver(signer) case "grpc": return r.getGRPCClientDriver(signer) case "cli": @@ -365,8 +366,22 @@ func (r *IntHelper) GetOperatorDriver(ctx context.Context, nodeName string, driv r.t.Fatalf("http driver not supported for node operator") return nil case "grpc": - r.t.Fatal("grpc driver not supported for node operator") // we can do this, but it is lower priority - return nil + c, ok := r.containers[nodeName] + if !ok { + r.t.Fatalf("container %s not found", nodeName) + } + + adminGrpcUrl, err := c.PortEndpoint(ctx, "50151", "tcp") + require.NoError(r.t, err, "failed to get admin grpc url") + + clt, err := adminclient.NewClient(ctx, adminGrpcUrl) + if err != nil { + r.t.Fatalf("failed to create admin client: %v", err) + } + + return &operator.AdminClientDriver{ + Client: clt, + } case "cli": c, ok := r.containers[nodeName] if !ok { @@ -379,7 +394,7 @@ func (r *IntHelper) GetOperatorDriver(ctx context.Context, nodeName string, driv } } -func (r *IntHelper) getHTTPClientDriver(signer auth.Signer, httpEndpoint string) KwilIntDriver { +func (r *IntHelper) getHTTPClientDriver(signer auth.Signer) KwilIntDriver { logger := log.New(log.Config{Level: r.cfg.LogLevel}) kwilClt, err := client.NewClient(context.TODO(), r.cfg.HTTPEndpoint, &client.ClientOptions{ diff --git a/test/integration/kwild_test.go b/test/integration/kwild_test.go index e65742dad..8a2fb90ac 100644 --- a/test/integration/kwild_test.go +++ b/test/integration/kwild_test.go @@ -71,8 +71,11 @@ func TestKwildValidatorRemoval(t *testing.T) { integration.WithNonValidators(numNonVals), } - testDrivers := []string{"cli"} // strings.Split(*drivers, ",") + testDrivers := strings.Split(*drivers, ",") for _, driverType := range testDrivers { + if driverType == "http" { + continue // admin service cannot use http + } t.Run(driverType+"_driver", func(t *testing.T) { helper := integration.NewIntHelper(t, opts...) @@ -118,8 +121,12 @@ func TestKwildValidatorUpdatesIntegration(t *testing.T) { expiryWait := 2 * expiryBlocks * blockInterval - testDrivers := []string{"cli"} // strings.Split(*drivers, ",") + testDrivers := strings.Split(*drivers, ",") for _, driverType := range testDrivers { + if driverType == "http" { + continue // admin service cannot use http + } + t.Run(driverType+"_driver", func(t *testing.T) { helper := integration.NewIntHelper(t, opts...) helper.Setup(ctx, allServices) From 13c259dd260bebfc0f0989d83266e111f5abc606 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 02:53:02 -0600 Subject: [PATCH 08/13] fixed invalid imports, and failing integration tests --- Taskfile-pb.yml | 2 + cmd/kwil-admin/cmds/node/dump-cfg.go | 8 +- cmd/kwil-admin/cmds/setup/peer.go | 2 +- cmd/kwil-admin/nodecfg/generate.go | 6 +- cmd/kwild/server/build.go | 1 + core/rpc/client/admin/admin.go | 4 +- core/rpc/client/admin/grpc/client.go | 11 +- .../rpc/protobuf/function/v0/service.pb.gw.go | 171 ++++++++++++++++++ test/driver/operator/cli_driver.go | 2 +- test/integration/docker-compose.yml | 9 +- 10 files changed, 194 insertions(+), 22 deletions(-) create mode 100644 core/rpc/protobuf/function/v0/service.pb.gw.go diff --git a/Taskfile-pb.yml b/Taskfile-pb.yml index 7a37dd731..ac9c3008b 100644 --- a/Taskfile-pb.yml +++ b/Taskfile-pb.yml @@ -67,6 +67,8 @@ tasks: protoc -I ./proto \ --go_out=. --go_opt module=github.com/kwilteam/kwil-db \ --go-grpc_out=. --go-grpc_opt module=github.com/kwilteam/kwil-db \ + --grpc-gateway_out=. --grpc-gateway_opt module=github.com/kwilteam/kwil-db \ + --grpc-gateway_opt generate_unbound_methods=true \ --openapiv2_out=internal/services/http/api/function \ --openapiv2_opt allow_merge=true --openapiv2_opt merge_file_name=v0 \ proto/kwil/function/v0/*.proto diff --git a/cmd/kwil-admin/cmds/node/dump-cfg.go b/cmd/kwil-admin/cmds/node/dump-cfg.go index cc2ba582c..668bc9298 100644 --- a/cmd/kwil-admin/cmds/node/dump-cfg.go +++ b/cmd/kwil-admin/cmds/node/dump-cfg.go @@ -30,7 +30,13 @@ func dumpCfgCmd() *cobra.Command { return display.PrintErr(cmd, err) } - cfg, err := client.GetConfig(ctx) + bts, err := client.GetConfig(ctx) + if err != nil { + return display.PrintErr(cmd, err) + } + + cfg := &config.KwildConfig{} + err = json.Unmarshal(bts, cfg) if err != nil { return display.PrintErr(cmd, err) } diff --git a/cmd/kwil-admin/cmds/setup/peer.go b/cmd/kwil-admin/cmds/setup/peer.go index 84d5ee136..ad267da61 100644 --- a/cmd/kwil-admin/cmds/setup/peer.go +++ b/cmd/kwil-admin/cmds/setup/peer.go @@ -58,7 +58,7 @@ func peerCmd() *cobra.Command { } } - _, err = nodecfg.GenerateNodeFiles(expandedDir, cfg) + _, err = nodecfg.GenerateNodeFiles(expandedDir, cfg, true) if err != nil { return display.PrintErr(cmd, err) } diff --git a/cmd/kwil-admin/nodecfg/generate.go b/cmd/kwil-admin/nodecfg/generate.go index 6fc1a4b51..4ede91851 100644 --- a/cmd/kwil-admin/nodecfg/generate.go +++ b/cmd/kwil-admin/nodecfg/generate.go @@ -94,7 +94,7 @@ func GenerateNodeConfig(genCfg *NodeGenerateConfig) error { cfg.ChainCfg.Consensus.TimeoutCommit = config.Duration(genCfg.BlockInterval) } - pub, err := GenerateNodeFiles(rootDir, cfg) + pub, err := GenerateNodeFiles(rootDir, cfg, false) if err != nil { return err } @@ -116,7 +116,7 @@ func GenerateNodeConfig(genCfg *NodeGenerateConfig) error { // GenerateNodeFiles will generate all generic node files that are not // dependent on the network configuration (e.g. genesis.json). // It can optionally be given a config file to merge with the default config. -func GenerateNodeFiles(outputDir string, originalCfg *config.KwildConfig) (publicKey []byte, err error) { +func GenerateNodeFiles(outputDir string, originalCfg *config.KwildConfig, silence bool) (publicKey []byte, err error) { cfg := config.DefaultConfig() if originalCfg != nil { err := cfg.Merge(originalCfg) @@ -155,7 +155,7 @@ func GenerateNodeFiles(outputDir string, originalCfg *config.KwildConfig) (publi if err != nil { return nil, fmt.Errorf("cannot read or create private key: %w", err) } - if newKey { + if newKey && !silence { fmt.Printf("Generated new private key: %v\n", fullKeyPath) } diff --git a/cmd/kwild/server/build.go b/cmd/kwild/server/build.go index 2e87b8592..65c927477 100644 --- a/cmd/kwild/server/build.go +++ b/cmd/kwild/server/build.go @@ -528,6 +528,7 @@ func buildGatewayServer(d *coreDependencies) *gateway.GatewayServer { gateway.WithLogger(*d.log.Named("gateway")), gateway.WithMiddleware(cors.MCors([]string{})), gateway.WithGrpcService(d.cfg.AppCfg.GrpcListenAddress, txpb.RegisterTxServiceHandlerFromEndpoint), + gateway.WithGrpcService(d.cfg.AppCfg.GrpcListenAddress, functionpb.RegisterFunctionServiceHandlerFromEndpoint), ) if err != nil { failBuild(err, "failed to build gateway server") diff --git a/core/rpc/client/admin/admin.go b/core/rpc/client/admin/admin.go index ae9d199a9..40d93f608 100644 --- a/core/rpc/client/admin/admin.go +++ b/core/rpc/client/admin/admin.go @@ -4,7 +4,6 @@ package admin import ( "context" - "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/core/types" adminTypes "github.com/kwilteam/kwil-db/core/types/admin" ) @@ -21,5 +20,6 @@ type AdminClient interface { Version(ctx context.Context) (string, error) ListPendingJoins(ctx context.Context) ([]*types.JoinRequest, error) // GetConfig gets the current config from the node. - GetConfig(ctx context.Context) (*config.KwildConfig, error) + // It returns the config serialized as JSON. + GetConfig(ctx context.Context) ([]byte, error) } diff --git a/core/rpc/client/admin/grpc/client.go b/core/rpc/client/admin/grpc/client.go index 17fd8752e..d5a3ccba6 100644 --- a/core/rpc/client/admin/grpc/client.go +++ b/core/rpc/client/admin/grpc/client.go @@ -5,7 +5,6 @@ import ( "context" "time" - "github.com/kwilteam/kwil-db/cmd/kwild/config" "github.com/kwilteam/kwil-db/core/rpc/client" adminRPC "github.com/kwilteam/kwil-db/core/rpc/client/admin" admpb "github.com/kwilteam/kwil-db/core/rpc/protobuf/admin/v0" @@ -163,19 +162,13 @@ func (c *GrpcAdminClient) ListPendingJoins(ctx context.Context) ([]*types.JoinRe return joins, nil } -func (c *GrpcAdminClient) GetConfig(ctx context.Context) (*config.KwildConfig, error) { +func (c *GrpcAdminClient) GetConfig(ctx context.Context) ([]byte, error) { resp, err := c.client.GetConfig(ctx, &admpb.GetConfigRequest{}) if err != nil { return nil, client.ConvertGRPCErr(err) } - cfg := &config.KwildConfig{} - err = cfg.UnmarshalBinary(resp.Config) - if err != nil { - return nil, err - } - - return cfg, nil + return resp.Config, nil } func convertPendingJoin(join *admpb.PendingJoin) *types.JoinRequest { diff --git a/core/rpc/protobuf/function/v0/service.pb.gw.go b/core/rpc/protobuf/function/v0/service.pb.gw.go new file mode 100644 index 000000000..e88efb9fd --- /dev/null +++ b/core/rpc/protobuf/function/v0/service.pb.gw.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: kwil/function/v0/service.proto + +/* +Package functionpb is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package functionpb + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_FunctionService_VerifySignature_0(ctx context.Context, marshaler runtime.Marshaler, client FunctionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq VerifySignatureRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.VerifySignature(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_FunctionService_VerifySignature_0(ctx context.Context, marshaler runtime.Marshaler, server FunctionServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq VerifySignatureRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.VerifySignature(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterFunctionServiceHandlerServer registers the http handlers for service FunctionService to "mux". +// UnaryRPC :call FunctionServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterFunctionServiceHandlerFromEndpoint instead. +func RegisterFunctionServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server FunctionServiceServer) error { + + mux.Handle("POST", pattern_FunctionService_VerifySignature_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/function.FunctionService/VerifySignature", runtime.WithHTTPPathPattern("/api/v1/verify_signature")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_FunctionService_VerifySignature_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_FunctionService_VerifySignature_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterFunctionServiceHandlerFromEndpoint is same as RegisterFunctionServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterFunctionServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.DialContext(ctx, endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterFunctionServiceHandler(ctx, mux, conn) +} + +// RegisterFunctionServiceHandler registers the http handlers for service FunctionService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterFunctionServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterFunctionServiceHandlerClient(ctx, mux, NewFunctionServiceClient(conn)) +} + +// RegisterFunctionServiceHandlerClient registers the http handlers for service FunctionService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "FunctionServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "FunctionServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "FunctionServiceClient" to call the correct interceptors. +func RegisterFunctionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client FunctionServiceClient) error { + + mux.Handle("POST", pattern_FunctionService_VerifySignature_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/function.FunctionService/VerifySignature", runtime.WithHTTPPathPattern("/api/v1/verify_signature")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_FunctionService_VerifySignature_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_FunctionService_VerifySignature_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_FunctionService_VerifySignature_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "verify_signature"}, "")) +) + +var ( + forward_FunctionService_VerifySignature_0 = runtime.ForwardResponseMessage +) diff --git a/test/driver/operator/cli_driver.go b/test/driver/operator/cli_driver.go index 1f2a29be5..6bce25fe2 100644 --- a/test/driver/operator/cli_driver.go +++ b/test/driver/operator/cli_driver.go @@ -126,7 +126,7 @@ func (o *OperatorCLIDriver) ValidatorNodeRemove(ctx context.Context, target []by func (o *OperatorCLIDriver) ValidatorsList(ctx context.Context) ([]*types.Validator, error) { var res []*types.Validator - err := o.runCommand(ctx, &res, "validators", "list") + err := o.runCommand(ctx, &res, "validators", "list-validators") if err != nil { return nil, err } diff --git a/test/integration/docker-compose.yml b/test/integration/docker-compose.yml index f9174d268..f6cd99758 100644 --- a/test/integration/docker-compose.yml +++ b/test/integration/docker-compose.yml @@ -21,7 +21,6 @@ services: ipv4_address: 172.10.100.2 depends_on: - ext1 - # the admin_listen_addr socket HAS to have the same number as the node name (node0 -> admin0.sock) command: | --root-dir=/app/kwil --log.level=${LOG_LEVEL:-debug} @@ -29,7 +28,7 @@ services: --app.grpc-listen-addr=:50051 --app.http-listen-addr=:8080 --app.admin-listen-addr=unix:///var/run/kwil/admin.sock - --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.p2p.listen-addr=tcp://0.0.0.0:26656 --chain.rpc.listen-addr=tcp://0.0.0.0:26657 node1: @@ -58,7 +57,7 @@ services: --app.grpc-listen-addr=:50051 --app.http-listen-addr=:8080 --app.admin-listen-addr=unix:///var/run/kwil/admin.sock - --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.p2p.listen-addr=tcp://0.0.0.0:26656 --chain.rpc.listen-addr=tcp://0.0.0.0:26657 node2: @@ -87,7 +86,7 @@ services: --app.grpc-listen-addr=:50051 --app.http-listen-addr=:8080 --app.admin-listen-addr=unix:///var/run/kwil/admin.sock - --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.p2p.listen-addr=tcp://0.0.0.0:26656 --chain.rpc.listen-addr=tcp://0.0.0.0:26657 # This node is used to test the scenario where new node join the network & sync the blocks @@ -118,7 +117,7 @@ services: --app.extension-endpoints=ext3:50051 --app.grpc-listen-addr=:50051 --app.http-listen-addr=:8080 - --chain.p2p.external-address=tcp://0.0.0.0:26656 + --chain.p2p.listen-addr=tcp://0.0.0.0:26656 --app.admin-listen-addr=unix:///var/run/kwil/admin.sock --chain.rpc.listen-addr=tcp://0.0.0.0:26657 From 6f4742c3cdb71bf25d79b071c0eaa18d76cafab8 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 02:55:54 -0600 Subject: [PATCH 09/13] changed DatasetInfo to DatasetIdentifier to be better descriptive, and avoid confusion with metadata --- cmd/kwil-cli/cmds/common/roundtripper.go | 2 +- cmd/kwil-cli/cmds/database/message.go | 2 +- cmd/kwil-cli/cmds/database/message_test.go | 6 +++--- core/client/client.go | 2 +- core/rpc/client/user/grpc/rpc.go | 6 +++--- core/rpc/client/user/http/client.go | 6 +++--- core/rpc/client/user/txsvc.go | 2 +- core/types/types.go | 4 ++-- internal/engine/execution/global.go | 8 ++++---- internal/modules/datasets/interfaces.go | 2 +- internal/modules/datasets/read.go | 2 +- internal/services/grpc/txsvc/v1/service.go | 2 +- test/driver/cli_driver.go | 6 +++--- test/stress/transport.go | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cmd/kwil-cli/cmds/common/roundtripper.go b/cmd/kwil-cli/cmds/common/roundtripper.go index 1d2beeb41..359875bed 100644 --- a/cmd/kwil-cli/cmds/common/roundtripper.go +++ b/cmd/kwil-cli/cmds/common/roundtripper.go @@ -122,7 +122,7 @@ type Client interface { ExecuteAction(ctx context.Context, dbid string, action string, tuples [][]any, opts ...client.TxOpt) (transactions.TxHash, error) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) - ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetInfo, error) + ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetIdentifier, error) Ping(ctx context.Context) (string, error) Query(ctx context.Context, dbid string, query string) (*client.Records, error) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) diff --git a/cmd/kwil-cli/cmds/database/message.go b/cmd/kwil-cli/cmds/database/message.go index 023bcd2f8..129456db7 100644 --- a/cmd/kwil-cli/cmds/database/message.go +++ b/cmd/kwil-cli/cmds/database/message.go @@ -21,7 +21,7 @@ import ( // respDBList represent databases belong to an owner in cli type respDBList struct { - Info []*types.DatasetInfo + Info []*types.DatasetIdentifier // owner is the owner configured in cli owner []byte } diff --git a/cmd/kwil-cli/cmds/database/message_test.go b/cmd/kwil-cli/cmds/database/message_test.go index 68ae46728..f48ffdcdf 100644 --- a/cmd/kwil-cli/cmds/database/message_test.go +++ b/cmd/kwil-cli/cmds/database/message_test.go @@ -12,7 +12,7 @@ import ( func Example_respDBlist_text_0() { display.Print( - &respDBList{Info: []*types.DatasetInfo{}, owner: mustDecodeHex("6f776e6572")}, + &respDBList{Info: []*types.DatasetIdentifier{}, owner: mustDecodeHex("6f776e6572")}, nil, "text") // Output: // No databases found for '6f776e6572'. @@ -20,7 +20,7 @@ func Example_respDBlist_text_0() { func Example_respDBlist_text() { display.Print( - &respDBList{Info: []*types.DatasetInfo{ + &respDBList{Info: []*types.DatasetIdentifier{ { Name: "db_a", Owner: mustDecodeHex("6f776e6572"), @@ -63,7 +63,7 @@ func mustDecodeBase64(s string) []byte { func Example_respDBlist_json() { display.Print( - &respDBList{Info: []*types.DatasetInfo{ + &respDBList{Info: []*types.DatasetIdentifier{ { Name: "db_a", Owner: mustDecodeBase64("b3duZXI="), diff --git a/core/client/client.go b/core/client/client.go index 55bf6f450..d72f83701 100644 --- a/core/client/client.go +++ b/core/client/client.go @@ -228,7 +228,7 @@ func (c *Client) Query(ctx context.Context, dbid string, query string) (*Records return NewRecordsFromMaps(res), nil } -func (c *Client) ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetInfo, error) { +func (c *Client) ListDatabases(ctx context.Context, owner []byte) ([]*types.DatasetIdentifier, error) { return c.txClient.ListDatabases(ctx, owner) } diff --git a/core/rpc/client/user/grpc/rpc.go b/core/rpc/client/user/grpc/rpc.go index 43937c586..55629f79c 100644 --- a/core/rpc/client/user/grpc/rpc.go +++ b/core/rpc/client/user/grpc/rpc.go @@ -172,7 +172,7 @@ type SvcConfig struct { ProviderAddress string } -func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetInfo, error) { +func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetIdentifier, error) { res, err := c.TxClient.ListDatabases(ctx, &txpb.ListDatabasesRequest{ Owner: ownerIdentifier, }) @@ -181,9 +181,9 @@ func (c *Client) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]* return nil, fmt.Errorf("failed to list databases: %w", err) } - datasets := make([]*types.DatasetInfo, len(res.Databases)) + datasets := make([]*types.DatasetIdentifier, len(res.Databases)) for i, db := range res.Databases { - datasets[i] = &types.DatasetInfo{ + datasets[i] = &types.DatasetIdentifier{ Name: db.Name, Owner: db.Owner, DBID: db.Dbid, diff --git a/core/rpc/client/user/http/client.go b/core/rpc/client/user/http/client.go index ece167f6c..7ecf90454 100644 --- a/core/rpc/client/user/http/client.go +++ b/core/rpc/client/user/http/client.go @@ -187,7 +187,7 @@ func (c *Client) GetSchema(ctx context.Context, dbid string) (*transactions.Sche return convertedSchema, nil } -func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetInfo, error) { +func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetIdentifier, error) { // we need to use b64url since this method uses a query string result, res, err := c.conn.TxServiceApi.TxServiceListDatabases(ctx, base64.URLEncoding.EncodeToString(ownerPubKey)) if err != nil { @@ -195,14 +195,14 @@ func (c *Client) ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*type } defer res.Body.Close() - datasets := make([]*types.DatasetInfo, 0, len(result.Databases)) + datasets := make([]*types.DatasetIdentifier, 0, len(result.Databases)) for _, db := range result.Databases { decodedOwner, err := base64.StdEncoding.DecodeString(db.Owner) if err != nil { return nil, err } - datasets = append(datasets, &types.DatasetInfo{ + datasets = append(datasets, &types.DatasetIdentifier{ Name: db.Name, Owner: decodedOwner, DBID: db.Dbid, diff --git a/core/rpc/client/user/txsvc.go b/core/rpc/client/user/txsvc.go index 9e1047ff9..34925339a 100644 --- a/core/rpc/client/user/txsvc.go +++ b/core/rpc/client/user/txsvc.go @@ -20,7 +20,7 @@ type TxSvcClient interface { EstimateCost(ctx context.Context, tx *transactions.Transaction) (*big.Int, error) GetAccount(ctx context.Context, pubKey []byte, status types.AccountStatus) (*types.Account, error) GetSchema(ctx context.Context, dbid string) (*transactions.Schema, error) - ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetInfo, error) + ListDatabases(ctx context.Context, ownerPubKey []byte) ([]*types.DatasetIdentifier, error) Ping(ctx context.Context) (string, error) Query(ctx context.Context, dbid string, query string) ([]map[string]any, error) TxQuery(ctx context.Context, txHash []byte) (*transactions.TcTxQueryResponse, error) diff --git a/core/types/types.go b/core/types/types.go index 37374358e..41353c96a 100644 --- a/core/types/types.go +++ b/core/types/types.go @@ -59,8 +59,8 @@ func (v *Validator) String() string { return fmt.Sprintf("{pubkey = %x, power = %d}", v.PubKey, v.Power) } -// DatasetInfo contains metadata about a dataset. -type DatasetInfo struct { +// DatasetIdentifier contains the information required to identify a dataset. +type DatasetIdentifier struct { Name string `json:"name"` Owner []byte `json:"owner"` DBID string `json:"dbid"` diff --git a/internal/engine/execution/global.go b/internal/engine/execution/global.go index 535fa8798..769c9cfe7 100644 --- a/internal/engine/execution/global.go +++ b/internal/engine/execution/global.go @@ -157,12 +157,12 @@ func (g *GlobalContext) Execute(ctx context.Context, options *types.ExecutionDat // ListDatasets list datasets deployed by a specific caller. // If caller is nil, it will list all datasets. -func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetInfo, error) { - datasets := make([]*coreTypes.DatasetInfo, 0, len(g.datasets)) +func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetIdentifier, error) { + datasets := make([]*coreTypes.DatasetIdentifier, 0, len(g.datasets)) if len(caller) == 0 { for dbid, dataset := range g.datasets { - datasets = append(datasets, &coreTypes.DatasetInfo{ + datasets = append(datasets, &coreTypes.DatasetIdentifier{ Name: dataset.schema.Name, Owner: dataset.schema.Owner, DBID: dbid, @@ -174,7 +174,7 @@ func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]*cor for dbid, dataset := range g.datasets { if bytes.Equal(dataset.schema.Owner, caller) { - datasets = append(datasets, &coreTypes.DatasetInfo{ + datasets = append(datasets, &coreTypes.DatasetIdentifier{ Name: dataset.schema.Name, Owner: dataset.schema.Owner, DBID: dbid, diff --git a/internal/modules/datasets/interfaces.go b/internal/modules/datasets/interfaces.go index d6245b258..6c2f7adee 100644 --- a/internal/modules/datasets/interfaces.go +++ b/internal/modules/datasets/interfaces.go @@ -18,6 +18,6 @@ type Engine interface { DeleteDataset(ctx context.Context, dbid string, caller []byte) error Execute(ctx context.Context, data *types.ExecutionData) (*sql.ResultSet, error) GetSchema(ctx context.Context, dbid string) (*types.Schema, error) - ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetInfo, error) + ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetIdentifier, error) Query(ctx context.Context, dbid string, query string) (*sql.ResultSet, error) } diff --git a/internal/modules/datasets/read.go b/internal/modules/datasets/read.go index 3e5438140..fe684c14c 100644 --- a/internal/modules/datasets/read.go +++ b/internal/modules/datasets/read.go @@ -62,7 +62,7 @@ func (u *DatasetModule) GetSchema(ctx context.Context, dbid string) (*engineType } // ListOwnedDatabase returns a list of databases owned by a public key. -func (u *DatasetModule) ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetInfo, error) { +func (u *DatasetModule) ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetIdentifier, error) { return u.engine.ListDatasets(ctx, owner) } diff --git a/internal/services/grpc/txsvc/v1/service.go b/internal/services/grpc/txsvc/v1/service.go index c674668f1..b11529eef 100644 --- a/internal/services/grpc/txsvc/v1/service.go +++ b/internal/services/grpc/txsvc/v1/service.go @@ -52,7 +52,7 @@ func NewService(engine EngineReader, accountStore AccountReader, vstore Validato type EngineReader interface { Call(ctx context.Context, dbid string, action string, args []any, msg *transactions.CallMessage) ([]map[string]any, error) GetSchema(ctx context.Context, dbid string) (*engineTypes.Schema, error) - ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetInfo, error) + ListOwnedDatabases(ctx context.Context, owner []byte) ([]*coreTypes.DatasetIdentifier, error) PriceDeploy(ctx context.Context, schema *engineTypes.Schema) (price *big.Int, err error) PriceDrop(ctx context.Context, dbid string) (price *big.Int, err error) PriceExecute(ctx context.Context, dbid string, action string, args [][]any) (price *big.Int, err error) diff --git a/test/driver/cli_driver.go b/test/driver/cli_driver.go index 1b7da9cda..67ed611c3 100644 --- a/test/driver/cli_driver.go +++ b/test/driver/cli_driver.go @@ -66,7 +66,7 @@ func (d *KwilCliDriver) DBID(name string) string { return utils.GenerateDBID(name, d.identity) } -func (d *KwilCliDriver) listDatabase() ([]*types.DatasetInfo, error) { +func (d *KwilCliDriver) listDatabase() ([]*types.DatasetIdentifier, error) { cmd := d.newKwilCliCmd("database", "list", "--owner", hex.EncodeToString(d.identity)) out, err := mustRun(cmd, d.logger) if err != nil { @@ -437,13 +437,13 @@ func parseRespQueryDb(data any) (*client.Records, error) { return client.NewRecordsFromMaps(resp), nil } -func parseRespListDatabases(data any) ([]*types.DatasetInfo, error) { +func parseRespListDatabases(data any) ([]*types.DatasetIdentifier, error) { bts, err := json.Marshal(data) if err != nil { return nil, fmt.Errorf("failed to marshal list databases resp: %w", err) } - var resp []*types.DatasetInfo + var resp []*types.DatasetIdentifier err = json.Unmarshal(bts, &resp) if err != nil { return nil, fmt.Errorf("failed to unmarshal list databases: %w", err) diff --git a/test/stress/transport.go b/test/stress/transport.go index 0659b00a6..235b334a8 100644 --- a/test/stress/transport.go +++ b/test/stress/transport.go @@ -51,7 +51,7 @@ func (tc *timedClient) Query(ctx context.Context, dbid string, query string) ([] return tc.cl.Query(ctx, dbid, query) } -func (tc *timedClient) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetInfo, error) { +func (tc *timedClient) ListDatabases(ctx context.Context, ownerIdentifier []byte) ([]*types.DatasetIdentifier, error) { if tc.showReqDur { defer tc.printDur(time.Now(), "ListDatabases") } From 7faf116f4e9a536d9aabc72fef4758a56b70bf26 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:25:35 -0600 Subject: [PATCH 10/13] fixed cookie path issue --- cmd/kwil-cli/cmds/common/roundtripper.go | 3 ++- cmd/kwil-cli/cmds/database/call.go | 10 +++++----- core/crypto/auth/auth_test.go | 14 ++++++++++++++ core/gatewayclient/client.go | 11 +++++++++-- core/gatewayclient/msg.go | 6 ++++-- core/rpc/client/gateway/http/client.go | 12 ++++++++++++ 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/cmd/kwil-cli/cmds/common/roundtripper.go b/cmd/kwil-cli/cmds/common/roundtripper.go index 359875bed..4692b0cd3 100644 --- a/cmd/kwil-cli/cmds/common/roundtripper.go +++ b/cmd/kwil-cli/cmds/common/roundtripper.go @@ -75,7 +75,8 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr } } - sig, err := signer.Sign([]byte(message)) + toSign := []byte(message) + sig, err := signer.Sign(toSign) if err != nil { return nil, err } diff --git a/cmd/kwil-cli/cmds/database/call.go b/cmd/kwil-cli/cmds/database/call.go index 3188c6523..33114d29d 100644 --- a/cmd/kwil-cli/cmds/database/call.go +++ b/cmd/kwil-cli/cmds/database/call.go @@ -57,24 +57,24 @@ func callCmd() *cobra.Command { return common.DialClient(cmd.Context(), cmd, dialFlags, func(ctx context.Context, clnt common.Client, conf *config.KwilCliConfig) error { dbid, err := getSelectedDbid(cmd, conf) if err != nil { - display.PrintErr(cmd, fmt.Errorf("target database not properly specified: %w", err)) + return display.PrintErr(cmd, fmt.Errorf("target database not properly specified: %w", err)) } lowerName := strings.ToLower(action) inputs, err := parseInputs(args) if err != nil { - display.PrintErr(cmd, fmt.Errorf("error getting inputs: %w", err)) + return display.PrintErr(cmd, fmt.Errorf("error getting inputs: %w", err)) } actionStructure, err := getAction(ctx, clnt, dbid, lowerName) if err != nil { - display.PrintErr(cmd, fmt.Errorf("error getting action: %w", err)) + return display.PrintErr(cmd, fmt.Errorf("error getting action: %w", err)) } tuples, err := createActionInputs(inputs, actionStructure) if err != nil { - display.PrintErr(cmd, fmt.Errorf("error creating action inputs: %w", err)) + return display.PrintErr(cmd, fmt.Errorf("error creating action inputs: %w", err)) } if len(tuples) == 0 { @@ -83,7 +83,7 @@ func callCmd() *cobra.Command { data, err := clnt.CallAction(ctx, dbid, lowerName, tuples[0]) if err != nil { - display.PrintErr(cmd, fmt.Errorf("error calling action: %w", err)) + return display.PrintErr(cmd, fmt.Errorf("error calling action: %w", err)) } if data == nil { diff --git a/core/crypto/auth/auth_test.go b/core/crypto/auth/auth_test.go index d88c0f3b8..9a85855cb 100644 --- a/core/crypto/auth/auth_test.go +++ b/core/crypto/auth/auth_test.go @@ -1,6 +1,7 @@ package auth_test import ( + "fmt" "testing" "github.com/kwilteam/kwil-db/core/crypto" @@ -78,3 +79,16 @@ func newEd25519Signer(pkey string) *auth.Ed25519Signer { return &auth.Ed25519Signer{Ed25519PrivateKey: *edKey} } + +func Test_del(t *testing.T) { + sig := []byte("\xb7Ka\\\xd35LSߨ\x8b\xf6\x9ate*\xf5\r\xd7Q \xd31\xe7\xec}\xd1Wl\t\xe2\x04xv/\x91\xb6f:\xe9\x01Uy)%+V\xa5]\x18#X\x19\xbaa!\x1ek\xe9\xa9\xee>E0\x01") + sender := []byte("\xaf\xfd\xc0l\xf3J\xfd}X\x01\xa1=H\xc9*Ӗ\t\x90\x1d") + msg := []byte("https://localhost wants you to sign in with your account:\n\nsign pws\n\nURI: https://localhost/auth\nVersion: 1\nChain ID: kwil-chain-shyc8zBu\nNonce: 236f0c9b3d285df2fe29\nIssue At: 2023-12-05T17:50:13Z\nExpiration Time: 2023-12-05T17:50:43Z\n") + + fmt.Println(sender) + fmt.Println(string(msg)) + + err := auth.EthSecp256k1Authenticator{}.Verify(sender, msg, sig) + assert.NoError(t, err) + +} diff --git a/core/gatewayclient/client.go b/core/gatewayclient/client.go index ce3bbeeea..9cf987682 100644 --- a/core/gatewayclient/client.go +++ b/core/gatewayclient/client.go @@ -100,7 +100,9 @@ func (c *GatewayClient) CallAction(ctx context.Context, dbid string, action stri // authenticate authenticates the client with the gateway. func (c *GatewayClient) authenticate(ctx context.Context) error { authParam, err := c.gatewayClient.GetAuthParameter(ctx) - if err != nil { + if errors.Is(err, rpcClient.ErrNotFound) { + return fmt.Errorf("failed to get auth parameter. are you sure you're talking to a gateway? err: %w", err) + } else if err != nil { return fmt.Errorf("get auth parameter: %w", err) } @@ -120,11 +122,16 @@ func (c *GatewayClient) authenticate(ctx context.Context) error { } // send the auth request - return c.gatewayClient.Auth(ctx, &gatewayTypes.GatewayAuth{ + err = c.gatewayClient.Auth(ctx, &gatewayTypes.GatewayAuth{ Nonce: authParam.Nonce, Sender: c.Signer.Identity(), Signature: sig, }) + if err != nil { + return fmt.Errorf("gateway auth: %w", err) + } + + return nil } // GetAuthCookie returns the authentication cookie currently being used. diff --git a/core/gatewayclient/msg.go b/core/gatewayclient/msg.go index 54d0b4539..168414636 100644 --- a/core/gatewayclient/msg.go +++ b/core/gatewayclient/msg.go @@ -44,7 +44,7 @@ func composeGatewayAuthMessage(param *types.GatewayAuthParameter, domain string, version string, chainID string) string { var msg bytes.Buffer msg.WriteString( - fmt.Sprintf("%s wants you to sign in with your account:\n", domain)) + fmt.Sprintf("%s wants you to sign in with your account:\n", domain)) // apparently this HAS to use https, according to the standard msg.WriteString("\n") if param.Statement != "" { msg.WriteString(fmt.Sprintf("%s\n", param.Statement)) @@ -55,6 +55,8 @@ func composeGatewayAuthMessage(param *types.GatewayAuthParameter, domain string, msg.WriteString(fmt.Sprintf("Chain ID: %s\n", chainID)) msg.WriteString(fmt.Sprintf("Nonce: %s\n", param.Nonce)) msg.WriteString(fmt.Sprintf("Issue At: %s\n", param.IssueAt)) - msg.WriteString(fmt.Sprintf("Expiration Time: %s\n", param.ExpirationTime)) + if param.ExpirationTime != "" { + msg.WriteString(fmt.Sprintf("Expiration Time: %s\n", param.ExpirationTime)) + } return msg.String() } diff --git a/core/rpc/client/gateway/http/client.go b/core/rpc/client/gateway/http/client.go index c718844a5..5f37741ec 100644 --- a/core/rpc/client/gateway/http/client.go +++ b/core/rpc/client/gateway/http/client.go @@ -9,6 +9,7 @@ import ( "net/http/cookiejar" "net/url" + rpcClient "github.com/kwilteam/kwil-db/core/rpc/client" "github.com/kwilteam/kwil-db/core/rpc/client/gateway" types "github.com/kwilteam/kwil-db/core/types/gateway" ) @@ -77,6 +78,10 @@ func (g *GatewayHttpClient) Auth(ctx context.Context, auth *types.GatewayAuth) e } defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return errors.Join(rpcClient.ErrNotFound, errors.New(res.Status)) + } + var r gatewayAuthPostResponse err = json.NewDecoder(res.Body).Decode(&r) if err != nil { @@ -103,6 +108,13 @@ func (g *GatewayHttpClient) GetAuthParameter(ctx context.Context) (*types.Gatewa } defer res.Body.Close() + if res.StatusCode == http.StatusNotFound { + return nil, errors.Join(rpcClient.ErrNotFound, errors.New(res.Status)) + } + if res.StatusCode != http.StatusOK { + return nil, errors.New(res.Status) + } + var r gatewayAuthGetResponse err = json.NewDecoder(res.Body).Decode(&r) if err != nil { From 3b8c35a5e02183d7b0f431c6b145c8f768b2a70e Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:38:27 -0600 Subject: [PATCH 11/13] addressed jons feedback --- Taskfile.yml | 2 - cmd/kwild/config/config.go | 2 +- core/crypto/auth/auth_test.go | 14 ----- .../rpc/http/function/.swagger-codegen-ignore | 1 + core/rpc/http/function/git_push.sh | 52 ------------------- core/rpc/http/tx/.swagger-codegen-ignore | 1 + core/rpc/http/tx/git_push.sh | 52 ------------------- deployments/compose/run.sh | 2 +- internal/abci/utils.go | 20 +------ internal/engine/execution/global.go | 17 +----- scripts/publish/dockerhub | 2 +- 11 files changed, 9 insertions(+), 156 deletions(-) delete mode 100644 core/rpc/http/function/git_push.sh delete mode 100644 core/rpc/http/tx/git_push.sh diff --git a/Taskfile.yml b/Taskfile.yml index 098ae1b0e..13d62c3b2 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -145,7 +145,6 @@ tasks: desc: Start the dev environment deps: - task: build:docker - vars: {VARIANT: 'shell'} cmds: - task: dev:up:nb @@ -170,7 +169,6 @@ tasks: desc: Start the dev environment(with testnet) deps: - task: build:docker - vars: { VARIANT: 'shell' } cmds: - task: dev:testnet:up:nb diff --git a/cmd/kwild/config/config.go b/cmd/kwild/config/config.go index e497462c5..ad6e80ad3 100644 --- a/cmd/kwild/config/config.go +++ b/cmd/kwild/config/config.go @@ -427,7 +427,7 @@ func DefaultConfig() *KwildConfig { }, ChainCfg: &ChainConfig{ P2P: &P2PConfig{ - ListenAddress: "tcp://127.0.0.1:26656", + ListenAddress: "tcp://0.0.0.0:26656", ExternalAddress: "", AddrBookStrict: false, // override comet MaxNumInboundPeers: 40, diff --git a/core/crypto/auth/auth_test.go b/core/crypto/auth/auth_test.go index 9a85855cb..d88c0f3b8 100644 --- a/core/crypto/auth/auth_test.go +++ b/core/crypto/auth/auth_test.go @@ -1,7 +1,6 @@ package auth_test import ( - "fmt" "testing" "github.com/kwilteam/kwil-db/core/crypto" @@ -79,16 +78,3 @@ func newEd25519Signer(pkey string) *auth.Ed25519Signer { return &auth.Ed25519Signer{Ed25519PrivateKey: *edKey} } - -func Test_del(t *testing.T) { - sig := []byte("\xb7Ka\\\xd35LSߨ\x8b\xf6\x9ate*\xf5\r\xd7Q \xd31\xe7\xec}\xd1Wl\t\xe2\x04xv/\x91\xb6f:\xe9\x01Uy)%+V\xa5]\x18#X\x19\xbaa!\x1ek\xe9\xa9\xee>E0\x01") - sender := []byte("\xaf\xfd\xc0l\xf3J\xfd}X\x01\xa1=H\xc9*Ӗ\t\x90\x1d") - msg := []byte("https://localhost wants you to sign in with your account:\n\nsign pws\n\nURI: https://localhost/auth\nVersion: 1\nChain ID: kwil-chain-shyc8zBu\nNonce: 236f0c9b3d285df2fe29\nIssue At: 2023-12-05T17:50:13Z\nExpiration Time: 2023-12-05T17:50:43Z\n") - - fmt.Println(sender) - fmt.Println(string(msg)) - - err := auth.EthSecp256k1Authenticator{}.Verify(sender, msg, sig) - assert.NoError(t, err) - -} diff --git a/core/rpc/http/function/.swagger-codegen-ignore b/core/rpc/http/function/.swagger-codegen-ignore index c5fa491b4..c2256b7be 100644 --- a/core/rpc/http/function/.swagger-codegen-ignore +++ b/core/rpc/http/function/.swagger-codegen-ignore @@ -21,3 +21,4 @@ #docs/*.md # Then explicitly reverse the ignore rule for a single file: #!docs/README.md +git_push.sh \ No newline at end of file diff --git a/core/rpc/http/function/git_push.sh b/core/rpc/http/function/git_push.sh deleted file mode 100644 index ae01b182a..000000000 --- a/core/rpc/http/function/git_push.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="GIT_USER_ID" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="GIT_REPO_ID" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="Minor update" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/core/rpc/http/tx/.swagger-codegen-ignore b/core/rpc/http/tx/.swagger-codegen-ignore index c5fa491b4..c2256b7be 100644 --- a/core/rpc/http/tx/.swagger-codegen-ignore +++ b/core/rpc/http/tx/.swagger-codegen-ignore @@ -21,3 +21,4 @@ #docs/*.md # Then explicitly reverse the ignore rule for a single file: #!docs/README.md +git_push.sh \ No newline at end of file diff --git a/core/rpc/http/tx/git_push.sh b/core/rpc/http/tx/git_push.sh deleted file mode 100644 index ae01b182a..000000000 --- a/core/rpc/http/tx/git_push.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="GIT_USER_ID" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="GIT_REPO_ID" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="Minor update" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/deployments/compose/run.sh b/deployments/compose/run.sh index 6d9a56bca..1edfac154 100755 --- a/deployments/compose/run.sh +++ b/deployments/compose/run.sh @@ -16,7 +16,7 @@ bringup() { start() { # Build Kwild - test $1 && task --taskfile ../../Taskfile.yml build:docker -- shell && task build || echo "skip build image" + test $1 && task --taskfile ../../Taskfile.yml build:docker && task build || echo "skip build image" # start kwild printf "bringing up kwild services: \n" diff --git a/internal/abci/utils.go b/internal/abci/utils.go index 721086b10..9af6e6bc1 100644 --- a/internal/abci/utils.go +++ b/internal/abci/utils.go @@ -96,24 +96,8 @@ type PrivateKeyInfo struct { } func (p *PrivateKeyInfo) MarshalJSON() ([]byte, error) { - // must use anonymous struct to avoid infinite recursion - return json.Marshal(struct { - PrivateKeyHex string `json:"private_key_hex"` - PrivateKeyBase64 string `json:"private_key_base64"` - PublicKeyBase64 string `json:"public_key_base64"` - PublicKeyCometizedHex string `json:"public_key_cometized_hex"` - PublicKeyPlainHex string `json:"public_key_plain_hex"` - Address string `json:"address"` - NodeID string `json:"node_id"` - }{ - PrivateKeyHex: p.PrivateKeyHex, - PrivateKeyBase64: p.PrivateKeyBase64, - PublicKeyBase64: p.PublicKeyBase64, - PublicKeyCometizedHex: p.PublicKeyCometizedHex, - PublicKeyPlainHex: p.PublicKeyPlainHex, - Address: p.Address, - NodeID: p.NodeID, - }) + type pki PrivateKeyInfo + return json.Marshal((*pki)(p)) } func (p *PrivateKeyInfo) MarshalText() ([]byte, error) { diff --git a/internal/engine/execution/global.go b/internal/engine/execution/global.go index 769c9cfe7..cd9a76180 100644 --- a/internal/engine/execution/global.go +++ b/internal/engine/execution/global.go @@ -156,24 +156,11 @@ func (g *GlobalContext) Execute(ctx context.Context, options *types.ExecutionDat } // ListDatasets list datasets deployed by a specific caller. -// If caller is nil, it will list all datasets. +// If caller is empty, it will list all datasets. func (g *GlobalContext) ListDatasets(ctx context.Context, caller []byte) ([]*coreTypes.DatasetIdentifier, error) { datasets := make([]*coreTypes.DatasetIdentifier, 0, len(g.datasets)) - - if len(caller) == 0 { - for dbid, dataset := range g.datasets { - datasets = append(datasets, &coreTypes.DatasetIdentifier{ - Name: dataset.schema.Name, - Owner: dataset.schema.Owner, - DBID: dbid, - }) - } - - return datasets, nil - } - for dbid, dataset := range g.datasets { - if bytes.Equal(dataset.schema.Owner, caller) { + if len(caller) == 0 || bytes.Equal(dataset.schema.Owner, caller) { datasets = append(datasets, &coreTypes.DatasetIdentifier{ Name: dataset.schema.Name, Owner: dataset.schema.Owner, diff --git a/scripts/publish/dockerhub b/scripts/publish/dockerhub index 84df785fc..7e1238d89 100755 --- a/scripts/publish/dockerhub +++ b/scripts/publish/dockerhub @@ -7,4 +7,4 @@ set -eu echo Building kwild for multiarch and pushing to dockerhub, tag: ${TAG} -docker buildx build --platform linux/amd64,linux/arm64/v8 -t kwildb/kwil:${TAG} --build-arg go_build_tags=${GO_BUILDTAGS} --push -f ./build/package/docker/kwild.shell.dockerfile . \ No newline at end of file +docker buildx build --platform linux/amd64,linux/arm64/v8 -t kwildb/kwil:${TAG} --build-arg go_build_tags=${GO_BUILDTAGS} --push -f ./build/package/docker/kwild.dockerfile . \ No newline at end of file From e7f3784d96e7624717ce0582c7143d498a493697 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:36:31 -0600 Subject: [PATCH 12/13] changed cookie persistence to support persistence with automatic cookies (previously only persisted manual auth) --- cmd/kwil-cli/cmds/common/roundtripper.go | 18 +++++++++++++++++- cmd/kwil-cli/cmds/utils/auth.go | 11 +---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/cmd/kwil-cli/cmds/common/roundtripper.go b/cmd/kwil-cli/cmds/common/roundtripper.go index 4692b0cd3..5b68d326e 100644 --- a/cmd/kwil-cli/cmds/common/roundtripper.go +++ b/cmd/kwil-cli/cmds/common/roundtripper.go @@ -109,7 +109,23 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr } } - return fn(ctx, client, conf) + err = fn(ctx, client, conf) + if err != nil { + return err + } + + // persist the cookie + cookie, found := client.GetAuthCookie() + if !found { + return nil + } + + err = SaveCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity(), cookie) + if err != nil { + return fmt.Errorf("save cookie: %w", err) + } + + return nil } // Client is a client that can be used to talk to a kwil node diff --git a/cmd/kwil-cli/cmds/utils/auth.go b/cmd/kwil-cli/cmds/utils/auth.go index bd37a17f8..ce11c460f 100644 --- a/cmd/kwil-cli/cmds/utils/auth.go +++ b/cmd/kwil-cli/cmds/utils/auth.go @@ -50,16 +50,7 @@ func kgwAuthnCmd() *cobra.Command { return display.PrintErr(cmd, fmt.Errorf("authentication failed: %w", err)) } - // retrieve the cookie and persist it - cookie, found := gatewayClient.GetAuthCookie() - if !found { - return display.PrintErr(cmd, fmt.Errorf("authentication failed: cookie could not be found")) - } - - err = common.SaveCookie(common.KGWAuthTokenFilePath(), gatewayClient.Signer.Identity(), cookie) - if err != nil { - return display.PrintErr(cmd, fmt.Errorf("save cookie: %w", err)) - } + // we do not need to persist the cookie since DialClient will do that for us return display.PrintCmd(cmd, display.RespString("Success")) }) From b0bee6d3a8fcccd89492e9337fcdaa51d74862f7 Mon Sep 17 00:00:00 2001 From: Brennan Lamey <66885902+brennanjl@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:42:57 -0600 Subject: [PATCH 13/13] rebased and updated proto --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 9a836553c..6fa7f850e 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 9a836553c13f1f176c3249849ed5bb489e446f7a +Subproject commit 6fa7f850e9e068822cdecb5d02139ae1b531191e