├── .DS_Store ├── .dockerignore ├── .github └── workflows │ ├── CD.yml │ └── CI.yml ├── .gitignore ├── API.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── block_parser ├── action_account_cell.go ├── action_account_sale_cell.go ├── action_apply_register_cell.go ├── action_approval.go ├── action_balance_cell.go ├── action_config_cell.go ├── action_did_cell.go ├── action_did_cell_v2.go ├── action_income_cell.go ├── action_keylist_config_cell.go ├── action_offer_cell.go ├── action_pre_register_cell.go ├── action_propose_cell.go ├── action_reverse_record_cell.go ├── action_reverse_record_root.go ├── action_sub_account_cell.go ├── block_parser.go ├── block_parser_handle.go └── block_parser_test.go ├── cmd └── main.go ├── compose.yaml ├── config ├── config.example.yaml ├── config.go └── contract.go ├── dao ├── api.md ├── dao.go ├── dao_account_info.go ├── dao_approval_info.go ├── dao_authorize.go ├── dao_block_info.go ├── dao_cid_pk.go ├── dao_custom_script_info.go ├── dao_did_cell_info.go ├── dao_income_cell_info.go ├── dao_offer_info.go ├── dao_rebate_info.go ├── dao_records_info.go ├── dao_reverse_info.go ├── dao_reverse_smt_info.go ├── dao_rule_config.go ├── dao_smt_info.go ├── dao_snapshot_permissions_info.go ├── dao_snapshot_register_info.go ├── dao_snapshot_tx_info.go ├── dao_subaccount_auto_mint_statement.go ├── dao_test.go ├── dao_token_price_info.go ├── dao_trade_deal_info.go ├── dao_trade_history_info.go ├── dao_trade_info.go ├── dao_transaction_info.go └── das_database.sql ├── example ├── api_test.go └── pkeyListParse_test.go ├── go.mod ├── go.sum ├── http_server ├── api_code │ ├── common.go │ ├── json_rpc.go │ └── monitor.go ├── handle │ ├── handle.go │ ├── handle_test.go │ ├── jason_rpc_handle.go │ ├── pagination.go │ ├── snapshot_address_accounts.go │ ├── snapshot_did_list.go │ ├── snapshot_permissions_info.go │ ├── snapshot_progress.go │ ├── snapshot_register_history.go │ ├── snapshot_verify.go │ └── version.go └── http_server.go ├── notify ├── lark.go └── notify_test.go ├── prometheus └── prometheus.go ├── snapshot ├── permissions.go ├── register.go ├── snapshot.go ├── snapshot_test.go └── tx.go └── timer ├── charset.go ├── timer.go ├── timer_gecko.go ├── timer_test.go └── timer_token.go /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotbitHQ/das-database/419fa565df6d25eb00ce4cc92d310149abf3ce6f/.DS_Store -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/*_test.go 2 | .idea/ 3 | .git/ -------------------------------------------------------------------------------- /.github/workflows/CD.yml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - CI 7 | types: 8 | - completed 9 | 10 | jobs: 11 | cd: 12 | runs-on: sg 13 | if: github.event.workflow_run.conclusion == 'success' 14 | steps: 15 | - name: Download Artifct 16 | uses: dawidd6/action-download-artifact@v2 17 | with: 18 | workflow: CI 19 | workflow_conclusion: success 20 | run_id: ${{ github.event.workflow_run.id }} 21 | run_number: ${{ github.event.workflow_run.run_number }} 22 | name: das_database_server_${{ github.event.workflow_run.head_commit.id }} 23 | - name: Deploy 24 | run: | 25 | host_name="" 26 | branch="${{ github.event.workflow_run.head_branch }}" 27 | if [[ "$branch" == "dev" ]]; then 28 | host_name="backendtest" 29 | elif [[ "$branch" == "test3" ]]; then 30 | host_name="backendtest3" 31 | else 32 | echo "Skipping build and deploy for branch ${branch}" 33 | exit 1 34 | fi 35 | 36 | rsync -a das_database_server root@"$host_name":/mnt/das/server/das_database/das_database_server 37 | ssh root@"$host_name" 'chmod +x /mnt/das/server/das_database/das_database_server' 38 | ssh root@"$host_name" 'supervisorctl restart das_database_svr' -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - dev 7 | - test3 8 | 9 | jobs: 10 | ci: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up Go 15 | uses: actions/setup-go@v4 16 | with: 17 | go-version-file: go.mod 18 | cache: false 19 | - name: Build 20 | run: make default 21 | - name: Upload Artifacts 22 | uses: actions/upload-artifact@v3.1.2 23 | with: 24 | name: das_database_server_${{ github.sha }} 25 | path: bin/linux/das_database_server 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | vendor 16 | .idea 17 | bin 18 | 19 | # execute file 20 | das_database 21 | das_database.exe 22 | das_database_server 23 | 24 | # temp file 25 | config/config.yaml 26 | mysql-data -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | * [API List](#API-List) 2 | * [Get Account History Permission](#Get-Account-History-Permission) 3 | * [Get Address History Hold Accounts](#Get-Address-History-Hold-Accounts) 4 | * [Get Snapshot Register Progress](Get-Snapshot-Register-Progress) 5 | * [Get Snapshot Progress](#Get-Snapshot-Progress) 6 | 7 | ## API List 8 | 9 | Please familiarize yourself with the meaning of some common parameters before reading the API list: 10 | 11 | | param | description | 12 | |:-------------------------------------------------------------------------------|:---------------------------------------------------| 13 | | type | Filled with "blockchain" for now | 14 | | [coin_type](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) | 60: eth, 195: trx, 9006: bsc, 966: matic, 3: doge | 15 | | account | Contains the suffix `.bit` in it | 16 | | key | Generally refers to the blockchain address for now | 17 | 18 | ### Error Code 19 | 20 | ```txt 21 | ApiCodeError500 ApiCode = 500 // server err 22 | ApiCodeParamsInvalid ApiCode = 10000 // invalid params 23 | ApiCodeMethodNotExist ApiCode = 10001 // method not exist 24 | ApiCodeDbError ApiCode = 10002 // db err 25 | ApiCodeAccountPermissionsDoNotExist ApiCode = 30020 // Account permission does not exist 26 | ApiCodeAccountHasBeenRecycled ApiCode = 30021 // Account has been recycled 27 | ApiCodeAccountCrossChain ApiCode = 30022 // Account cross-chain 28 | ApiCodeAccountExpired ApiCode = 20023 // account expired 29 | 30 | ``` 31 | 32 | ### Algorithm ID 33 | 34 | ```txt 35 | 36 | DasAlgorithmIdEth DasAlgorithmId = 3 // ETH Personal Sign 37 | DasAlgorithmIdTron DasAlgorithmId = 4 // TRON Personal Sign 38 | DasAlgorithmIdEth712 DasAlgorithmId = 5 // ETH 712 Sign 39 | DasAlgorithmIdEd25519 DasAlgorithmId = 6 // Ed25519 40 | DasAlgorithmIdDogeChain DasAlgorithmId = 7 // Doge Sign 41 | ``` 42 | 43 | ### Get Account History Permission 44 | 45 | **Request** 46 | * path: /v1/snapshot/permissions/info 47 | * param: 48 | 49 | ```json 50 | { 51 | "account": "7aaaaaaa.bit", 52 | "block_number": 3593828 53 | } 54 | ``` 55 | 56 | **Response** 57 | 58 | * owner_algorithm_id: The algorithm flag of the chain to which the address belongs 59 | 60 | ```json 61 | { 62 | "errno": 0, 63 | "errmsg": "", 64 | "data": { 65 | "account": "7aaaaaaa.bit", 66 | "account_id": "0xc475fcded6955abc8bf6e2f23e68c6912159505d", 67 | "block_number": 3512736, 68 | "owner": "0xc9f53b1d85356b60453f867610888d89a0b667ad", 69 | "owner_algorithm_id": 5, 70 | "manager": "0xc9f53b1d85356b60453f867610888d89a0b667ad", 71 | "manager_algorithm_id": 5 72 | } 73 | } 74 | ``` 75 | 76 | **Usage** 77 | 78 | ```shell 79 | curl -X POST http://127.0.0.1:8118/v1/snapshot/permissions/info -d'{"account":"7aaaaaaa.bit","block_number":3593828}' 80 | ``` 81 | 82 | or json rpc style: 83 | 84 | ```shell 85 | curl -X POST http://127.0.0.1:8118 -d'{"jsonrpc": "2.0","id": 1,"method": "snapshot_permissions_info","params": [{"account":"7aaaaaaa.bit","block_number":3593828}]}' 86 | ``` 87 | 88 | ### Get Address History Hold Accounts 89 | 90 | **Request** 91 | * path: /v1/snapshot/address/accounts 92 | * param: 93 | * role_type: (permission role type) manager or owner 94 | * size: [1,100] 95 | ```json 96 | { 97 | "type": "blockchain", 98 | "key_info": { 99 | "coin_type": "195", 100 | "key": "41a2ac25bf43680c05abe82c7b1bcc1a779cff8d5d" 101 | }, 102 | "block_number": 1941502, 103 | "role_type": "manager", 104 | "page": 1, 105 | "size": 100 106 | } 107 | ``` 108 | 109 | **Response** 110 | 111 | ```json 112 | { 113 | "errno": 0, 114 | "errmsg": "", 115 | "data": { 116 | "accounts": [ 117 | { 118 | "account": "8aaaaaaa.bit" 119 | }, 120 | { 121 | "account": "9aaaaaaa.bit" 122 | } 123 | ] 124 | } 125 | } 126 | ``` 127 | 128 | **Usage** 129 | 130 | ```shell 131 | curl -X POST http://127.0.0.1:8118/v1/snapshot/address/accounts -d'{"type":"blockchain","key_info":{"coin_type":"195","key":"41a2ac25bf43680c05abe82c7b1bcc1a779cff8d5d"},"block_number":1941502,"role_type":"manager"}' 132 | ``` 133 | 134 | or json rpc style: 135 | 136 | ```shell 137 | curl -X POST http://127.0.0.1:8118 -d'{"jsonrpc": "2.0","id": 1,"method": "snapshot_address_accounts","params": [{"type":"blockchain","key_info":{"coin_type":"195","key":"41a2ac25bf43680c05abe82c7b1bcc1a779cff8d5d"},"block_number":1941502,"role_type":"manager"}]}' 138 | ``` 139 | 140 | ### Get Snapshot Progress 141 | 142 | **Request** 143 | * path: /v1/snapshot/progress 144 | * param: 145 | * role_type: (permission role type) manager or owner 146 | * size: [1,100] 147 | ```json 148 | { 149 | "block_number": 1941502 150 | } 151 | ``` 152 | 153 | **Response** 154 | 155 | ```json 156 | { 157 | "errno": 0, 158 | "errmsg": "", 159 | "data": { 160 | "block_number": 1941502 161 | } 162 | } 163 | ``` 164 | 165 | **Usage** 166 | 167 | ```shell 168 | curl -X POST http://127.0.0.1:8118/v1/snapshot/progress -d'{"block_number": 1941502}' 169 | ``` 170 | 171 | ### Get Snapshot Register Progress 172 | 173 | **Request** 174 | * path: /v1/snapshot/register/history 175 | * param: 176 | * role_type: (permission role type) manager or owner 177 | * size: [1,100] 178 | ```json 179 | { 180 | "start_time": 0 181 | } 182 | ``` 183 | 184 | **Response** 185 | 186 | ```json 187 | { 188 | "errno": 0, 189 | "errmsg": "", 190 | "data": { 191 | "result": "" 192 | } 193 | } 194 | ``` 195 | 196 | **Usage** 197 | 198 | ```shell 199 | curl -X POST http://127.0.0.1:8118/v1/snapshot/register/history -d'{"start_time": 0}' 200 | ``` 201 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | ## 4 | ## Build 5 | ## 6 | FROM golang:1.18.10-buster AS build 7 | 8 | WORKDIR /app 9 | 10 | COPY . ./ 11 | 12 | ENV GOPROXY=https://goproxy.cn,direct 13 | 14 | RUN go build -ldflags -s -v -o das-database cmd/main.go 15 | 16 | ## 17 | ## Deploy 18 | ## 19 | FROM ubuntu 20 | 21 | ARG TZ=Asia/Shanghai 22 | 23 | RUN export DEBIAN_FRONTEND=noninteractive \ 24 | && apt-get update \ 25 | && apt-get install -y ca-certificates tzdata \ 26 | && ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \ 27 | && echo ${TZ} > /etc/timezone \ 28 | && dpkg-reconfigure tzdata \ 29 | && rm -rf /var/lib/apt/lists/* 30 | 31 | WORKDIR /app 32 | 33 | COPY --from=build /app/das-database /app/das-database 34 | COPY --from=build /app/config/config.example.yaml /app/config/config.yaml 35 | 36 | EXPOSE 8118 37 | 38 | ENTRYPOINT ["/app/das-database", "--config", "/app/config/config.yaml"] 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 DAS Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # build file 2 | GO_BUILD=go build -ldflags -s -v 3 | BINARY_NAME=das_database_server 4 | 5 | # update 6 | update: 7 | go mod tidy 8 | 9 | # linux 10 | parser_linux: 11 | export GOOS=linux 12 | export GOARCH=amd64 13 | $(GO_BUILD) -o $(BINARY_NAME) cmd/main.go 14 | mkdir -p bin/linux 15 | mv $(BINARY_NAME) bin/linux/ 16 | @echo "build $(BINARY_NAME) successfully." 17 | 18 | # mac 19 | parser_mac: 20 | export GOOS=darwin 21 | export GOARCH=amd64 22 | $(GO_BUILD) -o $(BINARY_NAME) cmd/main.go 23 | mkdir -p bin/mac 24 | mv $(BINARY_NAME) bin/mac/ 25 | @echo "build $(BINARY_NAME) successfully." 26 | 27 | # win 28 | parser_win: BINARY_NAME=das_database_server.exe 29 | parser_win: 30 | export GOOS=windows 31 | export GOARCH=amd64 32 | $(GO_BUILD) -o $(BINARY_NAME) cmd/main.go 33 | mkdir -p bin/win 34 | mv $(BINARY_NAME) bin/win/ 35 | @echo "build $(BINARY_NAME) successfully." 36 | 37 | docker: 38 | docker build --network host -t admindid/das-database:latest . 39 | 40 | docker-publish: 41 | docker image push admindid/das-database:latest 42 | 43 | # default 44 | default: parser_linux 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # das-database 2 | A block parser tool that allows extraction of various data types on DAS 3 | (register, edit, sell, transfer, ...) from CKB 4 | ## Prerequisites 5 | * Ubuntu 18.04 or newer 6 | * MYSQL >= 8.0 7 | * go version >= 1.21.3 8 | * [ckb-node](https://github.com/nervosnetwork/ckb) (Must be synced to latest height and add `Indexer` module to ckb.toml) 9 | * If the version of the dependency package is too low, please install `gcc-multilib` (apt install gcc-multilib) 10 | * Machine configuration: 4c8g200G 11 | 12 | ## Install & Run 13 | 14 | ### Source Compile 15 | ```bash 16 | # get the code 17 | git clone https://github.com/dotbitHQ/das-database.git 18 | 19 | # init config/config.yaml 20 | cp config/config.example.yaml config/config.yaml 21 | 22 | # create mysql database 23 | mysql -uroot -p 24 | > create database das_database; 25 | > quit; 26 | 27 | # compile and run 28 | cd das-database 29 | make default 30 | ./das_database_server --config=config/config.yaml 31 | # it will take about 3 hours to synchronize to the latest data(Dec 6, 2021) 32 | ``` 33 | 34 | ### Docker 35 | * docker >= 20.10 36 | * docker-compose >= 2.2.2 37 | 38 | 39 | ```bash 40 | sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 41 | sudo chmod +x /usr/local/bin/docker-compose 42 | sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 43 | docker-compose up -d 44 | ``` 45 | 46 | _if you already have a mysql installed, just run_ 47 | ```bash 48 | docker run -dp 8118:8118 -v $PWD/config/config.yaml:/app/config/config.yaml --name das-database-server admindid/das-database:latest 49 | ``` 50 | 51 | ## Usage 52 | ```sql 53 | select * from das_database.t_account_info limit 10; 54 | ``` 55 | 56 | ### Action Types 57 | All supported parsable transaction types as following: 58 | 59 | ```txt 60 | config 61 | deploy 62 | apply_register 63 | refund_apply 64 | pre_register 65 | propose 66 | extend_proposal 67 | confirm_proposal 68 | recycle_proposal 69 | edit_records 70 | edit_manager 71 | renew_account 72 | transfer_account 73 | withdraw_from_wallet 74 | consolidate_income 75 | create_income 76 | transfer_balance 77 | start_account_sale 78 | edit_account_sale 79 | cancel_account_sale 80 | buy_account 81 | declare_reverse_record 82 | redeclare_reverse_record 83 | retract_reverse_record 84 | transfer 85 | create_approval 86 | delay_approval 87 | revoke_approval 88 | fulfill_approval 89 | make_offer 90 | edit_offer 91 | cancel_offer 92 | accept_offer 93 | enable_sub_account 94 | create_sub_account 95 | edit_sub_account 96 | renew_sub_account 97 | recycle_sub_account 98 | lock_sub_account_for_cross_chain 99 | unlock_sub_account_for_cross_chain 100 | config_sub_account_custom_script 101 | config_sub_account 102 | collect_sub_account_profit 103 | update_sub_account 104 | collect_sub_account_channel_profit 105 | lock_account_for_cross_chain 106 | unlock_account_for_cross_chain 107 | force_recover_account_status 108 | recycle_expired_account 109 | update_reverse_record_root 110 | create_device_key_list 111 | update_device_key_list 112 | mint_dp 113 | transfer_dp 114 | burn_dp 115 | bid_expired_account_dutch_auction 116 | account_cell_upgrade 117 | did_edit_owner 118 | did_edit_records 119 | did_renew 120 | did_recycle 121 | did_upgrade 122 | did_register 123 | did_auction 124 | ``` 125 | 126 | ## Others 127 | * [What is DAS](https://github.com/dotbitHQ/did-contracts/blob/docs/docs/en/design/Overview-of-DAS.md) 128 | * [What is a DAS transaction on CKB](https://github.com/dotbitHQ/did-contracts/blob/docs/docs/en/developer/Transaction-Structure.md) 129 | -------------------------------------------------------------------------------- /block_parser/action_apply_register_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/scorpiotzh/toolib" 8 | ) 9 | 10 | func (b *BlockParser) ActionApplyRegister(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 11 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNameApplyRegisterCellType); err != nil { 12 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 13 | return 14 | } else if !isCV { 15 | log.Warn("not current version apply register tx") 16 | return 17 | } 18 | log.Info("ActionApplyRegister:", req.BlockNumber, req.TxHash) 19 | 20 | transactionInfo := dao.TableTransactionInfo{ 21 | BlockNumber: req.BlockNumber, 22 | Action: common.DasActionApplyRegister, 23 | ServiceType: dao.ServiceTypeRegister, 24 | Outpoint: common.OutPoint2String(req.TxHash, 0), 25 | ChainType: common.ChainTypeCkb, 26 | Address: common.Bytes2Hex(req.Tx.Outputs[0].Lock.Args), 27 | Capacity: req.Tx.Outputs[0].Capacity, 28 | BlockTimestamp: req.BlockTimestamp, 29 | } 30 | 31 | if err := b.dbDao.CreateTransactionInfo(transactionInfo); err != nil { 32 | log.Error("CreateTransactionInfo err:", err.Error(), toolib.JsonString(transactionInfo)) 33 | resp.Err = fmt.Errorf("CreateTransactionInfo err: %s", err.Error()) 34 | return 35 | } 36 | 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /block_parser/action_balance_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/scorpiotzh/toolib" 9 | ) 10 | 11 | func (b *BlockParser) ActionBalanceCells(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 12 | log.Info("ActionBalanceCells:", req.BlockNumber, req.TxHash, req.Action) 13 | 14 | dasLock, err := core.GetDasContractInfo(common.DasContractNameDispatchCellType) 15 | if err != nil { 16 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 17 | return 18 | } 19 | dasBalance, err := core.GetDasContractInfo(common.DasContractNameBalanceCellType) 20 | if err != nil { 21 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 22 | return 23 | } 24 | serviceType := dao.ServiceTypeRegister 25 | if req.Action == dao.DasActionTransferBalance { 26 | serviceType = dao.ServiceTypeTransaction 27 | } 28 | 29 | var transactionInfos []dao.TableTransactionInfo 30 | for i, v := range req.Tx.Outputs { 31 | if v.Lock.CodeHash.Hex() != dasLock.ContractTypeId.Hex() { 32 | continue 33 | } 34 | if req.Action == dao.DasActionTransferBalance && v.Type != nil && v.Type.CodeHash.Hex() != dasBalance.ContractTypeId.Hex() { 35 | continue 36 | } 37 | oldHex, _, err := b.dasCore.Daf().ArgsToHex(v.Lock.Args) 38 | if err != nil { 39 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 40 | return 41 | } 42 | transactionInfos = append(transactionInfos, dao.TableTransactionInfo{ 43 | BlockNumber: req.BlockNumber, 44 | Action: req.Action, 45 | ServiceType: serviceType, 46 | ChainType: oldHex.ChainType, 47 | Address: oldHex.AddressHex, 48 | Capacity: v.Capacity, 49 | Outpoint: common.OutPoint2String(req.TxHash, uint(i)), 50 | BlockTimestamp: req.BlockTimestamp, 51 | }) 52 | } 53 | 54 | if err = b.dbDao.CreateTransactionInfoList(transactionInfos); err != nil { 55 | log.Error("CreateTransactionInfoList err: ", err.Error(), toolib.JsonString(transactionInfos)) 56 | resp.Err = fmt.Errorf("CreateTransactionInfoList err: %s", err.Error()) 57 | return 58 | } 59 | 60 | return 61 | } 62 | 63 | func (b *BlockParser) ActionBalanceCell(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 64 | log.Info("ActionBalanceCell:", req.BlockNumber, req.TxHash, req.Action) 65 | 66 | dasLock, err := core.GetDasContractInfo(common.DasContractNameDispatchCellType) 67 | if err != nil { 68 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 69 | return 70 | } 71 | balanceType, err := core.GetDasContractInfo(common.DasContractNameBalanceCellType) 72 | if err != nil { 73 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 74 | return 75 | } 76 | serviceType := dao.ServiceTypeRegister 77 | if req.Action == common.DasActionWithdrawFromWallet { 78 | serviceType = dao.ServiceTypeTransaction 79 | } 80 | 81 | res, err := b.dasCore.Client().GetTransaction(b.ctx, req.Tx.Inputs[0].PreviousOutput.TxHash) 82 | if err != nil { 83 | resp.Err = fmt.Errorf("GetTransaction err: %s", err.Error()) 84 | return 85 | } 86 | output := res.Transaction.Outputs[req.Tx.Inputs[0].PreviousOutput.Index] 87 | if !dasLock.IsSameTypeId(output.Lock.CodeHash) { 88 | log.Warn("ActionBalanceCell: das lock not match", req.TxHash) 89 | return 90 | } 91 | if output.Type != nil && !balanceType.IsSameTypeId(output.Type.CodeHash) { 92 | log.Warn("ActionBalanceCell: balance type not match", req.TxHash) 93 | return 94 | } 95 | 96 | oHex, _, err := b.dasCore.Daf().ArgsToHex(output.Lock.Args) 97 | if err != nil { 98 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 99 | return 100 | } 101 | tx := dao.TableTransactionInfo{ 102 | BlockNumber: req.BlockNumber, 103 | Action: req.Action, 104 | ServiceType: serviceType, 105 | ChainType: oHex.ChainType, 106 | Address: oHex.AddressHex, 107 | Capacity: req.Tx.Outputs[0].Capacity, 108 | Outpoint: common.OutPoint2String(req.TxHash, 0), 109 | BlockTimestamp: req.BlockTimestamp, 110 | } 111 | if err := b.dbDao.CreateTransactionInfo(tx); err != nil { 112 | log.Error("CreateTransactionInfo err:", err.Error(), toolib.JsonString(tx)) 113 | resp.Err = fmt.Errorf("WithdrawFromWallet err: %s", err.Error()) 114 | return 115 | } 116 | 117 | return 118 | } 119 | -------------------------------------------------------------------------------- /block_parser/action_config_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "fmt" 5 | "github.com/dotbitHQ/das-lib/common" 6 | "github.com/dotbitHQ/das-lib/core" 7 | ) 8 | 9 | func (b *BlockParser) ActionConfigCell(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 10 | configContract, err := core.GetDasContractInfo(common.DasContractNameConfigCellType) 11 | if err != nil { 12 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 13 | return 14 | } else if req.Tx.Outputs[0].Type == nil { 15 | return 16 | } else if configContract.ContractTypeId != req.Tx.Outputs[0].Type.CodeHash { 17 | log.Warn("not current version config cell") 18 | return 19 | } 20 | 21 | log.Info("ActionConfigCell:", req.TxHash) 22 | // config cell 更新,重新同步 config cell out point 23 | if err = b.dasCore.AsyncDasConfigCell(); err != nil { 24 | resp.Err = fmt.Errorf("AsyncDasConfigCell err: %s", err.Error()) 25 | return 26 | } 27 | return 28 | } 29 | -------------------------------------------------------------------------------- /block_parser/action_did_cell_v2.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "bytes" 5 | "das_database/dao" 6 | "fmt" 7 | "github.com/dotbitHQ/das-lib/common" 8 | "github.com/dotbitHQ/das-lib/witness" 9 | "strconv" 10 | ) 11 | 12 | func (b *BlockParser) DidCellActionUpdate(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 13 | log.Info("DidCellActionUpdate:", req.BlockNumber, req.TxHash, req.Action) 14 | 15 | if len(req.TxDidCellMap.Inputs) != len(req.TxDidCellMap.Outputs) { 16 | resp.Err = fmt.Errorf("len(req.TxDidCellMap.Inputs)!=len(req.TxDidCellMap.Outputs)") 17 | return 18 | } 19 | txDidEntityWitness, err := witness.GetDidEntityFromTx(req.Tx) 20 | if err != nil { 21 | resp.Err = fmt.Errorf("witness.GetDidEntityFromTx err: %s", err.Error()) 22 | return 23 | } 24 | 25 | var oldOutpointList []string 26 | var list []dao.TableDidCellInfo 27 | var accountIds []string 28 | var records []dao.TableRecordsInfo 29 | var txList []dao.TableTransactionInfo 30 | 31 | for k, v := range req.TxDidCellMap.Inputs { 32 | _, cellDataOld, err := v.GetDataInfo() 33 | if err != nil { 34 | resp.Err = fmt.Errorf("GetDataInfo old err: %s[%s]", err.Error(), k) 35 | return 36 | } 37 | n, ok := req.TxDidCellMap.Outputs[k] 38 | if !ok { 39 | resp.Err = fmt.Errorf("TxDidCellMap diff err: %s[%s]", err.Error(), k) 40 | return 41 | } 42 | _, cellDataNew, err := n.GetDataInfo() 43 | if err != nil { 44 | resp.Err = fmt.Errorf("GetDataInfo new err: %s[%s]", err.Error(), k) 45 | return 46 | } 47 | account := cellDataOld.Account 48 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(account)) 49 | 50 | oldOutpoint := common.OutPointStruct2String(v.OutPoint) 51 | oldOutpointList = append(oldOutpointList, oldOutpoint) 52 | 53 | tmp := dao.TableDidCellInfo{ 54 | BlockNumber: req.BlockNumber, 55 | Outpoint: common.OutPointStruct2String(n.OutPoint), 56 | AccountId: accountId, 57 | Account: account, 58 | Args: common.Bytes2Hex(n.Lock.Args), 59 | LockCodeHash: n.Lock.CodeHash.Hex(), 60 | ExpiredAt: cellDataNew.ExpireAt, 61 | } 62 | list = append(list, tmp) 63 | addrOld, err := v.GetLockAddress(b.dasCore.NetType()) 64 | if err != nil { 65 | resp.Err = fmt.Errorf("GetLockAddress err: %s", err.Error()) 66 | return 67 | } 68 | if !v.Lock.Equals(n.Lock) { 69 | txList = append(txList, dao.TableTransactionInfo{ 70 | BlockNumber: req.BlockNumber, 71 | AccountId: accountId, 72 | Account: account, 73 | Action: common.DidCellActionEditOwner, 74 | ServiceType: dao.ServiceTypeRegister, 75 | ChainType: common.ChainTypeAnyLock, 76 | Address: addrOld, 77 | Capacity: 0, 78 | Outpoint: common.OutPoint2String(req.TxHash, uint(v.Index)), 79 | BlockTimestamp: req.BlockTimestamp, 80 | }) 81 | } 82 | if cellDataOld.ExpireAt != cellDataNew.ExpireAt { 83 | txList = append(txList, dao.TableTransactionInfo{ 84 | BlockNumber: req.BlockNumber, 85 | AccountId: accountId, 86 | Account: account, 87 | Action: common.DidCellActionRenew, 88 | ServiceType: dao.ServiceTypeRegister, 89 | ChainType: common.ChainTypeAnyLock, 90 | Address: addrOld, 91 | Capacity: 0, 92 | Outpoint: common.OutPoint2String(req.TxHash, uint(v.Index)), 93 | BlockTimestamp: req.BlockTimestamp, 94 | }) 95 | } 96 | 97 | if bytes.Compare(cellDataOld.WitnessHash, cellDataNew.WitnessHash) != 0 { 98 | txList = append(txList, dao.TableTransactionInfo{ 99 | BlockNumber: req.BlockNumber, 100 | AccountId: accountId, 101 | Account: account, 102 | Action: common.DidCellActionEditRecords, 103 | ServiceType: dao.ServiceTypeRegister, 104 | ChainType: common.ChainTypeAnyLock, 105 | Address: addrOld, 106 | Capacity: 0, 107 | Outpoint: common.OutPoint2String(req.TxHash, uint(v.Index)), 108 | BlockTimestamp: req.BlockTimestamp, 109 | }) 110 | 111 | accountIds = append(accountIds, accountId) 112 | if w, yes := txDidEntityWitness.Outputs[n.Index]; yes { 113 | for _, r := range w.DidCellWitnessDataV0.Records { 114 | records = append(records, dao.TableRecordsInfo{ 115 | AccountId: accountId, 116 | ParentAccountId: "", 117 | Account: account, 118 | Key: r.Key, 119 | Type: r.Type, 120 | Label: r.Label, 121 | Value: r.Value, 122 | Ttl: strconv.FormatUint(uint64(r.TTL), 10), 123 | }) 124 | } 125 | } 126 | } 127 | } 128 | 129 | if err := b.dbDao.DidCellUpdateList(oldOutpointList, list, accountIds, records, txList); err != nil { 130 | resp.Err = fmt.Errorf("DidCellUpdateList err: %s", err.Error()) 131 | return 132 | } 133 | return 134 | } 135 | 136 | func (b *BlockParser) DidCellActionRecycle(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 137 | log.Info("DidCellActionRecycle:", req.BlockNumber, req.TxHash, req.Action) 138 | 139 | var oldOutpointList []string 140 | var accountIds []string 141 | var txList []dao.TableTransactionInfo 142 | for k, v := range req.TxDidCellMap.Inputs { 143 | oldOutpoint := common.OutPointStruct2String(v.OutPoint) 144 | oldOutpointList = append(oldOutpointList, oldOutpoint) 145 | 146 | _, cellData, err := v.GetDataInfo() 147 | if err != nil { 148 | resp.Err = fmt.Errorf("GetDataInfo err: %s[%s]", err.Error(), k) 149 | return 150 | } 151 | account := cellData.Account 152 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(account)) 153 | accountIds = append(accountIds, accountId) 154 | 155 | anyLockAddr, err := v.GetLockAddress(b.dasCore.NetType()) 156 | if err != nil { 157 | resp.Err = fmt.Errorf("GetLockAddress err: %s[%s]", err.Error(), k) 158 | return 159 | } 160 | 161 | txInfo := dao.TableTransactionInfo{ 162 | BlockNumber: req.BlockNumber, 163 | AccountId: accountId, 164 | Account: account, 165 | Action: common.DidCellActionRecycle, 166 | ServiceType: dao.ServiceTypeRegister, 167 | ChainType: common.ChainTypeAnyLock, 168 | Address: anyLockAddr, 169 | Capacity: 0, 170 | Outpoint: common.OutPoint2String(req.TxHash, uint(v.Index)), 171 | BlockTimestamp: req.BlockTimestamp, 172 | } 173 | txList = append(txList, txInfo) 174 | } 175 | 176 | if err := b.dbDao.DidCellRecycleList(oldOutpointList, accountIds, txList); err != nil { 177 | resp.Err = fmt.Errorf("DidCellRecycleList err: %s", err.Error()) 178 | return 179 | } 180 | return 181 | } 182 | -------------------------------------------------------------------------------- /block_parser/action_income_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | ) 9 | 10 | func (b *BlockParser) ActionCreateIncome(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 11 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNameIncomeCellType); err != nil { 12 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 13 | return 14 | } else if isCV { 15 | log.Warn("not current version create income tx") 16 | return 17 | } 18 | log.Info("ActionCreateIncome:", req.BlockNumber, req.TxHash) 19 | 20 | return 21 | } 22 | 23 | func (b *BlockParser) ActionConsolidateIncome(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 24 | incomeContract, err := core.GetDasContractInfo(common.DasContractNameIncomeCellType) 25 | if err != nil { 26 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 27 | return 28 | } 29 | dasContract, err := core.GetDasContractInfo(common.DasContractNameDispatchCellType) 30 | if err != nil { 31 | resp.Err = fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 32 | return 33 | } 34 | log.Info("ActionConsolidateIncome:", req.TxHash) 35 | 36 | var inputsOutpoints []string 37 | var incomeCellInfos []dao.TableIncomeCellInfo 38 | var transactionInfos []dao.TableTransactionInfo 39 | 40 | for _, v := range req.Tx.Inputs { 41 | inputsOutpoints = append(inputsOutpoints, common.OutPoint2String(v.PreviousOutput.TxHash.Hex(), v.PreviousOutput.Index)) 42 | } 43 | 44 | for i, v := range req.Tx.Outputs { 45 | if dasContract.IsSameTypeId(v.Lock.CodeHash) { 46 | ownerHex, _, err := b.dasCore.Daf().ArgsToHex(v.Lock.Args) 47 | if err != nil { 48 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 49 | return 50 | } 51 | transactionInfos = append(transactionInfos, dao.TableTransactionInfo{ 52 | BlockNumber: req.BlockNumber, 53 | Action: common.DasActionConsolidateIncome, 54 | ServiceType: dao.ServiceTypeTransaction, 55 | ChainType: ownerHex.ChainType, 56 | Address: ownerHex.AddressHex, 57 | Capacity: v.Capacity, 58 | Outpoint: common.OutPoint2String(req.TxHash, uint(i)), 59 | BlockTimestamp: req.BlockTimestamp, 60 | }) 61 | } else if v.Type != nil && incomeContract.IsSameTypeId(v.Type.CodeHash) { 62 | incomeCellInfos = append(incomeCellInfos, dao.TableIncomeCellInfo{ 63 | BlockNumber: req.BlockNumber, 64 | Action: common.DasActionConsolidateIncome, 65 | Outpoint: common.OutPoint2String(req.TxHash, uint(i)), 66 | Capacity: v.Capacity, 67 | BlockTimestamp: req.BlockTimestamp, 68 | Status: dao.IncomeCellStatusUnMerge, 69 | }) 70 | } 71 | } 72 | 73 | if err = b.dbDao.ConsolidateIncome(inputsOutpoints, incomeCellInfos, transactionInfos); err != nil { 74 | log.Error("ConsolidateIncome err: ", err.Error()) 75 | resp.Err = fmt.Errorf("ConsolidateIncome err: %s", err.Error()) 76 | return 77 | } 78 | 79 | return 80 | } 81 | -------------------------------------------------------------------------------- /block_parser/action_keylist_config_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "das_database/dao" 7 | "fmt" 8 | "github.com/dotbitHQ/das-lib/common" 9 | "github.com/dotbitHQ/das-lib/witness" 10 | "math/big" 11 | ) 12 | 13 | func (b *BlockParser) ActionCreateDeviceKeyList(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 14 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasKeyListCellType); err != nil { 15 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 16 | return 17 | } else if !isCV { 18 | log.Warn("not current version transfer account tx") 19 | return 20 | } 21 | log.Info("ActionCreateDeviceKeyList:", req.BlockNumber, req.TxHash) 22 | 23 | builder, err := witness.WebAuthnKeyListDataBuilderFromTx(req.Tx, common.DataTypeNew) 24 | //add cidpk 25 | var cidPk []dao.TableCidPk 26 | keyList := witness.ConvertToWebauthnKeyList(builder.DeviceKeyListCellData.Keys()) 27 | if len(keyList) == 0 { 28 | resp.Err = fmt.Errorf("ConvertToWebauthnKeyList err: %s", err.Error()) 29 | return 30 | } 31 | //var cidPk []dao.TableCidPk 32 | cidPk = append([]dao.TableCidPk{}, dao.TableCidPk{ 33 | Cid: keyList[0].Cid, 34 | Pk: keyList[0].PubKey, 35 | EnableAuthorize: dao.EnableAuthorizeOn, 36 | Outpoint: common.OutPoint2String(req.TxHash, uint(builder.Index)), 37 | }) 38 | if err := b.dbDao.InsertCidPk(cidPk); err != nil { 39 | resp.Err = fmt.Errorf("InsertCidPk err: %s", err.Error()) 40 | return 41 | } 42 | return 43 | } 44 | 45 | // add and delete deviceKey 46 | func (b *BlockParser) ActionUpdateDeviceKeyList(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 47 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasKeyListCellType); err != nil { 48 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 49 | return 50 | } else if !isCV { 51 | log.Warn("not current version transfer account tx") 52 | return 53 | } 54 | log.Info("ActionUpdateDeviceKeyList err:", req.BlockNumber, req.TxHash) 55 | 56 | builder, err := witness.WebAuthnKeyListDataBuilderFromTx(req.Tx, common.DataTypeNew) 57 | if err != nil { 58 | resp.Err = fmt.Errorf("WebAuthnKeyListDataBuilderFromTx err: %s", err.Error()) 59 | return 60 | } 61 | log.Info("args: ", common.Bytes2Hex(req.Tx.Outputs[0].Lock.Args)) 62 | ownerHex, _, err := b.dasCore.Daf().ArgsToHex(req.Tx.Outputs[0].Lock.Args) 63 | if err != nil { 64 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 65 | return 66 | } 67 | var masterCidPk1 dao.TableCidPk 68 | 69 | masterCidPk1.Cid = common.Bytes2Hex(ownerHex.AddressPayload[:10]) 70 | masterCidPk1.Pk = common.Bytes2Hex(ownerHex.AddressPayload[10:]) 71 | masterCidPk1.Outpoint = common.OutPoint2String(req.TxHash, 0) 72 | 73 | webauthnSignLv, err := witness.GetWebAuthnSignByWitnessArgs(req.Tx.Witnesses[0]) 74 | if err != nil { 75 | resp.Err = fmt.Errorf("GetWebAuthnSignLvByWitness0 err:%s", err.Error()) 76 | return 77 | } 78 | 79 | if webauthnSignLv.PkIndex == 255 { 80 | masterCidPk1.OriginPk = webauthnSignLv.PubKey 81 | } 82 | 83 | var pubKey ecdsa.PublicKey 84 | pubKey.Curve = elliptic.P256() 85 | pubKey.X = new(big.Int).SetBytes(common.Hex2Bytes(webauthnSignLv.PubKey)[:32]) 86 | pubKey.Y = new(big.Int).SetBytes(common.Hex2Bytes(webauthnSignLv.PubKey)[32:]) 87 | signAddrPk1 := common.CalculatePk1(&pubKey) 88 | keyList := witness.ConvertToWebauthnKeyList(builder.DeviceKeyListCellData.Keys()) 89 | 90 | //var authorize []dao.TableAuthorize 91 | //update master cid1, pk1, originPk 92 | //update slave cid1 pk1 93 | //a [a,b] => [a,b,c] 94 | var slaveCidPks []dao.TableCidPk 95 | var slaveCidPksSign dao.TableCidPk 96 | var authorize []dao.TableAuthorize 97 | for i := 0; i < len(keyList); i++ { 98 | var slaveCidPk dao.TableCidPk 99 | cid1 := keyList[i].Cid 100 | pk1 := keyList[i].PubKey 101 | //非master 102 | if cid1 != masterCidPk1.Cid { 103 | slaveCidPk.Cid = keyList[i].Cid 104 | slaveCidPk.Pk = keyList[i].PubKey 105 | if common.Bytes2Hex(signAddrPk1) == pk1 { 106 | slaveCidPk.OriginPk = webauthnSignLv.PubKey 107 | slaveCidPksSign = slaveCidPk 108 | } else { 109 | slaveCidPks = append(slaveCidPks, slaveCidPk) 110 | } 111 | 112 | } 113 | authorize = append(authorize, dao.TableAuthorize{ 114 | MasterAlgId: common.DasAlgorithmIdWebauthn, 115 | MasterSubAlgId: common.DasAlgorithmId(7), 116 | MasterCid: masterCidPk1.Cid, 117 | MasterPk: masterCidPk1.Pk, 118 | SlaveAlgId: common.DasAlgorithmId(keyList[i].MinAlgId), 119 | SlaveSubAlgId: common.DasAlgorithmId(keyList[i].SubAlgId), 120 | SlaveCid: keyList[i].Cid, 121 | SlavePk: keyList[i].PubKey, 122 | Outpoint: common.OutPoint2String(req.TxHash, 0), 123 | }) 124 | } 125 | if err = b.dbDao.UpdateAuthorizeByMaster(authorize, masterCidPk1, slaveCidPksSign, slaveCidPks); err != nil { 126 | resp.Err = fmt.Errorf("UpdateAuthorizeByMaster err: %s", err.Error()) 127 | return 128 | } 129 | return 130 | } 131 | -------------------------------------------------------------------------------- /block_parser/action_pre_register_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/molecule" 8 | "github.com/dotbitHQ/das-lib/witness" 9 | ) 10 | 11 | func (b *BlockParser) ActionPreRegister(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 12 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNamePreAccountCellType); err != nil { 13 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 14 | return 15 | } else if !isCV { 16 | log.Warn("not current version pre register tx") 17 | return 18 | } 19 | log.Info("ActionPreRegister:", req.BlockNumber, req.TxHash) 20 | 21 | preBuilder, err := witness.PreAccountCellDataBuilderFromTx(req.Tx, common.DataTypeNew) 22 | if err != nil { 23 | resp.Err = fmt.Errorf("PreAccountCellDataBuilderFromTx err: %s", err.Error()) 24 | return 25 | } 26 | log.Info("ActionPreRegister:", preBuilder.Account) 27 | 28 | refundLock := preBuilder.RefundLock 29 | if refundLock == nil { 30 | tmp := molecule.ScriptDefault() 31 | refundLock = &tmp 32 | } 33 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(preBuilder.Account)) 34 | var transactionInfo = dao.TableTransactionInfo{ 35 | BlockNumber: req.BlockNumber, 36 | AccountId: accountId, 37 | Account: preBuilder.Account, 38 | Action: common.DasActionPreRegister, 39 | ServiceType: dao.ServiceTypeRegister, 40 | ChainType: common.ChainTypeCkb, 41 | Address: common.Bytes2Hex(refundLock.Args().RawData()), // refund lock(register itself) 42 | Outpoint: common.OutPoint2String(req.TxHash, 0), 43 | Capacity: req.Tx.Outputs[0].Capacity, 44 | BlockTimestamp: req.BlockTimestamp, 45 | } 46 | if err := b.dbDao.CreateTransactionInfo(transactionInfo); err != nil { 47 | log.Error("CreateTransactionInfo err:", err.Error(), req.TxHash, req.BlockNumber) 48 | resp.Err = fmt.Errorf("CreateTransactionInfo err: %s", err.Error()) 49 | return 50 | } 51 | 52 | return 53 | } 54 | -------------------------------------------------------------------------------- /block_parser/action_reverse_record_cell.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | ) 8 | 9 | func (b *BlockParser) ActionDeclareReverseRecord(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 10 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNameReverseRecordCellType); err != nil { 11 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 12 | return 13 | } else if !isCV { 14 | log.Warn("not current version declare reverse record tx") 15 | return 16 | } 17 | log.Info("ActionDeclareReverseRecord:", req.BlockNumber, req.TxHash) 18 | 19 | account := string(req.Tx.OutputsData[0]) 20 | oHex, _, err := b.dasCore.Daf().ArgsToHex(req.Tx.Outputs[0].Lock.Args) 21 | if err != nil { 22 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 23 | return 24 | } 25 | 26 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(account)) 27 | reverseInfo := dao.TableReverseInfo{ 28 | BlockNumber: req.BlockNumber, 29 | BlockTimestamp: req.BlockTimestamp, 30 | Outpoint: common.OutPoint2String(req.TxHash, 0), 31 | AlgorithmId: oHex.DasAlgorithmId, 32 | ChainType: oHex.ChainType, 33 | Address: oHex.AddressHex, 34 | Account: account, 35 | AccountId: accountId, 36 | Capacity: req.Tx.Outputs[0].Capacity, 37 | } 38 | 39 | txInfo := dao.TableTransactionInfo{ 40 | BlockNumber: req.BlockNumber, 41 | AccountId: accountId, 42 | Account: account, 43 | Action: common.DasActionDeclareReverseRecord, 44 | ServiceType: dao.ServiceTypeRegister, 45 | ChainType: oHex.ChainType, 46 | Address: oHex.AddressHex, 47 | Capacity: req.Tx.Outputs[0].Capacity, 48 | Outpoint: common.OutPoint2String(req.TxHash, 0), 49 | BlockTimestamp: req.BlockTimestamp, 50 | } 51 | 52 | if err := b.dbDao.DeclareReverseRecord(reverseInfo, txInfo); err != nil { 53 | resp.Err = fmt.Errorf("DeclareReverseRecord err: %s", err.Error()) 54 | return 55 | } 56 | 57 | return 58 | } 59 | 60 | func (b *BlockParser) ActionRedeclareReverseRecord(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 61 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNameReverseRecordCellType); err != nil { 62 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err.Error()) 63 | return 64 | } else if !isCV { 65 | log.Warn("not current version redeclare reverse record tx") 66 | return 67 | } 68 | log.Info("ActionDeclareReverseRecord:", req.BlockNumber, req.TxHash) 69 | 70 | lastOutpoint := common.OutPointStruct2String(req.Tx.Inputs[0].PreviousOutput) 71 | account := string(req.Tx.OutputsData[0]) 72 | 73 | ownerHex, _, err := b.dasCore.Daf().ArgsToHex(req.Tx.Outputs[0].Lock.Args) 74 | if err != nil { 75 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 76 | return 77 | } 78 | 79 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(account)) 80 | reverseInfo := dao.TableReverseInfo{ 81 | BlockNumber: req.BlockNumber, 82 | BlockTimestamp: req.BlockTimestamp, 83 | Outpoint: common.OutPoint2String(req.TxHash, 0), 84 | AlgorithmId: ownerHex.DasAlgorithmId, 85 | ChainType: ownerHex.ChainType, 86 | Address: ownerHex.AddressHex, 87 | AccountId: accountId, 88 | Account: account, 89 | Capacity: req.Tx.Outputs[0].Capacity, 90 | } 91 | 92 | txInfo := dao.TableTransactionInfo{ 93 | BlockNumber: req.BlockNumber, 94 | AccountId: accountId, 95 | Account: account, 96 | Action: common.DasActionRedeclareReverseRecord, 97 | ServiceType: dao.ServiceTypeRegister, 98 | ChainType: ownerHex.ChainType, 99 | Address: ownerHex.AddressHex, 100 | Capacity: req.Tx.Outputs[0].Capacity, 101 | Outpoint: common.OutPoint2String(req.TxHash, 0), 102 | BlockTimestamp: req.BlockTimestamp, 103 | } 104 | 105 | if err := b.dbDao.RedeclareReverseRecord(lastOutpoint, reverseInfo, txInfo); err != nil { 106 | resp.Err = fmt.Errorf("RedeclareReverseRecord err: %s", err.Error()) 107 | return 108 | } 109 | 110 | return 111 | } 112 | 113 | func (b *BlockParser) ActionRetractReverseRecord(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 114 | res, err := b.dasCore.Client().GetTransaction(b.ctx, req.Tx.Inputs[0].PreviousOutput.TxHash) 115 | if err != nil { 116 | resp.Err = fmt.Errorf("GetTransaction err: %s", err.Error()) 117 | return 118 | } 119 | if isCV, err := isCurrentVersionTx(res.Transaction, common.DasContractNameReverseRecordCellType); err != nil { 120 | resp.Err = fmt.Errorf("isisCurrentVersionTx err: %s", err.Error()) 121 | return 122 | } else if !isCV { 123 | log.Warn("not current version retract reverse record tx") 124 | return 125 | } 126 | log.Info("ActionRetractReverseRecord:", req.BlockNumber, req.TxHash) 127 | 128 | var listOutpoint []string 129 | for _, v := range req.Tx.Inputs { 130 | listOutpoint = append(listOutpoint, common.OutPointStruct2String(v.PreviousOutput)) 131 | } 132 | 133 | ownerHex, _, err := b.dasCore.Daf().ArgsToHex(res.Transaction.Outputs[req.Tx.Inputs[0].PreviousOutput.Index].Lock.Args) 134 | if err != nil { 135 | resp.Err = fmt.Errorf("ArgsToHex err: %s", err.Error()) 136 | return 137 | } 138 | txInfo := dao.TableTransactionInfo{ 139 | BlockNumber: req.BlockNumber, 140 | AccountId: "", 141 | Account: "", 142 | Action: common.DasActionRetractReverseRecord, 143 | ServiceType: dao.ServiceTypeRegister, 144 | ChainType: ownerHex.ChainType, 145 | Address: ownerHex.AddressHex, 146 | Capacity: req.Tx.OutputsCapacity(), 147 | Outpoint: common.OutPoint2String(req.TxHash, 0), 148 | BlockTimestamp: req.BlockTimestamp, 149 | } 150 | 151 | if err := b.dbDao.RetractReverseRecord(listOutpoint, txInfo); err != nil { 152 | resp.Err = fmt.Errorf("RetractReverseRecord err: %s", err.Error()) 153 | return 154 | } 155 | 156 | return 157 | } 158 | -------------------------------------------------------------------------------- /block_parser/action_reverse_record_root.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/molecule" 8 | "github.com/dotbitHQ/das-lib/witness" 9 | "github.com/nervosnetwork/ckb-sdk-go/crypto/blake2b" 10 | "gorm.io/gorm" 11 | ) 12 | 13 | func (b *BlockParser) ActionReverseRecordRoot(req FuncTransactionHandleReq) (resp FuncTransactionHandleResp) { 14 | if isCV, err := isCurrentVersionTx(req.Tx, common.DasContractNameReverseRecordRootCellType); err != nil { 15 | resp.Err = fmt.Errorf("isCurrentVersion err: %s", err) 16 | return 17 | } else if !isCV { 18 | return 19 | } 20 | log.Info("ActionReverseRecordRoot:", req.BlockNumber, req.TxHash) 21 | 22 | txReverseSmtRecord := make([]*witness.ReverseSmtRecord, 0) 23 | if err := witness.ParseFromTx(req.Tx, common.ActionDataTypeReverseSmt, &txReverseSmtRecord); err != nil { 24 | resp.Err = err 25 | return 26 | } 27 | 28 | smtRecords := make([]*dao.ReverseSmtInfo, 0) 29 | for idx, v := range txReverseSmtRecord { 30 | nonce := molecule.GoU32ToMoleculeU32(v.PrevNonce + 1) 31 | valBs := make([]byte, 0) 32 | valBs = append(valBs, nonce.RawData()...) 33 | valBs = append(valBs, v.NextAccount...) 34 | 35 | smtValBlake256, err := blake2b.Blake256(valBs) 36 | if err != nil { 37 | resp.Err = err 38 | return 39 | } 40 | algorithmId := common.DasAlgorithmId(v.SignType) 41 | address := common.FormatAddressPayload(v.Address, algorithmId) 42 | 43 | outpoint := common.OutPoint2String(req.TxHash, uint(idx)) 44 | smtRecord := &dao.ReverseSmtInfo{ 45 | RootHash: common.Bytes2Hex(v.NextRoot), 46 | BlockNumber: req.BlockNumber, 47 | AlgorithmID: uint8(algorithmId), 48 | Outpoint: outpoint, 49 | Address: address, 50 | LeafDataHash: common.Bytes2Hex(smtValBlake256), 51 | } 52 | smtRecords = append(smtRecords, smtRecord) 53 | } 54 | 55 | if err := b.dbDao.Transaction(func(tx *gorm.DB) error { 56 | for _, v := range smtRecords { 57 | err := tx.Where("algorithm_id=? and address=?", v.AlgorithmID, v.Address).Delete(&dao.ReverseSmtInfo{}).Error 58 | if err != nil && err != gorm.ErrRecordNotFound { 59 | return err 60 | } 61 | if err := tx.Create(v).Error; err != nil { 62 | return err 63 | } 64 | } 65 | for idx, v := range txReverseSmtRecord { 66 | outpoint := common.OutPoint2String(req.TxHash, uint(idx)) 67 | accountId := common.Bytes2Hex(common.GetAccountIdByAccount(v.NextAccount)) 68 | algorithmId := common.DasAlgorithmId(v.SignType) 69 | address := common.FormatAddressPayload(v.Address, algorithmId) 70 | p2shP2wpkh, err := v.GetP2SHP2WPKH(b.dasCore.NetType()) 71 | if err != nil { 72 | log.Error("GetP2SHP2WPKH err: %s", err.Error()) 73 | } 74 | p2tr, err := v.GetP2TR(b.dasCore.NetType()) 75 | if err != nil { 76 | log.Error("GetP2TR err: %s", err.Error()) 77 | } 78 | reverseInfo := &dao.TableReverseInfo{ 79 | BlockNumber: req.BlockNumber, 80 | BlockTimestamp: req.BlockTimestamp, 81 | Outpoint: outpoint, 82 | AlgorithmId: algorithmId, 83 | ChainType: algorithmId.ToChainType(), 84 | Address: address, 85 | Account: v.NextAccount, 86 | AccountId: accountId, 87 | ReverseType: dao.ReverseTypeSmt, 88 | P2shP2wpkh: p2shP2wpkh, 89 | P2tr: p2tr, 90 | } 91 | switch v.Action { 92 | case witness.ReverseSmtRecordActionUpdate: 93 | if v.PrevAccount != "" { 94 | if err := tx.Where("address=? and reverse_type=?", address, dao.ReverseTypeSmt).Delete(&dao.TableReverseInfo{}).Error; err != nil { 95 | return err 96 | } 97 | } 98 | if err := tx.Create(reverseInfo).Error; err != nil { 99 | return err 100 | } 101 | case witness.ReverseSmtRecordActionRemove: 102 | if err := tx.Where("address=? and reverse_type=?", address, dao.ReverseTypeSmt).Delete(&dao.TableReverseInfo{}).Error; err != nil { 103 | return err 104 | } 105 | } 106 | } 107 | return nil 108 | }); err != nil { 109 | resp.Err = err 110 | return 111 | } 112 | return 113 | } 114 | -------------------------------------------------------------------------------- /block_parser/block_parser_handle.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/nervosnetwork/ckb-sdk-go/types" 9 | ) 10 | 11 | /* 12 | * das database parser map handle 13 | */ 14 | func (b *BlockParser) registerTransactionHandle() { 15 | b.mapTransactionHandle = make(map[string]FuncTransactionHandle) 16 | b.mapTransactionHandle[dao.DasActionTransferBalance] = b.ActionBalanceCells 17 | b.mapTransactionHandle[dao.DasActionOrderRefund] = b.ActionBalanceCells 18 | b.mapTransactionHandle[dao.DasActionBalanceDeposit] = b.ActionBalanceCells 19 | b.mapTransactionHandle[dao.DasActionCrossRefund] = b.ActionBalanceCells 20 | b.mapTransactionHandle[common.DasActionWithdrawFromWallet] = b.ActionBalanceCell 21 | b.mapTransactionHandle[common.DasActionTransfer] = b.ActionBalanceCell 22 | 23 | b.mapTransactionHandle[common.DasActionConfig] = b.ActionConfigCell 24 | b.mapTransactionHandle[common.DasActionCreateIncome] = b.ActionCreateIncome 25 | b.mapTransactionHandle[common.DasActionConsolidateIncome] = b.ActionConsolidateIncome 26 | 27 | b.mapTransactionHandle[common.DasActionApplyRegister] = b.ActionApplyRegister 28 | b.mapTransactionHandle[common.DasActionPreRegister] = b.ActionPreRegister 29 | b.mapTransactionHandle[common.DasActionPropose] = b.ActionPropose 30 | b.mapTransactionHandle[common.DasActionExtendPropose] = b.ActionPropose 31 | b.mapTransactionHandle[common.DasActionConfirmProposal] = b.ActionConfirmProposal 32 | 33 | b.mapTransactionHandle[common.DasActionEditRecords] = b.ActionEditRecords 34 | b.mapTransactionHandle[common.DasActionEditManager] = b.ActionEditManager 35 | b.mapTransactionHandle[common.DasActionRenewAccount] = b.ActionRenewAccount 36 | b.mapTransactionHandle[common.DasActionTransferAccount] = b.ActionTransferAccount 37 | b.mapTransactionHandle[common.DasActionForceRecoverAccountStatus] = b.ActionForceRecoverAccountStatus 38 | b.mapTransactionHandle[common.DasActionRecycleExpiredAccount] = b.ActionRecycleExpiredAccount 39 | b.mapTransactionHandle[common.DasActionLockAccountForCrossChain] = b.ActionAccountCrossChain 40 | b.mapTransactionHandle[common.DasActionUnlockAccountForCrossChain] = b.ActionAccountCrossChain 41 | 42 | b.mapTransactionHandle[common.DasActionStartAccountSale] = b.ActionStartAccountSale 43 | b.mapTransactionHandle[common.DasActionEditAccountSale] = b.ActionEditAccountSale 44 | b.mapTransactionHandle[common.DasActionCancelAccountSale] = b.ActionCancelAccountSale 45 | b.mapTransactionHandle[common.DasActionBuyAccount] = b.ActionBuyAccount 46 | 47 | b.mapTransactionHandle[common.DasActionMakeOffer] = b.ActionMakeOffer 48 | b.mapTransactionHandle[common.DasActionEditOffer] = b.ActionEditOffer 49 | b.mapTransactionHandle[common.DasActionCancelOffer] = b.ActionCancelOffer 50 | b.mapTransactionHandle[common.DasActionAcceptOffer] = b.ActionAcceptOffer 51 | 52 | b.mapTransactionHandle[common.DasActionDeclareReverseRecord] = b.ActionDeclareReverseRecord 53 | b.mapTransactionHandle[common.DasActionRedeclareReverseRecord] = b.ActionRedeclareReverseRecord 54 | b.mapTransactionHandle[common.DasActionRetractReverseRecord] = b.ActionRetractReverseRecord 55 | b.mapTransactionHandle[common.DasActionUpdateReverseRecordRoot] = b.ActionReverseRecordRoot 56 | 57 | b.mapTransactionHandle[common.DasActionEnableSubAccount] = b.ActionEnableSubAccount 58 | b.mapTransactionHandle[common.DasActionCreateSubAccount] = b.ActionCreateSubAccount 59 | b.mapTransactionHandle[common.DasActionEditSubAccount] = b.ActionEditSubAccount 60 | b.mapTransactionHandle[common.DasActionUpdateSubAccount] = b.ActionUpdateSubAccount 61 | //b.mapTransactionHandle[common.DasActionLockSubAccountForCrossChain] = b.ActionSubAccountCrossChain 62 | //b.mapTransactionHandle[common.DasActionUnlockSubAccountForCrossChain] = b.ActionSubAccountCrossChain 63 | b.mapTransactionHandle[common.DasActionConfigSubAccountCustomScript] = b.ActionConfigSubAccountCreatingScript 64 | b.mapTransactionHandle[common.DasActionCollectSubAccountProfit] = b.ActionCollectSubAccountProfit 65 | b.mapTransactionHandle[common.DasActionCollectSubAccountChannelProfit] = b.ActionCollectSubAccountChannelProfit2 66 | b.mapTransactionHandle[common.DasActionConfigSubAccount] = b.ActionConfigSubAccount 67 | //webauthn 68 | b.mapTransactionHandle[common.DasActionCreateKeyList] = b.ActionCreateDeviceKeyList 69 | b.mapTransactionHandle[common.DasActionUpdateKeyList] = b.ActionUpdateDeviceKeyList 70 | b.mapTransactionHandle[common.DasActionCreateApproval] = b.DasActionCreateApproval 71 | b.mapTransactionHandle[common.DasActionDelayApproval] = b.DasActionDelayApproval 72 | b.mapTransactionHandle[common.DasActionRevokeApproval] = b.DasActionRevokeApproval 73 | b.mapTransactionHandle[common.DasActionFulfillApproval] = b.DasActionFulfillApproval 74 | b.mapTransactionHandle[common.DasActionBidExpiredAccountAuction] = b.ActionBidExpiredAccountAuction 75 | 76 | //b.mapTransactionHandle[common.DasActionAccountCellUpgrade] = b.ActionAccountUpgrade // upgrade account cell 77 | //did cell 78 | b.mapTransactionHandle[common.DidCellActionUpdate] = b.DidCellActionUpdate 79 | b.mapTransactionHandle[common.DidCellActionRecycle] = b.DidCellActionRecycle 80 | 81 | //b.mapTransactionHandle[common.DidCellActionEditRecords] = b.ActionEditDidCellRecords // edit did cell record 82 | //b.mapTransactionHandle[common.DidCellActionEditOwner] = b.ActionEditDidCellOwner // edit did cell owner 83 | //b.mapTransactionHandle[common.DidCellActionRecycle] = b.ActionDidCellRecycle // did cell recycle 84 | } 85 | 86 | func isCurrentVersionTx(tx *types.Transaction, name common.DasContractName) (bool, error) { 87 | contract, err := core.GetDasContractInfo(name) 88 | if err != nil { 89 | return false, fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 90 | } 91 | isCV := false 92 | for _, v := range tx.Outputs { 93 | if v.Type == nil { 94 | continue 95 | } 96 | if contract.IsSameTypeId(v.Type.CodeHash) { 97 | isCV = true 98 | break 99 | } 100 | } 101 | return isCV, nil 102 | } 103 | 104 | func CurrentVersionTx(tx *types.Transaction, name common.DasContractName) (bool, int, error) { 105 | contract, err := core.GetDasContractInfo(name) 106 | if err != nil { 107 | return false, -1, fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 108 | } 109 | 110 | idx := -1 111 | isCV := false 112 | for i, v := range tx.Outputs { 113 | if v.Type == nil { 114 | continue 115 | } 116 | if contract.IsSameTypeId(v.Type.CodeHash) { 117 | isCV = true 118 | idx = i 119 | break 120 | } 121 | } 122 | return isCV, idx, nil 123 | } 124 | 125 | type FuncTransactionHandleReq struct { 126 | DbDao *dao.DbDao 127 | Tx *types.Transaction 128 | TxHash string 129 | BlockNumber uint64 130 | BlockTimestamp uint64 131 | Action common.DasAction 132 | TxDidCellMap core.TxDidCellMap 133 | } 134 | 135 | type FuncTransactionHandleResp struct { 136 | ActionName string 137 | Err error 138 | } 139 | 140 | type FuncTransactionHandle func(FuncTransactionHandleReq) FuncTransactionHandleResp 141 | -------------------------------------------------------------------------------- /block_parser/block_parser_test.go: -------------------------------------------------------------------------------- 1 | package block_parser 2 | 3 | import ( 4 | "context" 5 | "das_database/config" 6 | "fmt" 7 | "github.com/dotbitHQ/das-lib/common" 8 | "github.com/dotbitHQ/das-lib/core" 9 | "github.com/dotbitHQ/das-lib/witness" 10 | "github.com/nervosnetwork/ckb-sdk-go/rpc" 11 | "github.com/nervosnetwork/ckb-sdk-go/types" 12 | "strings" 13 | "sync" 14 | "sync/atomic" 15 | "testing" 16 | "time" 17 | ) 18 | 19 | func TestBlockNumber(t *testing.T) { 20 | blockNumber := uint64(0) 21 | fmt.Println(^uint64(0)) 22 | blockNumber2 := atomic.AddUint64(&blockNumber, 1) 23 | fmt.Println(blockNumber, blockNumber2) 24 | blockNumber2 = atomic.AddUint64(&blockNumber, ^uint64(0)) 25 | fmt.Println(blockNumber, blockNumber2) 26 | } 27 | 28 | func getCkbClient() (rpc.Client, error) { 29 | if err := config.InitCfg("../config/config.yaml"); err != nil { 30 | panic(fmt.Errorf("InitCfg err: %s", err)) 31 | } 32 | return rpc.DialWithIndexer(config.Cfg.Chain.CkbUrl, config.Cfg.Chain.IndexUrl) 33 | } 34 | 35 | func TestBuyAccount(t *testing.T) { 36 | c, err := getCkbClient() 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | res, err := c.GetTransaction(context.Background(), types.HexToHash("0xd1ec867a25b7982ac95e13d129ecd44b0a5ca5b459363c4909fbfa07d1ccf28b")) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | actionDataBuilder, err := witness.ActionDataBuilderFromTx(res.Transaction) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | fmt.Println(actionDataBuilder.Action) 49 | s, _ := actionDataBuilder.ActionBuyAccountInviterScript() 50 | fmt.Println(common.Bytes2Hex(s.Args().RawData())) 51 | IncomeCellBuilder, err := witness.IncomeCellDataBuilderFromTx(res.Transaction, common.DataTypeNew) 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | list := IncomeCellBuilder.Records() 56 | fmt.Println(list) 57 | } 58 | 59 | func TestAccount(t *testing.T) { 60 | acc := "tzh03.00acc2022042902.bit" 61 | fmt.Println(acc[strings.Index(acc, ".")+1:]) 62 | } 63 | 64 | func TestCheckContractVersion(t *testing.T) { 65 | dc, err := getNewDasCoreTestnet2() 66 | if err != nil { 67 | t.Fatal(err) 68 | } 69 | ctx, cancel := context.WithCancel(context.Background()) 70 | 71 | var wg sync.WaitGroup 72 | bp, err := NewBlockParser(ParamsBlockParser{ 73 | DasCore: dc, 74 | CurrentBlockNumber: config.Cfg.Chain.CurrentBlockNumber, 75 | DbDao: nil, 76 | ConcurrencyNum: config.Cfg.Chain.ConcurrencyNum, 77 | ConfirmNum: config.Cfg.Chain.ConfirmNum, 78 | Ctx: ctx, 79 | Cancel: cancel, 80 | Wg: &wg, 81 | }) 82 | if err != nil { 83 | t.Fatal(err) 84 | } 85 | 86 | wg.Add(2) 87 | go func() { 88 | ticker := time.NewTicker(time.Second * 2) 89 | for { 90 | select { 91 | case <-ticker.C: 92 | fmt.Println("checkContractVersion1") 93 | if err := config.CheckContractVersion(bp.dasCore, bp.cancel); err != nil { 94 | t.Log(err) 95 | } 96 | case <-ctx.Done(): 97 | fmt.Println(1111) 98 | wg.Done() 99 | return 100 | } 101 | } 102 | }() 103 | 104 | go func() { 105 | ticker := time.NewTicker(time.Second * 2) 106 | count := 0 107 | for { 108 | select { 109 | case <-ticker.C: 110 | if count == 3 { 111 | core.ContractStatusMapTestNet[common.DasContractNameAccountCellType] = common.ContractStatus{Version: "1.6.0"} 112 | } 113 | fmt.Println("count:", count) 114 | count++ 115 | case <-ctx.Done(): 116 | fmt.Println(22232) 117 | wg.Done() 118 | return 119 | } 120 | } 121 | }() 122 | fmt.Println(1111222) 123 | wg.Wait() 124 | fmt.Println(1111222) 125 | time.Sleep(time.Second * 5) 126 | } 127 | 128 | func getClientTestnet2() (rpc.Client, error) { 129 | ckbUrl := "https://testnet.ckb.dev/" 130 | indexerUrl := "https://testnet.ckb.dev/" 131 | return rpc.DialWithIndexer(ckbUrl, indexerUrl) 132 | } 133 | 134 | func getNewDasCoreTestnet2() (*core.DasCore, error) { 135 | client, err := getClientTestnet2() 136 | if err != nil { 137 | return nil, err 138 | } 139 | 140 | env := core.InitEnvOpt(common.DasNetTypeTestnet2, 141 | common.DasContractNameConfigCellType, 142 | //common.DasContractNameAccountCellType, 143 | //common.DasContractNameDispatchCellType, 144 | //common.DasContractNameBalanceCellType, 145 | common.DasContractNameAlwaysSuccess, 146 | common.DasContractNameIncomeCellType, 147 | //common.DASContractNameSubAccountCellType, 148 | //common.DasContractNamePreAccountCellType, 149 | ) 150 | var wg sync.WaitGroup 151 | ops := []core.DasCoreOption{ 152 | core.WithClient(client), 153 | core.WithDasContractArgs(env.ContractArgs), 154 | core.WithDasContractCodeHash(env.ContractCodeHash), 155 | core.WithDasNetType(common.DasNetTypeTestnet2), 156 | core.WithTHQCodeHash(env.THQCodeHash), 157 | } 158 | dc := core.NewDasCore(context.Background(), &wg, ops...) 159 | // contract 160 | dc.InitDasContract(env.MapContract) 161 | // config cell 162 | if err = dc.InitDasConfigCell(); err != nil { 163 | return nil, err 164 | } 165 | // so script 166 | if err = dc.InitDasSoScript(); err != nil { 167 | return nil, err 168 | } 169 | return dc, nil 170 | } 171 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "das_database/block_parser" 6 | "das_database/config" 7 | "das_database/dao" 8 | "das_database/http_server" 9 | "das_database/prometheus" 10 | "das_database/snapshot" 11 | "das_database/timer" 12 | "fmt" 13 | "github.com/dotbitHQ/das-lib/core" 14 | "github.com/dotbitHQ/das-lib/http_api" 15 | "github.com/dotbitHQ/das-lib/http_api/logger" 16 | "github.com/nervosnetwork/ckb-sdk-go/rpc" 17 | "github.com/scorpiotzh/toolib" 18 | "github.com/urfave/cli/v2" 19 | "os" 20 | "sync" 21 | "time" 22 | ) 23 | 24 | var ( 25 | log = logger.NewLogger("main", logger.LevelDebug) 26 | exit = make(chan struct{}) 27 | ctxServer, cancel = context.WithCancel(context.Background()) 28 | wgServer = sync.WaitGroup{} 29 | ) 30 | 31 | func main() { 32 | log.Debugf("server start:") 33 | app := &cli.App{ 34 | Flags: []cli.Flag{ 35 | &cli.StringFlag{ 36 | Name: "config", 37 | Aliases: []string{"c"}, 38 | Usage: "Load configuration from `FILE`", 39 | }, 40 | }, 41 | Action: runServer, 42 | } 43 | 44 | if err := app.Run(os.Args); err != nil { 45 | log.Fatal(err) 46 | } 47 | } 48 | 49 | func runServer(ctx *cli.Context) error { 50 | // config 51 | configFilePath := ctx.String("config") 52 | if err := config.InitCfg(configFilePath); err != nil { 53 | return err 54 | } 55 | 56 | // config update 57 | watcher, err := config.AddCfgFileWatcher(configFilePath) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | //sentry 63 | if err := http_api.SentryInit(config.Cfg.Notice.SentryDsn); err != nil { 64 | return fmt.Errorf("SentryInit err: %s", err.Error()) 65 | } 66 | defer http_api.RecoverPanic() 67 | 68 | // prometheus 69 | prometheus.Init() 70 | prometheus.Tools.Run() 71 | 72 | // db 73 | cfgMysql := config.Cfg.DB.Mysql 74 | db, err := http_api.NewGormDB(cfgMysql.Addr, cfgMysql.User, cfgMysql.Password, cfgMysql.DbName, cfgMysql.MaxOpenConn, cfgMysql.MaxIdleConn) 75 | if err != nil { 76 | return fmt.Errorf("NewGormDataBase err:%s", err.Error()) 77 | } 78 | dbDao, err := dao.Initialize(db) 79 | if err != nil { 80 | return fmt.Errorf("Initialize err:%s ", err.Error()) 81 | } 82 | log.Info("db ok") 83 | 84 | // ckb node 85 | ckbClient, err := rpc.DialWithIndexer(config.Cfg.Chain.CkbUrl, config.Cfg.Chain.IndexUrl) 86 | if err != nil { 87 | return fmt.Errorf("DialWithIndexer err: %s", err.Error()) 88 | } 89 | log.Info("ckb node ok") 90 | 91 | // das core 92 | env := core.InitEnv(config.Cfg.Server.Net) 93 | opts := []core.DasCoreOption{ 94 | core.WithClient(ckbClient), 95 | core.WithDasContractArgs(env.ContractArgs), 96 | core.WithDasContractCodeHash(env.ContractCodeHash), 97 | core.WithDasNetType(config.Cfg.Server.Net), 98 | core.WithTHQCodeHash(env.THQCodeHash), 99 | } 100 | dc := core.NewDasCore(ctxServer, &wgServer, opts...) 101 | dc.InitDasContract(env.MapContract) 102 | if err := dc.InitDasConfigCell(); err != nil { 103 | return fmt.Errorf("InitDasConfigCell err: %s", err.Error()) 104 | } 105 | if err := dc.InitDasSoScript(); err != nil { 106 | return fmt.Errorf("InitDasSoScript err: %s", err.Error()) 107 | } 108 | dc.RunAsyncDasContract(time.Minute * 5) // contract outpoint 109 | dc.RunAsyncDasConfigCell(time.Minute * 3) // config cell outpoint 110 | dc.RunAsyncDasSoScript(time.Minute * 7) // so 111 | log.Info("contract ok") 112 | 113 | // block parser 114 | bp, err := block_parser.NewBlockParser(block_parser.ParamsBlockParser{ 115 | DasCore: dc, 116 | CurrentBlockNumber: config.Cfg.Chain.CurrentBlockNumber, 117 | DbDao: dbDao, 118 | ConcurrencyNum: config.Cfg.Chain.ConcurrencyNum, 119 | ConfirmNum: config.Cfg.Chain.ConfirmNum, 120 | Ctx: ctxServer, 121 | Cancel: cancel, 122 | Wg: &wgServer, 123 | }) 124 | if err != nil { 125 | return fmt.Errorf("NewBlockParser err: %s", err.Error()) 126 | } 127 | 128 | bp.RunParser() 129 | 130 | // timer 131 | parserTimer := timer.ParserTimer{ 132 | DbDao: dbDao, 133 | Ctx: ctxServer, 134 | Wg: &wgServer, 135 | DasCore: dc, 136 | } 137 | parserTimer.RunUpdateTokenPrice() 138 | parserTimer.RunFixCharset() 139 | log.Info("parser timer ok") 140 | 141 | // snapshot 142 | toolSnapshot := snapshot.ToolSnapshot{ 143 | Ctx: ctxServer, 144 | Cancel: cancel, 145 | Wg: &wgServer, 146 | DbDao: dbDao, 147 | DasCore: dc, 148 | ConcurrencyNum: config.Cfg.Snapshot.ConcurrencyNum, 149 | ConfirmNum: config.Cfg.Snapshot.ConfirmNum, 150 | } 151 | if err := toolSnapshot.Run(config.Cfg.Snapshot.Open); err != nil { 152 | return fmt.Errorf("toolSnapshot.Run err: %s", err.Error()) 153 | } 154 | 155 | // cache 156 | red, err := toolib.NewRedisClient(config.Cfg.Cache.Redis.Addr, config.Cfg.Cache.Redis.Password, config.Cfg.Cache.Redis.DbNum) 157 | if err != nil { 158 | log.Error("NewRedisClient err:", err.Error()) 159 | } 160 | 161 | // http server 162 | hs, err := http_server.Initialize(http_server.HttpServerParams{ 163 | Address: config.Cfg.Server.HttpServerAddr, 164 | DbDao: dbDao, 165 | Ctx: ctxServer, 166 | DasCore: dc, 167 | Bp: bp, 168 | Red: red, 169 | }) 170 | if err != nil { 171 | return fmt.Errorf("http server Initialize err:%s", err.Error()) 172 | } 173 | hs.Run() 174 | 175 | // quit monitor 176 | toolib.ExitMonitoring(func(sig os.Signal) { 177 | log.Warn("ExitMonitoring:", sig.String()) 178 | if watcher != nil { 179 | log.Warn("close watcher ... ") 180 | _ = watcher.Close() 181 | } 182 | hs.Shutdown() 183 | cancel() 184 | wgServer.Wait() 185 | exit <- struct{}{} 186 | }) 187 | 188 | <-exit 189 | log.Warn("success exit server. bye bye!") 190 | return nil 191 | } 192 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | networks: 3 | dotbit: 4 | ipam: 5 | driver: default 6 | config: 7 | - subnet: 182.17.0.0/16 8 | gateway: 182.17.0.1 9 | 10 | services: 11 | das-database: 12 | image: admindid/das-database:latest 13 | restart: always 14 | working_dir: /app 15 | entrypoint: [ "/app/das-database", "--config", "/app/config/config.yaml" ] 16 | ports: 17 | - ${DAS_DATABASE_PORT:-8118}:8118 18 | volumes: 19 | - ./config/config.yaml:/app/config/config.yaml 20 | depends_on: 21 | - mysql 22 | networks: 23 | - dotbit 24 | extra_hosts: 25 | - host.docker.internal:host-gateway 26 | 27 | mysql: 28 | image: mysql/mysql-server:8.0 29 | restart: always 30 | ports: 31 | - ${MYSQL_PORT:-3306}:3306 32 | volumes: 33 | - ./mysql-data:/var/lib/mysql 34 | environment: 35 | MYSQL_ROOT_PASSWORD: ${DAS_DB_PORT:-123456} 36 | MYSQL_DATABASE: das_database 37 | TZ: Asia/Shanghai 38 | # This allows ip ranges from 182.17.0.1 to 182.17.255.255 to connect to root 39 | MYSQL_ROOT_HOST: "182.17.%.%" 40 | networks: 41 | - dotbit 42 | extra_hosts: 43 | - host.docker.internal:host-gateway 44 | -------------------------------------------------------------------------------- /config/config.example.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | name: "database" 3 | net: 2 4 | http_server_addr: ":8118" 5 | fix_charset: true 6 | prometheus_push_gateway: "" 7 | notice: 8 | webhook_lark_err: "" 9 | sentry_dsn: "" 10 | chain: 11 | ckb_url: "" #"https://testnet.ckb.dev/" 12 | index_url: "" #"https://testnet.ckb.dev/indexer" 13 | current_block_number: 1927285 # 4872287: mainnet 1927285: testnet 14 | confirm_num: 4 # confirm nums before written into DB 15 | concurrency_num: 200 16 | origins: 17 | - "localhost:3000" 18 | snapshot: 19 | open: true 20 | concurrency_num: 100 21 | confirm_num: 4 22 | snapshot_num: 500 23 | db: 24 | mysql: 25 | log_mode: true 26 | addr: "" 27 | user: "" 28 | password: "" 29 | db_name: "" 30 | max_open_conn: 100 31 | max_idle_conn: 50 32 | cache: 33 | redis: 34 | addr: "" 35 | password: "" 36 | db_num: 17 37 | gecko_ids: 38 | - "nervos-network" 39 | - "ethereum" 40 | - "bitcoin" 41 | - "tron" 42 | - "_wx_cny_" 43 | - "binancecoin" 44 | - "matic-network" -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "github.com/dotbitHQ/das-lib/common" 6 | "github.com/dotbitHQ/das-lib/http_api/logger" 7 | "github.com/fsnotify/fsnotify" 8 | "github.com/scorpiotzh/toolib" 9 | ) 10 | 11 | var ( 12 | Cfg CfgServer 13 | log = logger.NewLogger("config", logger.LevelDebug) 14 | ) 15 | 16 | func InitCfg(configFilePath string) error { 17 | if configFilePath == "" { 18 | configFilePath = "../config/config.yaml" 19 | } 20 | log.Info("read from config:", configFilePath) 21 | if err := toolib.UnmarshalYamlFile(configFilePath, &Cfg); err != nil { 22 | return fmt.Errorf("UnmarshalYamlFile err:%s", err.Error()) 23 | } 24 | log.Info("config file:", toolib.JsonString(Cfg)) 25 | return nil 26 | } 27 | 28 | func AddCfgFileWatcher(configFilePath string) (*fsnotify.Watcher, error) { 29 | if configFilePath == "" { 30 | configFilePath = "../config/config.yaml" 31 | } 32 | return toolib.AddFileWatcher(configFilePath, func() { 33 | log.Info("update config file:", configFilePath) 34 | if err := toolib.UnmarshalYamlFile(configFilePath, &Cfg); err != nil { 35 | log.Error("UnmarshalYamlFile err:", err.Error()) 36 | } 37 | log.Info("new config file:", toolib.JsonString(Cfg)) 38 | }) 39 | } 40 | 41 | type CfgServer struct { 42 | Server struct { 43 | Name string `json:"name" yaml:"name"` 44 | Net common.DasNetType `json:"net" yaml:"net"` 45 | HttpServerAddr string `json:"http_server_addr" yaml:"http_server_addr"` 46 | FixCharset bool `json:"fix_charset" yaml:"fix_charset"` 47 | NotExit bool `json:"not_exit" yaml:"not_exit"` 48 | PrometheusPushGateway string `json:"prometheus_push_gateway" yaml:"prometheus_push_gateway"` 49 | } `json:"server" yaml:"server"` 50 | Notice struct { 51 | WebhookLarkErr string `json:"webhook_lark_err" yaml:"webhook_lark_err"` 52 | SentryDsn string `json:"sentry_dsn" yaml:"sentry_dsn"` 53 | } `json:"notice" yaml:"notice"` 54 | Chain struct { 55 | CkbUrl string `json:"ckb_url" yaml:"ckb_url"` 56 | IndexUrl string `json:"index_url" yaml:"index_url"` 57 | CurrentBlockNumber uint64 `json:"current_block_number" yaml:"current_block_number"` 58 | ConfirmNum uint64 `json:"confirm_num" yaml:"confirm_num"` 59 | ConcurrencyNum uint64 `json:"concurrency_num" yaml:"concurrency_num"` 60 | } `json:"chain" yaml:"chain"` 61 | Origins []string `json:"origins"` 62 | Snapshot struct { 63 | Open bool `json:"open" yaml:"open"` 64 | ConcurrencyNum uint64 `json:"concurrency_num" yaml:"concurrency_num"` 65 | ConfirmNum uint64 `json:"confirm_num" yaml:"confirm_num"` 66 | SnapshotNum int `json:"snapshot_num" yaml:"snapshot_num"` 67 | } `json:"snapshot" yaml:"snapshot"` 68 | DB struct { 69 | Mysql DbMysql `json:"mysql" yaml:"mysql"` 70 | } `json:"db" yaml:"db"` 71 | Cache struct { 72 | Redis struct { 73 | Addr string `json:"addr" yaml:"addr"` 74 | Password string `json:"password" yaml:"password"` 75 | DbNum int `json:"db_num" yaml:"db_num"` 76 | } `json:"redis" yaml:"redis"` 77 | } `json:"cache" yaml:"cache"` 78 | } 79 | 80 | type DbMysql struct { 81 | Addr string `json:"addr" yaml:"addr"` 82 | User string `json:"user" yaml:"user"` 83 | Password string `json:"password" yaml:"password"` 84 | DbName string `json:"db_name" yaml:"db_name"` 85 | MaxOpenConn int `json:"max_open_conn" yaml:"max_open_conn"` 86 | MaxIdleConn int `json:"max_idle_conn" yaml:"max_idle_conn"` 87 | } 88 | 89 | func PriceToCKB(price, quote, years uint64) (total uint64) { 90 | log.Info("PriceToCKB:", price, quote, years) 91 | if quote == 0 { 92 | return 0 93 | } 94 | if price > quote { 95 | total = price / quote * common.OneCkb * years 96 | } else { 97 | total = price * common.OneCkb / quote * years 98 | } 99 | log.Info("PriceToCKB:", price, quote, total) 100 | return 101 | } 102 | -------------------------------------------------------------------------------- /config/contract.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | ) 9 | 10 | var contractNames = []common.DasContractName{ 11 | //common.DasContractNameApplyRegisterCellType, 12 | //common.DasContractNamePreAccountCellType, 13 | //common.DasContractNameProposalCellType, 14 | common.DasContractNameConfigCellType, 15 | common.DasContractNameAccountCellType, 16 | common.DasContractNameAccountSaleCellType, 17 | common.DASContractNameSubAccountCellType, 18 | common.DASContractNameOfferCellType, 19 | //common.DasContractNameBalanceCellType, 20 | //common.DasContractNameIncomeCellType, 21 | common.DasContractNameReverseRecordCellType, 22 | common.DASContractNameEip712LibCellType, 23 | common.DasContractNameReverseRecordRootCellType, 24 | } 25 | 26 | func CheckContractVersion(dasCore *core.DasCore, cancel context.CancelFunc) error { 27 | if dasCore == nil { 28 | return fmt.Errorf("dasCore is nil") 29 | } 30 | sysStatus, err := dasCore.ConfigCellDataBuilderByTypeArgs(common.ConfigCellTypeArgsSystemStatus) 31 | if err != nil { 32 | return fmt.Errorf("ConfigCellDataBuilderByTypeArgs err: %s", err.Error()) 33 | } 34 | for _, v := range contractNames { 35 | defaultVersion, chainVersion, err := dasCore.CheckContractVersionV2(sysStatus, v) 36 | log.Debug("CheckContractVersion:", defaultVersion, chainVersion, v) 37 | if err != nil { 38 | if err == core.ErrContractMajorVersionDiff { 39 | log.Errorf("contract[%s] version diff, chain[%s], service[%s].", v, chainVersion, defaultVersion) 40 | log.Error("Please update the service. [https://github.com/dotbitHQ/das-database]") 41 | if cancel != nil && !Cfg.Server.NotExit { 42 | cancel() 43 | } 44 | return err 45 | } 46 | return fmt.Errorf("CheckContractVersion err: %s", err.Error()) 47 | } 48 | } 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /dao/api.md: -------------------------------------------------------------------------------- 1 | # das_database server 2 | 3 | resp common: 4 | ```json 5 | { 6 | "err_no": 0, 7 | "err_msg": "", 8 | "data": {} 9 | } 10 | ``` 11 | 12 | ```go 13 | // error code 14 | const ( 15 | ApiCodeSuccess ApiCode = 0 16 | ApiCodeError500 ApiCode = 500 17 | ApiCodeParamsInvalid ApiCode = 10000 18 | ApiCodeMethodNotExist ApiCode = 10001 19 | ApiCodeDbError ApiCode = 10002 20 | ApiCodeCacheError ApiCode = 10003 21 | ApiCodeSystemUpgrade ApiCode = 30019 22 | ) 23 | ``` 24 | 25 | ## If The Latest Block Number 26 | 27 | * post: /isLatestBlockNumber 28 | * req 29 | 30 | ```json 31 | Nil 32 | ``` 33 | 34 | * resp 35 | ```json 36 | { 37 | "apiCode": 0, 38 | "apiMsg": "", 39 | "data": { 40 | "isLatestBlockNumber": true 41 | } 42 | } 43 | ``` 44 | 45 | ## Parse Transaction 46 | 47 | * post: /parserTransaction 48 | * req 49 | 50 | ```json 51 | { 52 | "txHash": "0xb940f751ac1d3293f6c47ce0a71e2712fd4931476bcff9339d16addda6dc99aa" 53 | } 54 | ``` 55 | 56 | * resp 57 | 58 | ```json 59 | { 60 | "apiCode": 0, 61 | "apiMsg": "" 62 | } 63 | ``` 64 | 65 | ## Api Test 66 | 67 | ```shell 68 | curl -X POST http://127.0.0.1:8118/v1/latest/block/number 69 | 70 | curl -X POST http://127.0.0.1:8118/v1/parser/transaction -d '{"txHash":"0x77a891bcec5b11d3fed14cfa5bd8cf5532f6d09cc6ecefa77d9e4bef296e8fd0"}' 71 | ``` 72 | -------------------------------------------------------------------------------- /dao/dao_approval_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "errors" 5 | "github.com/dotbitHQ/das-lib/common" 6 | "gorm.io/gorm" 7 | "time" 8 | ) 9 | 10 | type ApprovalStatus int 11 | 12 | const ( 13 | ApprovalStatusEnable ApprovalStatus = 1 14 | ApprovalStatusFulFill ApprovalStatus = 2 15 | ApprovalStatusRevoke ApprovalStatus = 3 16 | ) 17 | 18 | type ApprovalInfo struct { 19 | ID uint64 `gorm:"column:id;primary_key;AUTO_INCREMENT"` 20 | BlockNumber uint64 `gorm:"column:block_number;default:0;NOT NULL"` 21 | RefOutpoint string `gorm:"column:ref_outpoint;index:idx_ref_outpoint;NOT NULL"` // Hash-Index 22 | Outpoint string `gorm:"column:outpoint;index:idx_outpoint;NOT NULL"` // Hash-Index 23 | Account string `gorm:"column:account;NOT NULL"` 24 | AccountID string `gorm:"column:account_id;index:idx_account_id;NOT NULL"` 25 | ParentAccountID string `gorm:"column:parent_account_id;index:idx_parent_account_id;NOT NULL"` 26 | Platform string `gorm:"column:platform;NOT NULL"` // platform address 27 | OwnerAlgorithmID common.DasAlgorithmId `gorm:"column:owner_algorithm_id;default:0;NOT NULL"` 28 | Owner string `gorm:"column:owner;index:idx_owner;NOT NULL"` // owner address 29 | ToAlgorithmID common.DasAlgorithmId `gorm:"column:to_algorithm_id;default:0;NOT NULL"` 30 | To string `gorm:"column:to;index:idx_to;NOT NULL"` // to address 31 | ProtectedUntil uint64 `gorm:"column:protected_until;default:0;NOT NULL"` // 授权的不可撤销时间 32 | SealedUntil uint64 `gorm:"column:sealed_until;default:0;NOT NULL"` // 授权开放时间 33 | MaxDelayCount uint8 `gorm:"column:max_delay_count;default:0;NOT NULL"` // 可推迟次数 34 | PostponedCount int `gorm:"column:postponed_count;default:0;NOT NULL"` // 推迟过的次数 35 | Status ApprovalStatus `gorm:"column:status;default:0;NOT NULL"` // 0-default 1-开启授权 2:完成授权 3-撤销授权 36 | CreatedAt time.Time `gorm:"column:created_at;type:timestamp;default:CURRENT_TIMESTAMP;NOT NULL" json:"created_at"` 37 | UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;default:CURRENT_TIMESTAMP;NOT NULL" json:"updated_at"` 38 | } 39 | 40 | func (m *ApprovalInfo) TableName() string { 41 | return "t_approval_info" 42 | } 43 | 44 | func (d *DbDao) CreateAccountApproval(info ApprovalInfo) (err error) { 45 | err = d.db.Create(&info).Error 46 | return 47 | } 48 | 49 | func (d *DbDao) UpdateAccountApproval(id uint64, info map[string]interface{}) (err error) { 50 | err = d.db.Model(&ApprovalInfo{}).Where("id=?", id).Updates(info).Error 51 | if errors.Is(err, gorm.ErrRecordNotFound) { 52 | err = nil 53 | } 54 | return 55 | } 56 | 57 | func (d *DbDao) GetAccountPendingApproval(accountId string) (approval ApprovalInfo, err error) { 58 | err = d.db.Where("account_id=? and status=?", accountId, ApprovalStatusEnable).Order("id desc").First(&approval).Error 59 | if errors.Is(err, gorm.ErrRecordNotFound) { 60 | err = nil 61 | } 62 | return 63 | } 64 | 65 | func (d *DbDao) GetPendingApprovalByAccIdAndPlatform(accountId, platform string) (approval ApprovalInfo, err error) { 66 | err = d.db.Where("account_id=? and platform=? and status=?", accountId, platform, ApprovalStatusEnable).Order("id desc").First(&approval).Error 67 | if errors.Is(err, gorm.ErrRecordNotFound) { 68 | err = nil 69 | } 70 | return 71 | } 72 | -------------------------------------------------------------------------------- /dao/dao_authorize.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "gorm.io/gorm" 6 | "gorm.io/gorm/clause" 7 | "time" 8 | ) 9 | 10 | type TableAuthorize struct { 11 | Id uint64 `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"` 12 | MasterAlgId common.DasAlgorithmId `json:"master_alg_id" gorm:"column:master_alg_id; type:tinyint DEFAULT NULL"` 13 | MasterSubAlgId common.DasAlgorithmId `json:"master_sub_alg_id" gorm:"column:master_sub_alg_id; type:tinyint DEFAULT NULL"` 14 | MasterCid string `json:"master_cid" gorm:"column:master_cid; uniqueIndex:uk_mastercid_slavecid; type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL"` 15 | MasterPk string `json:"master_pk" gorm:"column:master_pk; type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL"` 16 | SlaveAlgId common.DasAlgorithmId `json:"slave_alg_id" gorm:"column:slave_alg_id; type:tinyint DEFAULT NULL"` 17 | SlaveSubAlgId common.DasAlgorithmId `json:"slave_sub_alg_id" gorm:"column:slave_sub_alg_id; type:tinyint DEFAULT NULL"` 18 | SlaveCid string `json:"slave_cid" gorm:"column:slave_cid; uniqueIndex:uk_mastercid_slavecid; type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL"` 19 | SlavePk string `json:"slave_pk" gorm:"column:slave_pk; type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL"` 20 | Outpoint string `json:"outpoint" gorm:"column:outpoint;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL"` 21 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''""` 22 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 23 | } 24 | 25 | const ( 26 | TableNameAuthorize = "t_authorize" 27 | ) 28 | 29 | func (t *TableAuthorize) TableName() string { 30 | return TableNameAuthorize 31 | } 32 | 33 | func (d *DbDao) UpdateAuthorizeByMaster(authorize []TableAuthorize, masterCidPks, slaveCidPksSign TableCidPk, slaveCidPks []TableCidPk) error { 34 | return d.db.Transaction(func(tx *gorm.DB) error { 35 | if err := tx.Where("master_cid = ? and master_pk = ? ", authorize[0].MasterCid, authorize[0].MasterPk).Delete(&TableAuthorize{}).Error; err != nil { 36 | return err 37 | } 38 | if err := tx.Create(&authorize).Error; err != nil { 39 | return err 40 | } 41 | var masterFields []string 42 | if masterCidPks.OriginPk != "" { 43 | masterFields = []string{"outpoint", "origin_pk"} 44 | } else { 45 | masterFields = []string{"outpoint"} 46 | } 47 | 48 | if err := tx.Clauses(clause.OnConflict{ 49 | DoUpdates: clause.AssignmentColumns(masterFields), 50 | }).Create(&masterCidPks).Error; err != nil { 51 | return err 52 | } 53 | 54 | if slaveCidPksSign.Pk != "" { 55 | if err := tx.Clauses(clause.OnConflict{ 56 | DoUpdates: clause.AssignmentColumns([]string{"origin_pk"}), 57 | }).Create(&slaveCidPksSign).Error; err != nil { 58 | return err 59 | } 60 | } 61 | 62 | if len(slaveCidPks) > 0 { 63 | if err := tx.Clauses(clause.OnConflict{ 64 | DoUpdates: clause.AssignmentColumns([]string{}), 65 | }).Create(&slaveCidPks).Error; err != nil { 66 | return err 67 | } 68 | } 69 | 70 | return nil 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /dao/dao_block_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "gorm.io/gorm/clause" 5 | "time" 6 | ) 7 | 8 | type TableBlockInfo struct { 9 | Id uint64 `json:"id" gorm:"column:id; primaryKey; type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '';"` 10 | ParserType ParserType `json:"parser_type" gorm:"column:parser_type; uniqueIndex:uk_pt_bn; type:smallint(6) NOT NULL DEFAULT '0' COMMENT '';"` 11 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number; uniqueIndex:uk_pt_bn; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 12 | BlockHash string `json:"block_hash" gorm:"column:block_hash; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 13 | ParentHash string `json:"parent_hash" gorm:"column:parent_hash; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 14 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at; type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '';"` 15 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at; type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '';"` 16 | } 17 | 18 | const ( 19 | TableNameBlockInfo = "t_block_info" 20 | ) 21 | 22 | func (t *TableBlockInfo) TableName() string { 23 | return TableNameBlockInfo 24 | } 25 | 26 | type ParserType int 27 | 28 | const ( 29 | ParserTypeDAS = 99 30 | ParserTypeSubAccount = 98 // das-sub-account 31 | ParserTypeSnapshot = 97 32 | 33 | ParserTypeCKB = 0 34 | ParserTypeETH = 1 35 | ParserTypeTRON = 3 36 | ParserTypeBSC = 5 37 | ParserTypePOLYGON = 6 38 | ) 39 | 40 | func (d *DbDao) CreateBlockInfo(parserType ParserType, blockNumber uint64, blockHash, parentHash string) error { 41 | return d.db.Clauses(clause.OnConflict{ 42 | DoUpdates: clause.AssignmentColumns([]string{"block_hash", "parent_hash"}), 43 | }).Create(&TableBlockInfo{ 44 | ParserType: parserType, 45 | BlockNumber: blockNumber, 46 | BlockHash: blockHash, 47 | ParentHash: parentHash, 48 | }).Error 49 | } 50 | 51 | func (d *DbDao) DeleteBlockInfo(parserType ParserType, blockNumber uint64) error { 52 | return d.db.Where("parser_type=? AND block_number 0 { 83 | if err := tx.Clauses(clause.OnConflict{ 84 | DoUpdates: clause.AssignmentColumns([]string{ 85 | "action", "capacity", "status", 86 | }), 87 | }).Create(&incomeCellInfos).Error; err != nil { 88 | return err 89 | } 90 | } 91 | 92 | if len(transactionInfos) > 0 { 93 | if err := tx.Clauses(clause.OnConflict{ 94 | DoUpdates: clause.AssignmentColumns([]string{ 95 | "account_id", "account", "service_type", 96 | "chain_type", "address", "capacity", "status", 97 | }), 98 | }).Create(&transactionInfos).Error; err != nil { 99 | return err 100 | } 101 | } 102 | 103 | return nil 104 | }) 105 | } 106 | 107 | func (d *DbDao) RenewAccount(outpoints []string, incomeCellInfos []TableIncomeCellInfo, accountInfo TableAccountInfo, transactionInfo TableTransactionInfo, oldDidCellOutpoints []string, didCellInfoList []TableDidCellInfo) error { 108 | return d.db.Transaction(func(tx *gorm.DB) error { 109 | if err := tx.Where("outpoint IN ?", outpoints).Delete(&TableIncomeCellInfo{}).Error; err != nil { 110 | return err 111 | } 112 | 113 | if len(incomeCellInfos) > 0 { 114 | if err := tx.Clauses(clause.OnConflict{ 115 | DoUpdates: clause.AssignmentColumns([]string{ 116 | "action", "capacity", "status", 117 | }), 118 | }).Create(&incomeCellInfos).Error; err != nil { 119 | return err 120 | } 121 | } 122 | 123 | if err := tx.Select("block_number", "outpoint", "expired_at"). 124 | Where("account_id = ?", accountInfo.AccountId). 125 | Updates(accountInfo).Error; err != nil { 126 | return err 127 | } 128 | 129 | if err := tx.Clauses(clause.OnConflict{ 130 | DoUpdates: clause.AssignmentColumns([]string{ 131 | "account_id", "account", "service_type", 132 | "chain_type", "address", "capacity", "status", 133 | }), 134 | }).Create(&transactionInfo).Error; err != nil { 135 | return err 136 | } 137 | 138 | if len(oldDidCellOutpoints) > 0 { 139 | if err := tx.Where("outpoint IN(?) ", oldDidCellOutpoints). 140 | Delete(&TableDidCellInfo{}).Error; err != nil { 141 | return err 142 | } 143 | } 144 | 145 | if len(didCellInfoList) > 0 { 146 | if err := tx.Clauses(clause.Insert{ 147 | Modifier: "IGNORE", 148 | }).Create(&didCellInfoList).Error; err != nil { 149 | return err 150 | } 151 | } 152 | return nil 153 | }) 154 | } 155 | -------------------------------------------------------------------------------- /dao/dao_rebate_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "time" 6 | ) 7 | 8 | type TableRebateInfo struct { 9 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 10 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 11 | Outpoint string `json:"outpoint" gorm:"column:outpoint;uniqueIndex:uk_o_rt;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 12 | InviteeId string `json:"invitee_id" gorm:"column:invitee_id;index:k_invitee_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'account id of invitee'"` 13 | InviteeAccount string `json:"invitee_account" gorm:"column:invitee_account;index:k_invitee_account;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 14 | InviteeChainType common.ChainType `json:"invitee_chain_type" gorm:"column:invitee_chain_type;index:k_ict_ia;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 15 | InviteeAddress string `json:"invitee_address" gorm:"column:invitee_address;index:k_ict_ia;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 16 | RewardType int `json:"reward_type" gorm:"column:reward_type;uniqueIndex:uk_o_rt;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '1: invite 2: channel'"` 17 | Reward uint64 `json:"reward" gorm:"column:reward;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'reward amount'"` 18 | Action string `json:"action" gorm:"column:action;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 19 | ServiceType int `json:"service_type" gorm:"column:service_type;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '1: register 2: trade'"` 20 | InviterArgs string `json:"inviter_args" gorm:"column:inviter_args;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 21 | InviterId string `json:"inviter_id" gorm:"column:inviter_id;index:k_inviter_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'account id of inviter'"` 22 | InviterAccount string `json:"inviter_account" gorm:"column:inviter_account;index:k_inviter_account;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'inviter account'"` 23 | InviterChainType common.ChainType `json:"inviter_chain_type" gorm:"column:inviter_chain_type;index:k_irct_ia;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 24 | InviterAddress string `json:"inviter_address" gorm:"column:inviter_address;index:k_irct_ia;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'address of inviter'"` 25 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 26 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 27 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 28 | } 29 | 30 | const ( 31 | TableNameRebateInfo = "t_rebate_info" 32 | RewardTypeInviter = 0 33 | RewardTypeChannel = 1 34 | ) 35 | 36 | func (t *TableRebateInfo) TableName() string { 37 | return TableNameRebateInfo 38 | } 39 | -------------------------------------------------------------------------------- /dao/dao_records_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | "gorm.io/gorm/clause" 6 | "time" 7 | ) 8 | 9 | type TableRecordsInfo struct { 10 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 11 | AccountId string `json:"account_id" gorm:"column:account_id;index:k_account_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'hash of account'"` 12 | ParentAccountId string `json:"parent_account_id" gorm:"column:parent_account_id;index:k_parent_account_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 13 | Account string `json:"account" gorm:"column:account;index:k_account;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 14 | Key string `json:"key" gorm:"column:key;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''"` 15 | Type string `json:"type" gorm:"column:type;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''"` 16 | Label string `json:"label" gorm:"column:label;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''"` 17 | Value string `json:"value" gorm:"column:value;index:k_value,length:768;type:varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''"` 18 | Ttl string `json:"ttl" gorm:"column:ttl;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ''"` 19 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 20 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 21 | } 22 | 23 | const ( 24 | TableNameRecordsInfo = "t_records_info" 25 | ) 26 | 27 | func (t *TableRecordsInfo) TableName() string { 28 | return TableNameRecordsInfo 29 | } 30 | 31 | func (d *DbDao) CreateRecordsInfos(accountInfo TableAccountInfo, recordsInfos []TableRecordsInfo, transactionInfo TableTransactionInfo) error { 32 | return d.db.Transaction(func(tx *gorm.DB) error { 33 | if err := tx.Select("block_number", "outpoint"). 34 | Where("account_id = ?", accountInfo.AccountId). 35 | Updates(accountInfo).Error; err != nil { 36 | return err 37 | } 38 | 39 | if err := tx.Where("account_id = ?", accountInfo.AccountId).Delete(&TableRecordsInfo{}).Error; err != nil { 40 | return err 41 | } 42 | 43 | if len(recordsInfos) > 0 { 44 | if err := tx.Create(&recordsInfos).Error; err != nil { 45 | return err 46 | } 47 | } 48 | 49 | if err := tx.Clauses(clause.OnConflict{ 50 | DoUpdates: clause.AssignmentColumns([]string{ 51 | "account_id", "account", "service_type", 52 | "chain_type", "address", "capacity", "status", 53 | }), 54 | }).Create(&transactionInfo).Error; err != nil { 55 | return err 56 | } 57 | 58 | return nil 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /dao/dao_reverse_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "gorm.io/gorm" 6 | "gorm.io/gorm/clause" 7 | "time" 8 | ) 9 | 10 | type TableReverseInfo struct { 11 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 12 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:BIGINT(20) NOT NULL DEFAULT '0' COMMENT ''"` 13 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:BIGINT(20) NOT NULL DEFAULT '0' COMMENT ''"` 14 | Outpoint string `json:"outpoint" gorm:"column:outpoint;uniqueIndex:uk_outpoint;type:VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 15 | AlgorithmId common.DasAlgorithmId `json:"algorithm_id" gorm:"column:algorithm_id;type:SMALLINT(6) NOT NULL DEFAULT '0' COMMENT ''"` 16 | ChainType common.ChainType `json:"chain_type" gorm:"column:chain_type;index:k_address;type:SMALLINT(6) NOT NULL DEFAULT '0' COMMENT ''"` 17 | Address string `json:"address" gorm:"column:address;index:k_address;type:VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 18 | AccountId string `json:"account_id" gorm:"account_id;index:k_account_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'hash of account'"` 19 | Account string `json:"account" gorm:"column:account;index:k_account;type:VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 20 | Capacity uint64 `json:"capacity" gorm:"column:capacity;type:BIGINT(20) NOT NULL DEFAULT '0' COMMENT ''"` 21 | ReverseType uint32 `json:"reverse_type" gorm:"column:reverse_type;type:tinyint(1) NOT NULL DEFAULT '0' COMMENT '0: old reverse type,1:new outpoint struct'"` 22 | P2shP2wpkh string `json:"p2sh_p2wpkh" gorm:"column:p2sh_p2wpkh; index:k_p2sh_p2wpkh; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 23 | P2tr string `json:"p2tr" gorm:"column:p2tr; index:k_p2tr; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 24 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 25 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 26 | } 27 | 28 | const ( 29 | TableNameReverseInfo = "t_reverse_info" 30 | 31 | ReverseTypeOld = 0 32 | ReverseTypeSmt = 1 33 | ) 34 | 35 | func (t *TableReverseInfo) TableName() string { 36 | return TableNameReverseInfo 37 | } 38 | 39 | func (d *DbDao) DeclareReverseRecord(reverseInfo TableReverseInfo, txInfo TableTransactionInfo) error { 40 | return d.db.Transaction(func(tx *gorm.DB) error { 41 | 42 | if err := tx.Clauses(clause.OnConflict{ 43 | DoUpdates: clause.AssignmentColumns([]string{ 44 | "algorithm_id", "chain_type", "address", "account_id", "account", "capacity", 45 | }), 46 | }).Create(&reverseInfo).Error; err != nil { 47 | return err 48 | } 49 | 50 | if err := tx.Clauses(clause.OnConflict{ 51 | DoUpdates: clause.AssignmentColumns([]string{ 52 | "account_id", "account", "service_type", 53 | "chain_type", "address", "capacity", "status", 54 | }), 55 | }).Create(&txInfo).Error; err != nil { 56 | return err 57 | } 58 | 59 | return nil 60 | }) 61 | } 62 | 63 | func (d *DbDao) RedeclareReverseRecord(lastOutpoint string, reverseInfo TableReverseInfo, txInfo TableTransactionInfo) error { 64 | return d.db.Transaction(func(tx *gorm.DB) error { 65 | 66 | if err := tx.Where(" outpoint=? ", lastOutpoint).Delete(TableReverseInfo{}).Error; err != nil { 67 | return err 68 | } 69 | 70 | if err := tx.Clauses(clause.OnConflict{ 71 | DoUpdates: clause.AssignmentColumns([]string{ 72 | "algorithm_id", "chain_type", "address", "account_id", "account", "capacity", 73 | }), 74 | }).Create(&reverseInfo).Error; err != nil { 75 | return err 76 | } 77 | 78 | if err := tx.Clauses(clause.OnConflict{ 79 | DoUpdates: clause.AssignmentColumns([]string{ 80 | "account_id", "account", "service_type", 81 | "chain_type", "address", "capacity", "status", 82 | }), 83 | }).Create(&txInfo).Error; err != nil { 84 | return err 85 | } 86 | 87 | return nil 88 | }) 89 | } 90 | 91 | func (d *DbDao) RetractReverseRecord(listOutpoint []string, txInfo TableTransactionInfo) error { 92 | return d.db.Transaction(func(tx *gorm.DB) error { 93 | 94 | if err := tx.Where(" outpoint IN(?) ", listOutpoint).Delete(TableReverseInfo{}).Error; err != nil { 95 | return err 96 | } 97 | 98 | if err := tx.Clauses(clause.OnConflict{ 99 | DoUpdates: clause.AssignmentColumns([]string{ 100 | "account_id", "account", "service_type", 101 | "chain_type", "address", "capacity", "status", 102 | }), 103 | }).Create(&txInfo).Error; err != nil { 104 | return err 105 | } 106 | 107 | return nil 108 | }) 109 | } 110 | -------------------------------------------------------------------------------- /dao/dao_reverse_smt_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // ReverseSmtInfo current reverse info 8 | type ReverseSmtInfo struct { 9 | ID uint64 `gorm:"column:id;primary_key;AUTO_INCREMENT"` 10 | RootHash string `gorm:"column:root_hash;NOT NULL"` // SMT根节点hash 11 | BlockNumber uint64 `gorm:"column:block_number;default:0;NOT NULL;index:idx_address_blk_outpoint,priority:2"` 12 | AlgorithmID uint8 `gorm:"column:algorithm_id;type:smallint(6) NOT NULL DEFAULT '0'"` 13 | Outpoint string `gorm:"column:outpoint;NOT NULL;index:idx_address_blk_outpoint,priority:3"` // 设置反解的地址 14 | Address string `gorm:"column:address;NOT NULL;index:idx_address_blk_outpoint,priority:1"` 15 | LeafDataHash string `gorm:"column:leaf_data_hash;NOT NULL"` // SMT叶子节点hash 16 | CreatedAt time.Time `gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 17 | UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 18 | } 19 | 20 | const TableNameReverseSmtInfo = "t_reverse_smt_info" 21 | 22 | func (m *ReverseSmtInfo) TableName() string { 23 | return TableNameReverseSmtInfo 24 | } 25 | -------------------------------------------------------------------------------- /dao/dao_rule_config.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type RuleConfig struct { 8 | Id int64 `gorm:"column:id;AUTO_INCREMENT" json:"id"` 9 | Account string `gorm:"column:account;type:varchar(255);comment:账号;NOT NULL" json:"account"` 10 | AccountId string `gorm:"uniqueIndex:idx_acc_id,column:account_id;type:varchar(255);comment:账号id;NOT NULL" json:"account_id"` 11 | TxHash string `gorm:"index:idx_tx_hash,column:tx_hash;type:varchar(255);comment:交易hash;NOT NULL" json:"tx_hash"` 12 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 13 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 14 | CreatedAt time.Time `gorm:"column:created_at;type:timestamp;default:CURRENT_TIMESTAMP;NOT NULL" json:"created_at"` 15 | UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;default:CURRENT_TIMESTAMP;NOT NULL" json:"updated_at"` 16 | } 17 | 18 | func (m *RuleConfig) TableName() string { 19 | return "t_rule_config" 20 | } 21 | -------------------------------------------------------------------------------- /dao/dao_snapshot_register_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "gorm.io/gorm/clause" 6 | "time" 7 | ) 8 | 9 | type TableSnapshotRegisterInfo struct { 10 | Id uint64 `json:"id" gorm:"column:id; primaryKey; type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '';"` 11 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number; index:k_block_number; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 12 | AccountId string `json:"account_id" gorm:"column:account_id; uniqueIndex:uk_account_id; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 13 | ParentAccountId string `json:"parent_account_id" gorm:"column:parent_account_id; index:k_parent_account_id; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 14 | Hash string `json:"hash" gorm:"column:hash; uniqueIndex:uk_account_id; index:k_hash; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 15 | Account string `json:"account" gorm:"column:account; type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '';"` 16 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 17 | Owner string `json:"owner" gorm:"column:owner; index:k_owner; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 18 | OwnerAlgorithmId common.DasAlgorithmId `json:"owner_algorithm_id" gorm:"column:owner_algorithm_id; type:SMALLINT(6) NOT NULL DEFAULT '0' COMMENT '';"` 19 | RegisteredAt uint64 `json:"registered_at" gorm:"column:registered_at; index:k_registered_at; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 20 | ExpiredAt uint64 `json:"expired_at" gorm:"column:expired_at; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 21 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 22 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 23 | } 24 | 25 | const ( 26 | TableNameSnapshotRegisterInfo = "t_snapshot_register_info" 27 | ) 28 | 29 | func (t *TableSnapshotRegisterInfo) TableName() string { 30 | return TableNameSnapshotRegisterInfo 31 | } 32 | 33 | func (d *DbDao) CreateSnapshotRegister(list []TableSnapshotRegisterInfo) error { 34 | if len(list) == 0 { 35 | return nil 36 | } 37 | return d.db.Clauses(clause.Insert{ 38 | Modifier: "IGNORE", 39 | }).Create(&list).Error 40 | } 41 | 42 | func (d *DbDao) GetRegisterHistory(limit, offset int) (list []TableSnapshotRegisterInfo, err error) { 43 | err = d.db.Select("account,owner,registered_at").Where("parent_account_id=''"). 44 | Order("block_number"). 45 | Limit(limit).Offset(offset).Find(&list).Error 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /dao/dao_snapshot_tx_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "gorm.io/gorm/clause" 5 | "time" 6 | ) 7 | 8 | type TableSnapshotTxInfo struct { 9 | Id uint64 `json:"id" gorm:"column:id; primaryKey; type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '';"` 10 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number; index:k_block_number; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 11 | Hash string `json:"hash" gorm:"column:hash; uniqueIndex:uk_hash; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 12 | Action string `json:"action" gorm:"column:action; index:k_action; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 13 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 14 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 15 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 16 | } 17 | 18 | const ( 19 | TableNameSnapshotTxInfo = "t_snapshot_tx_info" 20 | TxSnapshotSchedule = "TxSnapshotSchedule" 21 | ) 22 | 23 | func (t *TableSnapshotTxInfo) TableName() string { 24 | return TableNameSnapshotTxInfo 25 | } 26 | 27 | func (d *DbDao) CreateSnapshotTxInfo(info TableSnapshotTxInfo) error { 28 | if err := d.db.Clauses(clause.Insert{ 29 | Modifier: "IGNORE", 30 | }).Create(&info).Error; err != nil { 31 | return err 32 | } 33 | return nil 34 | } 35 | 36 | func (d *DbDao) InitSnapshotSchedule() error { 37 | info := TableSnapshotTxInfo{ 38 | BlockNumber: 0, 39 | Hash: TxSnapshotSchedule, 40 | Action: TxSnapshotSchedule, 41 | BlockTimestamp: 0, 42 | } 43 | return d.db.Clauses(clause.Insert{ 44 | Modifier: "IGNORE", 45 | }).Create(&info).Error 46 | } 47 | 48 | func (d *DbDao) GetTxSnapshotSchedule() (info TableSnapshotTxInfo, err error) { 49 | err = d.db.Where("hash=? AND action=?", TxSnapshotSchedule, TxSnapshotSchedule).Find(&info).Error 50 | return 51 | } 52 | 53 | func (d *DbDao) GetTxSnapshotByBlockNumber(blockNumber uint64, limit int) (list []TableSnapshotTxInfo, err error) { 54 | if limit <= 0 || limit > 5000 { 55 | limit = 500 56 | } 57 | err = d.db.Where("block_number>=? AND action!=?", blockNumber, TxSnapshotSchedule). 58 | Order("block_number,id").Limit(limit).Find(&list).Error 59 | return 60 | } 61 | 62 | func (d *DbDao) UpdateTxSnapshotSchedule(blockNumber uint64) error { 63 | return d.db.Model(TableSnapshotTxInfo{}). 64 | Where("hash=? AND action=?", TxSnapshotSchedule, TxSnapshotSchedule). 65 | Updates(map[string]interface{}{ 66 | "block_number": blockNumber, 67 | }).Error 68 | } 69 | -------------------------------------------------------------------------------- /dao/dao_subaccount_auto_mint_statement.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "github.com/shopspring/decimal" 6 | "time" 7 | ) 8 | 9 | type SubAccountAutoMintTxType int 10 | 11 | const ( 12 | SubAccountAutoMintTxTypeIncome SubAccountAutoMintTxType = 1 13 | SubAccountAutoMintTxTypeExpenditure SubAccountAutoMintTxType = 2 14 | ) 15 | 16 | type TableSubAccountAutoMintStatement struct { 17 | Id uint64 `json:"id" gorm:"column:id; primaryKey; type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '';"` 18 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number; index:k_block_number; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 19 | TxHash string `json:"tx_hash" gorm:"column:tx_hash; uniqueIndex:uk_tx_wi; index:idx_hash; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 20 | WitnessIndex int `json:"witness_index" gorm:"column:witness_index; uniqueIndex:uk_tx_wi; type:int(11) NOT NULL DEFAULT '0' COMMENT '';"` 21 | ParentAccountId string `json:"parent_account_id" gorm:"column:parent_account_id; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 22 | ServiceProviderId string `json:"service_provider_id" gorm:"column:service_provider_id; index:idx_service_provider_id; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 23 | Price decimal.Decimal `json:"price" gorm:"column:price; type:decimal(60,2) NOT NULL DEFAULT '0' COMMENT '';"` 24 | Quote decimal.Decimal `json:"quote" gorm:"column:quote; type:decimal(50,10) NOT NULL DEFAULT '0' COMMENT '';"` 25 | Years uint64 `json:"years" gorm:"column:years; type:int(11) NOT NULL DEFAULT '0' COMMENT'';"` 26 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp; type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '';"` 27 | TxType SubAccountAutoMintTxType `json:"tx_type" gorm:"column:tx_type; type:int(11) NOT NULL DEFAULT '0' COMMENT '1: income, 2: expenditure';"` 28 | SubAction common.SubAction `json:"sub_action" gorm:"column:sub_action; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 29 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 30 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 31 | } 32 | 33 | func (t *TableSubAccountAutoMintStatement) TableName() string { 34 | return "t_sub_account_auto_mint_statement" 35 | } 36 | -------------------------------------------------------------------------------- /dao/dao_test.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "das_database/config" 5 | "fmt" 6 | "github.com/shopspring/decimal" 7 | "testing" 8 | ) 9 | 10 | func getInit() (*DbDao, error) { 11 | if err := config.InitCfg("../config/config.yaml"); err != nil { 12 | return nil, fmt.Errorf("InitCfg err: %s", err) 13 | } 14 | cfgMysql := config.Cfg.DB.Mysql 15 | db, err := NewGormDataBase(cfgMysql.Addr, cfgMysql.User, cfgMysql.Password, cfgMysql.DbName, cfgMysql.MaxOpenConn, cfgMysql.MaxIdleConn) 16 | if err != nil { 17 | return nil, fmt.Errorf("NewGormDataBase err:%s", err.Error()) 18 | } 19 | dbDao, err := Initialize(db) 20 | if err != nil { 21 | return nil, fmt.Errorf("Initialize err:%s ", err.Error()) 22 | } 23 | return dbDao, nil 24 | } 25 | 26 | func TestInsertOrUpdate(t *testing.T) { 27 | dbDao, err := getInit() 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | incomeCellInfo := TableIncomeCellInfo{ 32 | BlockNumber: 5718189, 33 | Action: "create_income", 34 | Outpoint: "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2", 35 | Capacity: 40000000000, 36 | BlockTimestamp: 1635320117861, 37 | Status: 0, 38 | } 39 | err = dbDao.CreateIncomeCellInfo(incomeCellInfo) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | t.Log(incomeCellInfo) 44 | } 45 | 46 | func TestInsertListOrUpdate(t *testing.T) { 47 | dbDao, err := getInit() 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | incomeCellInfos := []TableIncomeCellInfo{ 52 | { 53 | BlockNumber: 57181892, 54 | Action: "create_income", 55 | Outpoint: "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2", 56 | Capacity: 400000000002, 57 | BlockTimestamp: 16353201178612, 58 | Status: 0, 59 | }, 60 | { 61 | BlockNumber: 5718189, 62 | Action: "create_income", 63 | Outpoint: "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_3", 64 | Capacity: 40000000000, 65 | BlockTimestamp: 1635320117861, 66 | Status: 0, 67 | }, 68 | } 69 | err = dbDao.CreateIncomeCellInfoList(incomeCellInfos) 70 | if err != nil { 71 | t.Fatal(err) 72 | } 73 | t.Log(incomeCellInfos) 74 | } 75 | 76 | func TestDelete(t *testing.T) { 77 | dbDao, err := getInit() 78 | if err != nil { 79 | t.Fatal(err) 80 | } 81 | err = dbDao.DeleteIncomeCellInfo() 82 | if err != nil { 83 | t.Fatal(err) 84 | } 85 | // gorm.ErrMissingWhereClause 86 | } 87 | 88 | func TestDeleteWhere(t *testing.T) { 89 | dbDao, err := getInit() 90 | if err != nil { 91 | t.Fatal(err) 92 | } 93 | err = dbDao.DeleteIncomeCellInfoByOutpoint("0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2") 94 | if err != nil { 95 | t.Fatal(err) 96 | } 97 | } 98 | 99 | func TestSave(t *testing.T) { 100 | dbDao, err := getInit() 101 | if err != nil { 102 | t.Fatal(err) 103 | } 104 | incomeCellInfo := TableIncomeCellInfo{ 105 | BlockNumber: 57181892, 106 | Action: "create_income", 107 | Outpoint: "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2", 108 | Capacity: 400000000002, 109 | BlockTimestamp: 16353201178612, 110 | Status: 0, 111 | } 112 | err = dbDao.SaveIncomeCellInfo(incomeCellInfo) 113 | if err != nil { 114 | t.Fatal(err) 115 | } 116 | } 117 | 118 | func TestUpdateWhere(t *testing.T) { 119 | dbDao, err := getInit() 120 | if err != nil { 121 | t.Fatal(err) 122 | } 123 | err = dbDao.UpdateIncomeCellInfoMerged([]string{"0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2", "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_3"}) 124 | if err != nil { 125 | t.Fatal(err) 126 | } 127 | } 128 | 129 | func TestUpdatesWhere(t *testing.T) { 130 | dbDao, err := getInit() 131 | if err != nil { 132 | t.Fatal(err) 133 | } 134 | incomeCellInfo := TableIncomeCellInfo{ 135 | BlockNumber: 5718189, 136 | Action: "create_income", 137 | Outpoint: "0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2", 138 | Capacity: 40000000000, 139 | BlockTimestamp: 1635320117861, 140 | Status: 0, 141 | } 142 | err = dbDao.UpdatesIncomeCellInfo(incomeCellInfo) 143 | if err != nil { 144 | t.Fatal(err) 145 | } 146 | } 147 | 148 | func TestFirstWhere(t *testing.T) { 149 | dbDao, err := getInit() 150 | if err != nil { 151 | t.Fatal(err) 152 | } 153 | incomeCellInfo, err := dbDao.FirstIncomeCellInfoByOutpoint("0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2") 154 | if err != nil { 155 | t.Fatal(err) 156 | } 157 | t.Log(incomeCellInfo) 158 | } 159 | 160 | func TestFindWhere(t *testing.T) { 161 | dbDao, err := getInit() 162 | if err != nil { 163 | t.Fatal(err) 164 | } 165 | incomeCellInfo, err := dbDao.FindIncomeCellInfoListByOutpoint("0xe9116d651c371662b6e29e2102422e23f90656b8619df82c48b782ff4db43a37_2") 166 | if err != nil { 167 | t.Fatal(err) 168 | } 169 | t.Log(incomeCellInfo) 170 | } 171 | 172 | func TestTransaction(t *testing.T) { 173 | dbDao, err := getInit() 174 | if err != nil { 175 | t.Fatal(err) 176 | } 177 | outpoints := []string{"0x5687b6b801d9214f11d36bfd88edefef7d428941cd48deb3dcc0581307bd7ff5-0", "0xb53374c1f187696dc64fcbe6656b3e5915d7649ddca6c65136334655b57d3375-0"} 178 | incomeCellInfos := []TableIncomeCellInfo{ 179 | { 180 | BlockNumber: 57181892, 181 | Action: "consolidate_income", 182 | Outpoint: "0x5687b6b801d9214f11d36bfd88edefef7d428941cd48deb3dcc0581307bd7ff5-0", 183 | Capacity: 13375050000, 184 | BlockTimestamp: 1635320117861, 185 | }, 186 | } 187 | transactionInfos := []TableTransactionInfo{ 188 | { 189 | BlockNumber: 57181892, 190 | Account: "linux.bit", 191 | Action: "consolidate_income", 192 | ServiceType: 1, 193 | ChainType: 0, 194 | Address: "0x78100ef7dfa4485dd1118b0d1bca3ef65d742ce0", 195 | Capacity: 40000000000, 196 | Outpoint: "0x5687b6b801d9214f11d36bfd88edefef7d428941cd48deb3dcc0581307bd7ff5-0", 197 | BlockTimestamp: 1635320117861, 198 | }, 199 | } 200 | err = dbDao.ConsolidateIncome(outpoints, incomeCellInfos, transactionInfos) 201 | if err != nil { 202 | t.Fatal(err) 203 | } 204 | t.Log(incomeCellInfos, "\n") 205 | t.Log(transactionInfos) 206 | } 207 | 208 | func TestUpdateCNYToUSDRate(t *testing.T) { 209 | dbDao, err := getInit() 210 | if err != nil { 211 | t.Fatal(err) 212 | } 213 | err = dbDao.UpdateCNYToUSDRate([]string{"ckb_ckb", "eth_eth"}, decimal.NewFromInt(80)) 214 | if err != nil { 215 | t.Fatal(err) 216 | } 217 | } 218 | 219 | func TestAutoMigrate(t *testing.T) { 220 | dbDao, err := getInit() 221 | if err != nil { 222 | t.Fatal(err) 223 | } 224 | err = dbDao.db.AutoMigrate( 225 | &TableAccountInfo{}, 226 | &TableBlockInfo{}, 227 | &TableIncomeCellInfo{}, 228 | &TableOfferInfo{}, 229 | &TableRebateInfo{}, 230 | &TableRecordsInfo{}, 231 | &TableReverseInfo{}, 232 | &TableSmtInfo{}, 233 | &TableTokenPriceInfo{}, 234 | &TableTradeDealInfo{}, 235 | &TableTradeInfo{}, 236 | &TableTransactionInfo{}, 237 | ) 238 | if err != nil { 239 | t.Fatal(err) 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /dao/dao_token_price_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "fmt" 5 | "github.com/dotbitHQ/das-lib/common" 6 | "github.com/shopspring/decimal" 7 | "gorm.io/gorm" 8 | "time" 9 | ) 10 | 11 | type TableTokenPriceInfo struct { 12 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 13 | TokenId string `json:"token_id" gorm:"column:token_id;uniqueIndex:uk_token_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 14 | GeckoId string `json:"gecko_id" gorm:"column:gecko_id;uniqueIndex:uk_gecko_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'the id from coingecko'"` 15 | ChainType int `json:"chain_type" gorm:"column:chain_type;index:k_ct_c;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 16 | CoinType common.CoinType `json:"coin_type" gorm:"column:coin_type; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 17 | Contract string `json:"contact" gorm:"column:contract;index:k_ct_c;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 18 | Name string `json:"name" gorm:"column:name;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'the name of token'"` 19 | Symbol string `json:"symbol" gorm:"column:symbol;index:k_symbol;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'the symbol of token'"` 20 | Decimals int32 `json:"decimals" gorm:"column:decimals;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 21 | Price decimal.Decimal `json:"price" gorm:"column:price;type:decimal(50, 8) NOT NULL DEFAULT '0.00000000' COMMENT ''"` 22 | Logo string `json:"logo" gorm:"column:logo;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 23 | Change24h decimal.Decimal `json:"change_24_h" gorm:"column:change_24_h;type:decimal(50, 8) NOT NULL DEFAULT '0.00000000' COMMENT ''"` 24 | Vol24h decimal.Decimal `json:"vol_24_h" gorm:"column:vol_24_h;type:decimal(50, 8) NOT NULL DEFAULT '0.00000000' COMMENT ''"` 25 | MarketCap decimal.Decimal `json:"market_cap" gorm:"column:market_cap;type:decimal(50, 8) NOT NULL DEFAULT '0.00000000' COMMENT ''"` 26 | LastUpdatedAt int64 `json:"last_updated_at" gorm:"column:last_updated_at;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 27 | Status int `json:"status" gorm:"column:status;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '0: normal 1: banned'"` 28 | Icon string `json:"icon" gorm:"column:icon; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 29 | DisplayName string `json:"display_name" gorm:"column:display_name; type:varchar(255) NOT NULL DEFAULT '' COMMENT '';"` 30 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 31 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 32 | } 33 | 34 | const ( 35 | TableNameTokenPriceInfo = "t_token_price_info" 36 | ) 37 | 38 | func (t *TableTokenPriceInfo) TableName() string { 39 | return TableNameTokenPriceInfo 40 | } 41 | 42 | func (t *TableTokenPriceInfo) GetPriceUsd(price uint64) decimal.Decimal { 43 | decPrice, _ := decimal.NewFromString(fmt.Sprintf("%d", price)) 44 | return t.Price.Mul(decPrice).DivRound(decimal.New(1, t.Decimals), 6) 45 | } 46 | 47 | func (d *DbDao) SearchTokenPriceInfoList() (tokenPriceInfos []TableTokenPriceInfo, err error) { 48 | err = d.db.Order("id DESC").Find(&tokenPriceInfos).Error 49 | return 50 | } 51 | 52 | func (d *DbDao) UpdateTokenPriceInfoList(tokenList []TableTokenPriceInfo) error { 53 | if len(tokenList) == 0 { 54 | return nil 55 | } 56 | return d.db.Transaction(func(tx *gorm.DB) error { 57 | for i, _ := range tokenList { 58 | if err := d.db.Model(TableTokenPriceInfo{}). 59 | Where("token_id=?", tokenList[i].TokenId). 60 | Updates(map[string]interface{}{ 61 | "price": tokenList[i].Price, 62 | "last_updated_at": tokenList[i].LastUpdatedAt, 63 | }).Error; err != nil { 64 | return err 65 | } 66 | } 67 | return nil 68 | }) 69 | } 70 | 71 | func (d *DbDao) UpdateCNYToUSDRate(tokenIds []string, price decimal.Decimal) error { 72 | return d.db.Select("price", "last_updated_at"). 73 | Where("token_id IN ?", tokenIds). 74 | Updates(TableTokenPriceInfo{ 75 | Price: price, 76 | LastUpdatedAt: time.Now().Unix(), 77 | }).Error 78 | } 79 | -------------------------------------------------------------------------------- /dao/dao_trade_deal_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "github.com/shopspring/decimal" 6 | "time" 7 | ) 8 | 9 | type TableTradeDealInfo struct { 10 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 11 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 12 | Outpoint string `json:"outpoint" gorm:"column:outpoint;uniqueIndex:uk_outpoint;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 13 | AccountId string `json:"account_id" gorm:"account_id;index:k_account_id;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'hash of account'"` 14 | Account string `json:"account" gorm:"column:account;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 15 | DealType int `json:"deal_type" gorm:"column:deal_type;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '0: sale 1: auction'"` 16 | SellChainType common.ChainType `json:"sell_chain_type" gorm:"column:sell_chain_type;index:k_sct_sa;type:int(11) NOT NULL DEFAULT '0' COMMENT ''"` 17 | SellAddress string `json:"sell_address" gorm:"column:sell_address;index:k_sct_sa;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 18 | BuyChainType common.ChainType `json:"buy_chain_type" gorm:"column:buy_chain_type;index:k_bct_ba;type:int(11) NOT NULL DEFAULT '0' COMMENT ''"` 19 | BuyAddress string `json:"buy_address" gorm:"column:buy_address;index:k_bct_ba;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 20 | PriceCkb uint64 `json:"price_ckb" gorm:"column:price_ckb;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'price in CKB'"` 21 | PriceUsd decimal.Decimal `json:"price_usd" gorm:"column:price_usd;type:decimal(50, 8) NOT NULL DEFAULT '0.00000000' COMMENT 'price in dollar'"` 22 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 23 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 24 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 25 | } 26 | 27 | const ( 28 | TableNameTradeDealInfo = "t_trade_deal_info" 29 | DealTypeSale = 0 30 | DealTypeAuction = 1 31 | DealTypeOffer = 2 32 | ) 33 | 34 | func (t *TableTradeDealInfo) TableName() string { 35 | return TableNameTradeDealInfo 36 | } 37 | -------------------------------------------------------------------------------- /dao/dao_trade_history_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "github.com/shopspring/decimal" 6 | "time" 7 | ) 8 | 9 | type TableTradeHistoryInfo struct { 10 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 11 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 12 | Outpoint string `json:"outpoint" gorm:"column:outpoint; uniqueIndex:uk_outpoint; type:varchar(255) NOT NULL DEFAULT '' COMMENT ''"` 13 | AccountId string `json:"account_id" gorm:"account_id;index:k_account_id;type:varchar(255) NOT NULL DEFAULT '' COMMENT 'hash of account'"` 14 | Account string `json:"account" gorm:"column:account;index:k_account;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 15 | OwnerAlgorithmId common.DasAlgorithmId `json:"owner_algorithm_id" gorm:"column:owner_algorithm_id;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 16 | OwnerChainType common.ChainType `json:"owner_chain_type" gorm:"column:owner_chain_type;index:k_oct_oa;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 17 | OwnerAddress string `json:"owner_address" gorm:"column:owner_address;index:k_oct_oa;type:varchar(255) NOT NULL DEFAULT '' COMMENT ''"` 18 | Description string `json:"description" gorm:"column:description;type:varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT ''"` 19 | StartedAt uint64 `json:"started_at" gorm:"column:started_at;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 20 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 21 | PriceCkb uint64 `json:"price_ckb" gorm:"column:price_ckb;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 22 | PriceUsd decimal.Decimal `json:"price_usd" gorm:"column:price_usd;type:decimal(50, 8) NOT NULL DEFAULT '0' COMMENT ''"` 23 | ProfitRate uint32 `json:"profit_rate" gorm:"column:profit_rate;type:int(11) unsigned NOT NULL DEFAULT '100' COMMENT ''"` 24 | Status uint8 `json:"status" gorm:"column:status;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '0: normal 1: on sale 2: on auction'"` 25 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 26 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 27 | } 28 | 29 | const ( 30 | TableNameTradeHistoryInfo = "t_trade_history_info" 31 | ) 32 | 33 | func (t *TableTradeHistoryInfo) TableName() string { 34 | return TableNameTradeHistoryInfo 35 | } 36 | -------------------------------------------------------------------------------- /dao/dao_transaction_info.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/dotbitHQ/das-lib/common" 5 | "gorm.io/gorm/clause" 6 | "time" 7 | ) 8 | 9 | type TableTransactionInfo struct { 10 | Id uint64 `json:"id" gorm:"column:id;primaryKey;type:bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''"` 11 | BlockNumber uint64 `json:"block_number" gorm:"column:block_number;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 12 | AccountId string `json:"account_id" gorm:"account_id;index:k_ai_a;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'hash of account'"` 13 | Account string `json:"account" gorm:"column:account;index:k_a_a;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 14 | Action string `json:"action" gorm:"column:action;index:k_ct_a_a,priority:3;index:k_a_a;index:k_ai_a;uniqueIndex:uk_a_o;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 15 | ServiceType int `json:"service_type" gorm:"column:service_type;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '1: register 2: trade'"` 16 | ChainType common.ChainType `json:"chain_type" gorm:"column:chain_type;index:k_ct_a_a,priority:1;index:k_ct_a;type:smallint(6) NOT NULL DEFAULT '0' COMMENT ''"` 17 | Address string `json:"address" gorm:"column:address;index:k_ct_a_a,priority:2;index:k_ct_a;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 18 | Capacity uint64 `json:"capacity" gorm:"column:capacity;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 19 | Outpoint string `json:"outpoint" gorm:"column:outpoint;index:k_outpoint;uniqueIndex:uk_a_o;type:varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT ''"` 20 | BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp;type:bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT ''"` 21 | Status int `json:"status" gorm:"column:status;type:smallint(6) NOT NULL DEFAULT '0' COMMENT '0: normal -1: rejected'"` 22 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''"` 23 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at;type:timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ''"` 24 | } 25 | 26 | const ( 27 | TableNameTransactionInfo = "t_transaction_info" 28 | 29 | ServiceTypeRegister = 1 30 | ServiceTypeTransaction = 2 31 | ServiceTypeSubAccount = 3 32 | ) 33 | 34 | func (t *TableTransactionInfo) TableName() string { 35 | return TableNameTransactionInfo 36 | } 37 | 38 | const ( 39 | DasActionTransferBalance = "transfer_balance" 40 | DasActionSaleAccount = "sale_account" 41 | DasActionOfferAccepted = "offer_accepted" 42 | DasActionEditOfferAdd = "offer_edit_add" 43 | DasActionEditOfferSub = "offer_edit_sub" 44 | DasActionOrderRefund = "order_refund" 45 | DasActionBalanceDeposit = "balance_deposit" 46 | DasActionCrossRefund = "cross_refund" 47 | ) 48 | 49 | func (d *DbDao) CreateTransactionInfo(transactionInfo TableTransactionInfo) error { 50 | return d.db.Clauses(clause.OnConflict{ 51 | DoUpdates: clause.AssignmentColumns([]string{ 52 | "account_id", "account", "service_type", 53 | "chain_type", "address", "capacity", "status", 54 | }), 55 | }).Create(&transactionInfo).Error 56 | } 57 | 58 | func (d *DbDao) CreateTransactionInfoList(transactionInfos []TableTransactionInfo) error { 59 | if len(transactionInfos) > 0 { 60 | return d.db.Clauses(clause.OnConflict{ 61 | DoUpdates: clause.AssignmentColumns([]string{ 62 | "account_id", "account", "service_type", 63 | "chain_type", "address", "capacity", "status", 64 | }), 65 | }).Create(&transactionInfos).Error 66 | } 67 | 68 | return nil 69 | } 70 | 71 | func (d *DbDao) CreateTxs(txs []TableTransactionInfo) error { 72 | if len(txs) == 0 { 73 | return nil 74 | } 75 | return d.db.Clauses(clause.Insert{ 76 | Modifier: "IGNORE", 77 | }).Create(&txs).Error 78 | } 79 | 80 | func (d *DbDao) FindTransactionInfoByAccountAction(account, action string) (transactionInfo TableTransactionInfo, err error) { 81 | err = d.db.Where("account = ? AND action = ?", account, action).Limit(1).Find(&transactionInfo).Error 82 | return 83 | } 84 | -------------------------------------------------------------------------------- /example/api_test.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | "das_database/dao" 5 | "das_database/http_server/api_code" 6 | "das_database/http_server/handle" 7 | "fmt" 8 | "github.com/dotbitHQ/das-lib/core" 9 | "github.com/parnurzeal/gorequest" 10 | "github.com/scorpiotzh/toolib" 11 | "golang.org/x/sync/errgroup" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | var ApiUrl = "https://snapshot-api.did.id/v1" 17 | 18 | func TestSnapshotProgress(t *testing.T) { 19 | url := ApiUrl + "/snapshot/progress" 20 | 21 | var req handle.ReqSnapshotProgress 22 | var data handle.RespSnapshotProgress 23 | 24 | if err := doReq(url, req, &data); err != nil { 25 | t.Fatal(err) 26 | } 27 | fmt.Println(toolib.JsonString(&data)) 28 | } 29 | 30 | func TestSnapshotPermissionsInfo(t *testing.T) { 31 | url := ApiUrl + "/snapshot/permissions/info" 32 | 33 | req := handle.ReqSnapshotPermissionsInfo{ 34 | Account: "test.20230216.bit", 35 | BlockNumber: 8357751, 36 | } 37 | var data handle.RespSnapshotPermissionsInfo 38 | 39 | if err := doReq(url, req, &data); err != nil { 40 | t.Fatal(err) 41 | } 42 | fmt.Println(toolib.JsonString(&data)) 43 | } 44 | 45 | func TestSnapshotAddressAccounts(t *testing.T) { 46 | url := ApiUrl + "/snapshot/address/accounts" 47 | req := handle.ReqSnapshotAddressAccounts{ 48 | ChainTypeAddress: core.ChainTypeAddress{ 49 | Type: "blockchain", 50 | KeyInfo: core.KeyInfo{ 51 | CoinType: "60", 52 | ChainId: "", 53 | Key: "0xc9f53b1d85356b60453f867610888d89a0b667ad", 54 | }, 55 | }, 56 | BlockNumber: 8357751, 57 | RoleType: "manager", 58 | Pagination: handle.Pagination{Page: 1, Size: 10}, 59 | } 60 | var data handle.RespSnapshotAddressAccounts 61 | 62 | if err := doReq(url, req, &data); err != nil { 63 | t.Fatal(err) 64 | } 65 | fmt.Println(toolib.JsonString(&data)) 66 | } 67 | 68 | func TestSnapshotRegisterHistory(t *testing.T) { 69 | url := ApiUrl + "/snapshot/register/history" 70 | req := handle.ReqSnapshotRegisterHistory{StartTime: "2023-02-10"} 71 | var data handle.RespSnapshotRegisterHistory 72 | 73 | if err := doReq(url, req, &data); err != nil { 74 | t.Fatal(err) 75 | } 76 | fmt.Println(fmt.Println(data.Result)) 77 | } 78 | 79 | func doReq(url string, req, data interface{}) error { 80 | var resp api_code.ApiResp 81 | resp.Data = &data 82 | 83 | _, _, errs := gorequest.New().Post(url).SendStruct(&req).EndStruct(&resp) 84 | if errs != nil { 85 | return fmt.Errorf("%v", errs) 86 | } 87 | if resp.ErrNo != api_code.ApiCodeSuccess { 88 | return fmt.Errorf("%d - %s", resp.ErrNo, resp.ErrMsg) 89 | } 90 | return nil 91 | } 92 | 93 | func TestPage(t *testing.T) { 94 | page := handle.Pagination{ 95 | Page: 1, 96 | Size: 20000, 97 | } 98 | fmt.Println(page.GetLimit(), page.GetOffset()) 99 | page.SetMaxSize(20000) 100 | fmt.Println(page.GetLimit(), page.GetOffset()) 101 | 102 | startTime := "2023-02-10" 103 | loc, _ := time.LoadLocation("Local") 104 | theTime, err := time.ParseInLocation("2006-01-02", startTime, loc) 105 | if err != nil { 106 | fmt.Println(err.Error()) 107 | } 108 | theTimestamp := uint64(theTime.Unix()) 109 | fmt.Println(theTimestamp) 110 | } 111 | 112 | func TestFixSnapshot(t *testing.T) { 113 | db, err := dao.NewGormDataBase("", "", "", "", 100, 200) 114 | if err != nil { 115 | t.Fatal(err) 116 | } 117 | 118 | var list []dao.TableSnapshotPermissionsInfo 119 | if err := db.Where(" `status`=99 ").Find(&list).Error; err != nil { 120 | t.Fatal(err) 121 | } 122 | fmt.Println(len(list)) 123 | errG := &errgroup.Group{} 124 | 125 | var ch = make(chan dao.TableSnapshotPermissionsInfo, 20) 126 | 127 | for i := 0; i < 20; i++ { 128 | errG.Go(func() error { 129 | for v := range ch { 130 | t.Log(v.AccountId, v.BlockNumber) 131 | var old dao.TableSnapshotPermissionsInfo 132 | if err := db.Where("account_id=? AND block_number maxSize { 19 | return maxSize 20 | } 21 | return p.Size 22 | } 23 | 24 | func (p *Pagination) GetOffset() int { 25 | page := p.Page 26 | if p.Page < 1 { 27 | page = 1 28 | } 29 | size := p.GetLimit() 30 | return (page - 1) * size 31 | } 32 | -------------------------------------------------------------------------------- /http_server/handle/snapshot_address_accounts.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "das_database/dao" 5 | "das_database/http_server/api_code" 6 | "encoding/json" 7 | "fmt" 8 | "github.com/dotbitHQ/das-lib/core" 9 | "github.com/dotbitHQ/das-lib/http_api" 10 | "github.com/gin-gonic/gin" 11 | "github.com/scorpiotzh/toolib" 12 | "net/http" 13 | ) 14 | 15 | type ReqSnapshotAddressAccounts struct { 16 | core.ChainTypeAddress 17 | BlockNumber uint64 `json:"block_number"` 18 | RoleType dao.RoleType `json:"role_type"` 19 | Pagination 20 | } 21 | 22 | type RespSnapshotAddressAccounts struct { 23 | Total int64 `json:"total"` 24 | Accounts []SnapshotAddressAccount `json:"accounts"` 25 | } 26 | 27 | type SnapshotAddressAccount struct { 28 | Account string `json:"account"` 29 | } 30 | 31 | func (h *HttpHandle) JsonRpcSnapshotAddressAccounts(p json.RawMessage, apiResp *http_api.ApiResp) { 32 | var req []ReqSnapshotAddressAccounts 33 | err := json.Unmarshal(p, &req) 34 | if err != nil { 35 | log.Error("json.Unmarshal err:", err.Error()) 36 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 37 | return 38 | } 39 | if len(req) != 1 { 40 | log.Error("len(req) is :", len(req)) 41 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 42 | return 43 | } 44 | 45 | if err = h.doSnapshotAddressAccounts(&req[0], apiResp); err != nil { 46 | log.Error("doSnapshotAddressAccounts err:", err.Error()) 47 | } 48 | } 49 | 50 | func (h *HttpHandle) SnapshotAddressAccounts(ctx *gin.Context) { 51 | var ( 52 | funcName = "SnapshotAddressAccounts" 53 | req ReqSnapshotAddressAccounts 54 | apiResp http_api.ApiResp 55 | err error 56 | ) 57 | 58 | if err := ctx.ShouldBindJSON(&req); err != nil { 59 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 60 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 61 | ctx.JSON(http.StatusOK, apiResp) 62 | return 63 | } 64 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 65 | 66 | if err = h.doSnapshotAddressAccounts(&req, &apiResp); err != nil { 67 | log.Error("doSnapshotAddressAccounts err:", err.Error(), funcName) 68 | } 69 | 70 | ctx.JSON(http.StatusOK, apiResp) 71 | } 72 | 73 | func (h *HttpHandle) doSnapshotAddressAccounts(req *ReqSnapshotAddressAccounts, apiResp *http_api.ApiResp) error { 74 | var resp RespSnapshotAddressAccounts 75 | resp.Accounts = make([]SnapshotAddressAccount, 0) 76 | 77 | addrHex, err := req.ChainTypeAddress.FormatChainTypeAddress(h.dasCore.NetType(), false) 78 | if err != nil { 79 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "Invalid key info parameter") 80 | return nil 81 | } 82 | 83 | // check 84 | //ok, err := h.checkSnapshotProgress(req.BlockNumber, apiResp) 85 | //if apiResp.ErrNo != api_code.ApiCodeSuccess { 86 | // return err 87 | //} else if !ok { 88 | // apiResp.ApiRespErr(api_code.ApiCodeSnapshotBehindSchedule, "Snapshot behind schedule") 89 | // return nil 90 | //} 91 | 92 | // snapshot 93 | list, err := h.dbDao.GetSnapshotAddressAccounts(addrHex.AddressHex, req.RoleType, req.BlockNumber, req.GetLimit(), req.GetOffset()) 94 | if err != nil { 95 | apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query historical account holding") 96 | return fmt.Errorf("GetSnapshotAddressAccounts err: %s", err.Error()) 97 | } 98 | for _, v := range list { 99 | resp.Accounts = append(resp.Accounts, SnapshotAddressAccount{Account: v.Account}) 100 | } 101 | 102 | total, err := h.dbDao.GetSnapshotAddressAccountsTotal(addrHex.AddressHex, req.RoleType, req.BlockNumber) 103 | if err != nil { 104 | apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query historical account holding") 105 | return fmt.Errorf("GetSnapshotAddressAccountsTotal err: %s", err.Error()) 106 | } 107 | resp.Total = total 108 | 109 | apiResp.ApiRespOK(resp) 110 | return nil 111 | } 112 | -------------------------------------------------------------------------------- /http_server/handle/snapshot_did_list.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/dotbitHQ/das-lib/http_api" 9 | "github.com/gin-gonic/gin" 10 | "github.com/scorpiotzh/toolib" 11 | "net/http" 12 | ) 13 | 14 | type ReqSnapshotDidList struct { 15 | core.ChainTypeAddress 16 | BlockNumber uint64 `json:"block_number"` 17 | AccountLength uint64 `json:"account_length"` 18 | } 19 | 20 | type RespSnapshotDidList struct { 21 | Total int `json:"total"` 22 | Accounts []SnapshotDid `json:"accounts"` 23 | } 24 | 25 | type SnapshotDid struct { 26 | Account string `json:"account"` 27 | } 28 | 29 | func (h *HttpHandle) JsonRpcSnapshotDidList(p json.RawMessage, apiResp *http_api.ApiResp) { 30 | var req []ReqSnapshotDidList 31 | err := json.Unmarshal(p, &req) 32 | if err != nil { 33 | log.Error("json.Unmarshal err:", err.Error()) 34 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 35 | return 36 | } 37 | if len(req) != 1 { 38 | log.Error("len(req) is :", len(req)) 39 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 40 | return 41 | } 42 | 43 | if err = h.doSnapshotDidList(&req[0], apiResp); err != nil { 44 | log.Error("doSnapshotDidList err:", err.Error()) 45 | } 46 | } 47 | 48 | func (h *HttpHandle) SnapshotDidList(ctx *gin.Context) { 49 | var ( 50 | funcName = "SnapshotDidList" 51 | req ReqSnapshotDidList 52 | apiResp http_api.ApiResp 53 | err error 54 | ) 55 | 56 | if err := ctx.ShouldBindJSON(&req); err != nil { 57 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 58 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 59 | ctx.JSON(http.StatusOK, apiResp) 60 | return 61 | } 62 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 63 | 64 | if err = h.doSnapshotDidList(&req, &apiResp); err != nil { 65 | log.Error("doSnapshotDidList err:", err.Error(), funcName) 66 | } 67 | 68 | ctx.JSON(http.StatusOK, apiResp) 69 | } 70 | 71 | func (h *HttpHandle) doSnapshotDidList(req *ReqSnapshotDidList, apiResp *http_api.ApiResp) error { 72 | var resp RespSnapshotDidList 73 | resp.Accounts = make([]SnapshotDid, 0) 74 | 75 | addrHex, err := req.ChainTypeAddress.FormatChainTypeAddress(h.dasCore.NetType(), false) 76 | if err != nil { 77 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info parameter") 78 | return nil 79 | } 80 | log.Info("doSnapshotDidList:", addrHex.AddressHex, addrHex.DasAlgorithmId) 81 | 82 | // snapshot 83 | list, err := h.dbDao.GetSnapshotDidList(addrHex.AddressHex, req.BlockNumber, req.AccountLength) 84 | if err != nil { 85 | apiResp.ApiRespErr(http_api.ApiCodeDbError, "Failed to query did list") 86 | return fmt.Errorf("GetSnapshotDidList err: %s", err.Error()) 87 | } 88 | for _, v := range list { 89 | _, accLen, err := common.GetDotBitAccountLength(v.Account) 90 | if err != nil { 91 | apiResp.ApiRespErr(http_api.ApiCodeError500, err.Error()) 92 | return fmt.Errorf("GetDotBitAccountLength err: %s", err.Error()) 93 | } 94 | if uint64(accLen) != req.AccountLength { 95 | continue 96 | } 97 | resp.Accounts = append(resp.Accounts, SnapshotDid{Account: v.Account}) 98 | } 99 | resp.Total = len(list) 100 | 101 | apiResp.ApiRespOK(resp) 102 | return nil 103 | } 104 | -------------------------------------------------------------------------------- /http_server/handle/snapshot_progress.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "das_database/http_server/api_code" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/gin-gonic/gin" 8 | "github.com/scorpiotzh/toolib" 9 | "net/http" 10 | ) 11 | 12 | type ReqSnapshotProgress struct { 13 | BlockNumber uint64 `json:"block_number"` 14 | } 15 | 16 | type RespSnapshotProgress struct { 17 | BlockNumber uint64 `json:"block_number"` 18 | } 19 | 20 | func (h *HttpHandle) JsonRpcSnapshotProgress(p json.RawMessage, apiResp *api_code.ApiResp) { 21 | var req []ReqSnapshotProgress 22 | err := json.Unmarshal(p, &req) 23 | if err != nil { 24 | log.Error("json.Unmarshal err:", err.Error()) 25 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 26 | return 27 | } 28 | if len(req) != 1 { 29 | log.Error("len(req) is :", len(req)) 30 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 31 | return 32 | } 33 | 34 | if err = h.doSnapshotProgress(&req[0], apiResp); err != nil { 35 | log.Error("doSnapshotProgress err:", err.Error()) 36 | } 37 | } 38 | 39 | func (h *HttpHandle) SnapshotProgress(ctx *gin.Context) { 40 | var ( 41 | funcName = "SnapshotProgress" 42 | req ReqSnapshotProgress 43 | apiResp api_code.ApiResp 44 | err error 45 | ) 46 | 47 | if err := ctx.ShouldBindJSON(&req); err != nil { 48 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 49 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 50 | ctx.JSON(http.StatusOK, apiResp) 51 | return 52 | } 53 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 54 | 55 | if err = h.doSnapshotProgress(&req, &apiResp); err != nil { 56 | log.Error("doSnapshotProgress err:", err.Error(), funcName) 57 | } 58 | 59 | ctx.JSON(http.StatusOK, apiResp) 60 | } 61 | 62 | func (h *HttpHandle) doSnapshotProgress(req *ReqSnapshotProgress, apiResp *api_code.ApiResp) error { 63 | var resp RespSnapshotProgress 64 | 65 | txS, err := h.dbDao.GetTxSnapshotSchedule() 66 | if err != nil { 67 | apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query snapshot progress") 68 | return fmt.Errorf("GetTxSnapshotSchedule err: %s", err.Error()) 69 | } else if txS.Id > 0 { 70 | resp.BlockNumber = txS.BlockNumber 71 | } 72 | log.Info("doSnapshotProgress:", resp.BlockNumber) 73 | 74 | apiResp.ApiRespOK(resp) 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /http_server/handle/snapshot_register_history.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "das_database/http_server/api_code" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/dotbitHQ/das-lib/common" 8 | "github.com/dotbitHQ/das-lib/http_api" 9 | "github.com/gin-gonic/gin" 10 | "github.com/scorpiotzh/toolib" 11 | "net/http" 12 | "sort" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | type ReqSnapshotRegisterHistory struct { 18 | StartTime string `json:"start_time"` 19 | } 20 | 21 | type RespSnapshotRegisterHistory struct { 22 | Result string `json:"result"` 23 | } 24 | 25 | func (h *HttpHandle) JsonRpcSnapshotRegisterHistory(p json.RawMessage, apiResp *http_api.ApiResp) { 26 | var req []ReqSnapshotRegisterHistory 27 | err := json.Unmarshal(p, &req) 28 | if err != nil { 29 | log.Error("json.Unmarshal err:", err.Error()) 30 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 31 | return 32 | } 33 | if len(req) != 1 { 34 | log.Error("len(req) is :", len(req)) 35 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 36 | return 37 | } 38 | 39 | if err = h.doSnapshotRegisterHistory(&req[0], apiResp); err != nil { 40 | log.Error("doSnapshotRegisterHistory err:", err.Error()) 41 | } 42 | } 43 | 44 | func (h *HttpHandle) SnapshotRegisterHistory(ctx *gin.Context) { 45 | var ( 46 | funcName = "SnapshotRegisterHistory" 47 | req ReqSnapshotRegisterHistory 48 | apiResp http_api.ApiResp 49 | err error 50 | ) 51 | 52 | if err := ctx.ShouldBindJSON(&req); err != nil { 53 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 54 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 55 | ctx.JSON(http.StatusOK, apiResp) 56 | return 57 | } 58 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 59 | 60 | if err = h.doSnapshotRegisterHistory(&req, &apiResp); err != nil { 61 | log.Error("doSnapshotRegisterHistory err:", err.Error(), funcName) 62 | } 63 | 64 | ctx.JSON(http.StatusOK, apiResp) 65 | } 66 | 67 | type registerInfo struct { 68 | count4 uint64 69 | count5 uint64 70 | countAll uint64 71 | countOwner uint64 72 | } 73 | 74 | func (h *HttpHandle) doSnapshotRegisterHistory(req *ReqSnapshotRegisterHistory, apiResp *http_api.ApiResp) error { 75 | var resp RespSnapshotRegisterHistory 76 | 77 | theTime, err := time.ParseInLocation("2006-01-02", req.StartTime, time.Local) 78 | if err != nil { 79 | fmt.Println(err.Error()) 80 | } 81 | theTimestamp := uint64(theTime.Unix()) 82 | log.Info("theTimestamp:", theTimestamp) 83 | 84 | page := Pagination{ 85 | Page: 1, 86 | Size: 10000, 87 | maxSize: 10000, 88 | } 89 | 90 | var res = make(map[string]registerInfo) 91 | var owner = make(map[string]struct{}) 92 | 93 | for { 94 | list, err := h.dbDao.GetRegisterHistory(page.GetLimit(), page.GetOffset()) 95 | if err != nil { 96 | apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query history info") 97 | return fmt.Errorf("GetRegisterHistory err: %s", err.Error()) 98 | } 99 | page.Page++ 100 | for _, v := range list { 101 | _, length, _ := common.GetDotBitAccountLength(v.Account) 102 | tm := time.Unix(int64(v.RegisteredAt), 0) 103 | registeredAt := tm.Format("2006-01-02") 104 | var tmp registerInfo 105 | if item, ok := res[registeredAt]; ok { 106 | tmp.count4 = item.count4 107 | tmp.count5 = item.count5 108 | tmp.countAll = item.countAll 109 | tmp.countOwner = item.countOwner 110 | } 111 | if length == 4 { 112 | tmp.count4++ 113 | } else if length >= 5 { 114 | tmp.count5++ 115 | } 116 | tmp.countAll++ 117 | 118 | if _, ok := owner[strings.ToLower(v.Owner)]; !ok { 119 | tmp.countOwner++ 120 | owner[strings.ToLower(v.Owner)] = struct{}{} 121 | } 122 | if v.RegisteredAt < theTimestamp { 123 | continue 124 | } 125 | res[registeredAt] = tmp 126 | } 127 | if len(list) == 0 || len(list) < page.GetLimit() { 128 | break 129 | } 130 | } 131 | log.Info("res:", len(res)) 132 | 133 | var strList []string 134 | for k, v := range res { 135 | str := "%s,%d,%d,%d,%d,\n" 136 | strList = append(strList, fmt.Sprintf(str, k, v.count4, v.count5, v.countAll, v.countOwner)) 137 | } 138 | sort.Strings(strList) 139 | resp.Result = "Date,4Digit,5Digit,DailyNewCount,DailyNewOwner,\n" 140 | for _, v := range strList { 141 | resp.Result += v 142 | } 143 | 144 | apiResp.ApiRespOK(resp) 145 | return nil 146 | } 147 | -------------------------------------------------------------------------------- /http_server/handle/snapshot_verify.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/dotbitHQ/das-lib/http_api" 9 | "github.com/gin-gonic/gin" 10 | "github.com/scorpiotzh/toolib" 11 | "net/http" 12 | ) 13 | 14 | type ReqSnapshotVerify struct { 15 | core.ChainTypeAddress 16 | Message string `json:"message"` 17 | Signature string `json:"signature"` 18 | PasskeySignAddress string `json:"passkey_sign_address"` 19 | } 20 | 21 | type RespSnapshotVerify struct { 22 | Verified bool `json:"verified"` 23 | } 24 | 25 | func (h *HttpHandle) JsonRpcSnapshotVerify(p json.RawMessage, apiResp *http_api.ApiResp) { 26 | var req []ReqSnapshotVerify 27 | err := json.Unmarshal(p, &req) 28 | if err != nil { 29 | log.Error("json.Unmarshal err:", err.Error()) 30 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 31 | return 32 | } 33 | if len(req) != 1 { 34 | log.Error("len(req) is :", len(req)) 35 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 36 | return 37 | } 38 | 39 | if err = h.doSnapshotVerify(&req[0], apiResp); err != nil { 40 | log.Error("doSnapshotVerify err:", err.Error()) 41 | } 42 | } 43 | 44 | func (h *HttpHandle) SnapshotVerify(ctx *gin.Context) { 45 | var ( 46 | funcName = "SnapshotVerify" 47 | req ReqSnapshotVerify 48 | apiResp http_api.ApiResp 49 | err error 50 | ) 51 | 52 | if err := ctx.ShouldBindJSON(&req); err != nil { 53 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 54 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "params invalid") 55 | ctx.JSON(http.StatusOK, apiResp) 56 | return 57 | } 58 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 59 | 60 | if err = h.doSnapshotVerify(&req, &apiResp); err != nil { 61 | log.Error("doSnapshotVerify err:", err.Error(), funcName) 62 | } 63 | 64 | ctx.JSON(http.StatusOK, apiResp) 65 | } 66 | 67 | func (h *HttpHandle) doSnapshotVerify(req *ReqSnapshotVerify, apiResp *http_api.ApiResp) error { 68 | var resp RespSnapshotVerify 69 | 70 | addrHex, err := req.ChainTypeAddress.FormatChainTypeAddress(h.dasCore.NetType(), false) 71 | if err != nil { 72 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info") 73 | return nil 74 | } 75 | if addrHex.DasAlgorithmId == common.DasAlgorithmIdAnyLock { 76 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info") 77 | return nil 78 | } 79 | 80 | signature := req.Signature 81 | addressHex := addrHex.AddressHex 82 | if addrHex.DasAlgorithmId == common.DasAlgorithmIdWebauthn { 83 | signAddressHex, err := h.dasCore.Daf().NormalToHex(core.DasAddressNormal{ 84 | ChainType: common.ChainTypeWebauthn, 85 | AddressNormal: req.PasskeySignAddress, 86 | }) 87 | if err != nil { 88 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info") 89 | return nil 90 | } 91 | addressHex = signAddressHex.AddressHex 92 | loginAddrHex := core.DasAddressHex{ 93 | DasAlgorithmId: common.DasAlgorithmIdWebauthn, 94 | DasSubAlgorithmId: common.DasWebauthnSubAlgorithmIdES256, 95 | AddressHex: addrHex.AddressHex, 96 | AddressPayload: common.Hex2Bytes(addrHex.AddressHex), 97 | ChainType: common.ChainTypeWebauthn, 98 | } 99 | signAddrHex := core.DasAddressHex{ 100 | DasAlgorithmId: common.DasAlgorithmIdWebauthn, 101 | DasSubAlgorithmId: common.DasWebauthnSubAlgorithmIdES256, 102 | AddressHex: signAddressHex.AddressHex, 103 | AddressPayload: common.Hex2Bytes(signAddressHex.AddressHex), 104 | ChainType: common.ChainTypeWebauthn, 105 | } 106 | idx, err := h.dasCore.GetIdxOfKeylist(loginAddrHex, signAddrHex) 107 | if err != nil { 108 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info") 109 | return fmt.Errorf("GetIdxOfKeylist err: %s", err.Error()) 110 | } 111 | if idx == -1 { 112 | apiResp.ApiRespErr(http_api.ApiCodeParamsInvalid, "Invalid key info") 113 | return fmt.Errorf("GetIdxOfKeylist idx: %d", idx) 114 | } 115 | h.dasCore.AddPkIndexForSignMsg(&signature, idx) 116 | } 117 | 118 | resp.Verified, _, err = http_api.VerifySignature(addrHex.DasAlgorithmId, req.Message, signature, addressHex) 119 | if err != nil { 120 | apiResp.ApiRespErr(http_api.ApiCodeSignError, "VerifySignature err") 121 | return fmt.Errorf("VerifySignature err: %s", err.Error()) 122 | } 123 | 124 | apiResp.ApiRespOK(resp) 125 | return nil 126 | } 127 | -------------------------------------------------------------------------------- /http_server/handle/version.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "das_database/http_server/api_code" 5 | "encoding/json" 6 | "github.com/gin-gonic/gin" 7 | "github.com/scorpiotzh/toolib" 8 | "net/http" 9 | ) 10 | 11 | type ReqVersion struct { 12 | } 13 | 14 | type RespVersion struct { 15 | } 16 | 17 | func (h *HttpHandle) JsonRpcVersion(p json.RawMessage, apiResp *api_code.ApiResp) { 18 | var req []ReqVersion 19 | err := json.Unmarshal(p, &req) 20 | if err != nil { 21 | log.Error("json.Unmarshal err:", err.Error()) 22 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 23 | return 24 | } 25 | if len(req) != 1 { 26 | log.Error("len(req) is :", len(req)) 27 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 28 | return 29 | } 30 | 31 | if err = h.doVersion(&req[0], apiResp); err != nil { 32 | log.Error("doVersion err:", err.Error()) 33 | } 34 | } 35 | 36 | func (h *HttpHandle) Version(ctx *gin.Context) { 37 | var ( 38 | funcName = "Version" 39 | req ReqVersion 40 | apiResp api_code.ApiResp 41 | err error 42 | ) 43 | 44 | if err := ctx.ShouldBindJSON(&req); err != nil { 45 | log.Error("ShouldBindJSON err: ", err.Error(), funcName) 46 | apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid") 47 | ctx.JSON(http.StatusOK, apiResp) 48 | return 49 | } 50 | log.Info("ApiReq:", funcName, toolib.JsonString(req)) 51 | 52 | if err = h.doVersion(&req, &apiResp); err != nil { 53 | log.Error("doVersion err:", err.Error(), funcName) 54 | } 55 | 56 | ctx.JSON(http.StatusOK, apiResp) 57 | } 58 | 59 | func (h *HttpHandle) doVersion(req *ReqVersion, apiResp *api_code.ApiResp) error { 60 | var resp RespVersion 61 | 62 | apiResp.ApiRespOK(resp) 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /http_server/http_server.go: -------------------------------------------------------------------------------- 1 | package http_server 2 | 3 | import ( 4 | "context" 5 | "das_database/block_parser" 6 | "das_database/config" 7 | "das_database/dao" 8 | "das_database/http_server/api_code" 9 | "das_database/http_server/handle" 10 | "encoding/json" 11 | "github.com/dotbitHQ/das-lib/core" 12 | "github.com/dotbitHQ/das-lib/http_api/logger" 13 | sentrygin "github.com/getsentry/sentry-go/gin" 14 | "github.com/gin-gonic/gin" 15 | "github.com/go-redis/redis" 16 | "github.com/scorpiotzh/toolib" 17 | "net/http" 18 | "time" 19 | ) 20 | 21 | var ( 22 | log = logger.NewLogger("http_server", logger.LevelDebug) 23 | ) 24 | 25 | type HttpServer struct { 26 | address string 27 | engine *gin.Engine 28 | h *handle.HttpHandle 29 | srv *http.Server 30 | ctx context.Context 31 | red *redis.Client 32 | } 33 | 34 | type HttpServerParams struct { 35 | Address string 36 | DbDao *dao.DbDao 37 | Ctx context.Context 38 | DasCore *core.DasCore 39 | Bp *block_parser.BlockParser 40 | Red *redis.Client 41 | } 42 | 43 | func Initialize(p HttpServerParams) (*HttpServer, error) { 44 | hs := HttpServer{ 45 | address: p.Address, 46 | engine: gin.New(), 47 | h: handle.Initialize(handle.HttpHandleParams{ 48 | DbDao: p.DbDao, 49 | DasCore: p.DasCore, 50 | Ctx: p.Ctx, 51 | Bp: p.Bp, 52 | Red: p.Red, 53 | }), 54 | ctx: p.Ctx, 55 | red: p.Red, 56 | } 57 | return &hs, nil 58 | } 59 | 60 | func (h *HttpServer) Run() { 61 | shortDataTime, lockTime, shortExpireTime := time.Minute, time.Second*30, time.Second*5 62 | cacheHandle := toolib.MiddlewareCacheByRedis(h.red, false, shortDataTime, lockTime, shortExpireTime, respHandle) 63 | 64 | if len(config.Cfg.Origins) > 0 { 65 | toolib.AllowOriginList = append(toolib.AllowOriginList, config.Cfg.Origins...) 66 | } 67 | 68 | h.engine.Use(toolib.MiddlewareCors()) 69 | h.engine.POST("", cacheHandle, h.h.JasonRpcHandle) 70 | h.engine.Use(sentrygin.New(sentrygin.Options{ 71 | Repanic: true, 72 | })) 73 | v1 := h.engine.Group("v1") 74 | { 75 | v1.POST("/latest/block/number", api_code.DoMonitorLog(api_code.MethodLatestBlockNumber), h.h.IsLatestBlockNumber) 76 | v1.POST("/snapshot/progress", api_code.DoMonitorLog(api_code.MethodSnapshotProgress), cacheHandle, h.h.SnapshotProgress) 77 | v1.POST("/snapshot/permissions/info", api_code.DoMonitorLog(api_code.MethodSnapshotPermissionsInfo), cacheHandle, h.h.SnapshotPermissionsInfo) 78 | v1.POST("/snapshot/address/accounts", api_code.DoMonitorLog(api_code.MethodSnapshotAddressAccounts), cacheHandle, h.h.SnapshotAddressAccounts) 79 | v1.POST("/snapshot/register/history", api_code.DoMonitorLog(api_code.MethodSnapshotRegisterHistory), cacheHandle, h.h.SnapshotRegisterHistory) 80 | 81 | v1.POST("/snapshot/did/list", api_code.DoMonitorLog(api_code.MethodSnapshotDidList), cacheHandle, h.h.SnapshotDidList) 82 | v1.POST("/snapshot/verify", api_code.DoMonitorLog(api_code.MethodSnapshotVerify), cacheHandle, h.h.SnapshotVerify) 83 | v1.GET("/test/jenkins", func(c *gin.Context) { 84 | c.JSON(200, "main--v1.0.0") 85 | }) 86 | } 87 | 88 | h.srv = &http.Server{ 89 | Addr: h.address, 90 | Handler: h.engine, 91 | } 92 | go func() { 93 | if err := h.srv.ListenAndServe(); err != nil { 94 | log.Error("http_server run err:", err) 95 | } 96 | }() 97 | } 98 | 99 | func (h *HttpServer) Shutdown() { 100 | log.Warn("http server Shutdown ... ") 101 | if h.srv != nil { 102 | if err := h.srv.Shutdown(h.ctx); err != nil { 103 | log.Error("http server Shutdown err:", err.Error()) 104 | } 105 | } 106 | } 107 | 108 | func respHandle(c *gin.Context, res string, err error) { 109 | if err != nil { 110 | log.Error("respHandle err:", err.Error()) 111 | c.AbortWithStatusJSON(http.StatusOK, api_code.ApiRespErr(api_code.ApiCodeError500, err.Error())) 112 | } else if res != "" { 113 | var respMap map[string]interface{} 114 | _ = json.Unmarshal([]byte(res), &respMap) 115 | c.AbortWithStatusJSON(http.StatusOK, respMap) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /notify/lark.go: -------------------------------------------------------------------------------- 1 | package notify 2 | 3 | import ( 4 | "das_database/prometheus" 5 | "fmt" 6 | "github.com/parnurzeal/gorequest" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | type MsgContent struct { 12 | Tag string `json:"tag"` 13 | UserId string `json:"user_id,omitempty"` 14 | UnEscape bool `json:"un_escape,omitempty"` 15 | Text string `json:"text,omitempty"` 16 | Href string `json:"href,omitempty"` 17 | } 18 | type MsgData struct { 19 | Email string `json:"email"` 20 | MsgType string `json:"msg_type"` 21 | Content struct { 22 | Post struct { 23 | ZhCn struct { 24 | Title string `json:"title"` 25 | Content [][]MsgContent `json:"content"` 26 | } `json:"zh_cn"` 27 | } `json:"post"` 28 | } `json:"content"` 29 | } 30 | 31 | func SendLarkTextNotify(url, title, text string) error { 32 | if url == "" || text == "" { 33 | return nil 34 | } 35 | var data MsgData 36 | data.Email = "" 37 | data.MsgType = "post" 38 | data.Content.Post.ZhCn.Title = title 39 | data.Content.Post.ZhCn.Content = [][]MsgContent{ 40 | { 41 | MsgContent{ 42 | Tag: "text", 43 | UnEscape: false, 44 | Text: text, 45 | }, 46 | }, 47 | } 48 | resp, _, errs := gorequest.New().Post(url).Timeout(time.Second * 10).SendStruct(&data).End() 49 | if len(errs) > 0 { 50 | return fmt.Errorf("errs:%v", errs) 51 | } else if resp.StatusCode != http.StatusOK { 52 | return fmt.Errorf("http code:%d", resp.StatusCode) 53 | } 54 | return nil 55 | } 56 | 57 | func SendLarkErrNotify(title, text string) { 58 | if title == "" || text == "" { 59 | return 60 | } 61 | prometheus.Tools.Metrics.ErrNotify().WithLabelValues(title, text).Inc() 62 | } 63 | -------------------------------------------------------------------------------- /notify/notify_test.go: -------------------------------------------------------------------------------- 1 | package notify 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestSendLarkTextNotify(t *testing.T) { 10 | // notify 11 | msg := "> Transaction hash:%s\n> Action:%s\n> Timestamp:%s\n> Error message:%s" 12 | msg = fmt.Sprintf(msg, "0x31db70391cb1b541cccbd5146e77870c095b48bc4dc8d763f222c9b0afe19424", "edit_offer", time.Now().Format("2006-01-02 15:04:05"), "ArgsToHex err...") 13 | err := SendLarkTextNotify( 14 | "https://open.larksuite.com/open-apis/bot/v2/hook/a5225cf9-7865-486e-917d-2284b0395e98", 15 | "DasDatabase BlockParser", 16 | msg, 17 | ) 18 | if err != nil { 19 | t.Log("SendLarkTextNotify err:", err.Error()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /prometheus/prometheus.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | import ( 4 | "das_database/config" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/http_api/logger" 7 | "github.com/prometheus/client_golang/prometheus" 8 | "github.com/prometheus/client_golang/prometheus/push" 9 | "net" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | var ( 15 | log = logger.NewLogger("prometheus", logger.LevelDebug) 16 | PromRegister = prometheus.NewRegistry() 17 | ) 18 | 19 | var Tools *Prometheus 20 | 21 | type Prometheus struct { 22 | pusher *push.Pusher 23 | Metrics Metric 24 | } 25 | 26 | type Metric struct { 27 | l sync.Mutex 28 | api *prometheus.SummaryVec 29 | errNotify *prometheus.CounterVec 30 | } 31 | 32 | func (m *Metric) Api() *prometheus.SummaryVec { 33 | if m.api == nil { 34 | m.l.Lock() 35 | defer m.l.Unlock() 36 | m.api = prometheus.NewSummaryVec(prometheus.SummaryOpts{ 37 | Name: "api", 38 | }, []string{"method", "http_status", "err_no", "err_msg"}) 39 | PromRegister.MustRegister(m.api) 40 | } 41 | return m.api 42 | } 43 | 44 | func (m *Metric) ErrNotify() *prometheus.CounterVec { 45 | if m.errNotify == nil { 46 | m.l.Lock() 47 | defer m.l.Unlock() 48 | m.errNotify = prometheus.NewCounterVec(prometheus.CounterOpts{ 49 | Name: "notify", 50 | }, []string{"title", "text"}) 51 | PromRegister.MustRegister(m.errNotify) 52 | } 53 | return m.errNotify 54 | } 55 | 56 | func Init() { 57 | Tools = &Prometheus{} 58 | } 59 | 60 | func (t *Prometheus) Run() { 61 | if config.Cfg.Server.PrometheusPushGateway != "" && config.Cfg.Server.Name != "" { 62 | t.pusher = push.New(config.Cfg.Server.PrometheusPushGateway, config.Cfg.Server.Name) 63 | t.pusher.Gatherer(PromRegister) 64 | t.pusher.Grouping("env", fmt.Sprint(config.Cfg.Server.Net)) 65 | t.pusher.Grouping("instance", GetLocalIp("eth0")) 66 | 67 | go func() { 68 | ticker := time.NewTicker(time.Second * 5) 69 | defer ticker.Stop() 70 | 71 | for range ticker.C { 72 | _ = t.pusher.Push() 73 | } 74 | }() 75 | } 76 | } 77 | 78 | func GetLocalIp(interfaceName string) string { 79 | ief, err := net.InterfaceByName(interfaceName) 80 | if err != nil { 81 | log.Error("GetLocalIp: ", err) 82 | return "" 83 | } 84 | addrs, err := ief.Addrs() 85 | if err != nil { 86 | log.Error("GetLocalIp: ", err) 87 | return "" 88 | } 89 | 90 | var ipv4Addr net.IP 91 | for _, addr := range addrs { 92 | if ipv4Addr = addr.(*net.IPNet).IP.To4(); ipv4Addr != nil { 93 | break 94 | } 95 | } 96 | if ipv4Addr == nil { 97 | log.Errorf("GetLocalIp interface %s don't have an ipv4 address", interfaceName) 98 | return "" 99 | } 100 | return ipv4Addr.String() 101 | } 102 | -------------------------------------------------------------------------------- /snapshot/register.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "das_database/dao" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/dotbitHQ/das-lib/witness" 9 | "github.com/nervosnetwork/ckb-sdk-go/types" 10 | ) 11 | 12 | func (t *ToolSnapshot) addAccountRegisterByDasActionConfirmProposal(info dao.TableSnapshotTxInfo, tx *types.Transaction) error { 13 | log.Info("addAccountRegister:", info.Action, info.Hash) 14 | 15 | mapOldAcc, err := witness.AccountIdCellDataBuilderFromTx(tx, common.DataTypeOld) 16 | if err != nil { 17 | return fmt.Errorf("AccountIdCellDataBuilderFromTx err: %s", err.Error()) 18 | } 19 | 20 | mapNewAcc, err := witness.AccountIdCellDataBuilderFromTx(tx, common.DataTypeNew) 21 | if err != nil { 22 | return fmt.Errorf("AccountIdCellDataBuilderFromTx err: %s", err.Error()) 23 | } 24 | 25 | var list []dao.TableSnapshotRegisterInfo 26 | for k, v := range mapNewAcc { 27 | if _, ok := mapOldAcc[k]; ok { 28 | continue 29 | } 30 | 31 | owner, _, err := t.DasCore.Daf().ArgsToHex(tx.Outputs[v.Index].Lock.Args) 32 | if err != nil { 33 | return fmt.Errorf("ArgsToHex err: %s", err.Error()) 34 | } 35 | tmp := dao.TableSnapshotRegisterInfo{ 36 | BlockNumber: info.BlockNumber, 37 | AccountId: k, 38 | ParentAccountId: "", 39 | Hash: info.Hash, 40 | Account: v.Account, 41 | BlockTimestamp: info.BlockTimestamp, 42 | Owner: owner.AddressHex, 43 | OwnerAlgorithmId: owner.DasAlgorithmId, 44 | RegisteredAt: v.RegisteredAt, 45 | ExpiredAt: v.ExpiredAt, 46 | } 47 | list = append(list, tmp) 48 | } 49 | 50 | if err := t.DbDao.CreateSnapshotRegister(list); err != nil { 51 | return fmt.Errorf("CreateSnapshotRegister err: %s", err.Error()) 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func (t *ToolSnapshot) addSubAccountRegisterByDasActionCreateSubAccount(info dao.TableSnapshotTxInfo, tx *types.Transaction) error { 58 | log.Info("addSubAccountRegister:", info.Action, info.Hash) 59 | 60 | contractSub, err := core.GetDasContractInfo(common.DASContractNameSubAccountCellType) 61 | if err != nil { 62 | return fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 63 | } 64 | var parentAccountId string 65 | for _, v := range tx.Outputs { 66 | if v.Type != nil && contractSub.IsSameTypeId(v.Type.CodeHash) { 67 | parentAccountId = common.Bytes2Hex(v.Type.Args) 68 | break 69 | } 70 | } 71 | 72 | var sanb witness.SubAccountNewBuilder 73 | mapSubAcc, err := sanb.SubAccountNewMapFromTx(tx) 74 | if err != nil { 75 | return fmt.Errorf("SubAccountNewMapFromTx err: %s", err.Error()) 76 | } 77 | var list []dao.TableSnapshotRegisterInfo 78 | for k, v := range mapSubAcc { 79 | owner, _, err := t.DasCore.Daf().ArgsToHex(v.CurrentSubAccountData.Lock.Args) 80 | if err != nil { 81 | return fmt.Errorf("ArgsToHex err: %s", err.Error()) 82 | } 83 | tmp := dao.TableSnapshotRegisterInfo{ 84 | BlockNumber: info.BlockNumber, 85 | AccountId: k, 86 | ParentAccountId: parentAccountId, 87 | Hash: info.Hash, 88 | Account: v.CurrentSubAccountData.Account(), 89 | BlockTimestamp: info.BlockTimestamp, 90 | Owner: owner.AddressHex, 91 | RegisteredAt: v.CurrentSubAccountData.RegisteredAt, 92 | OwnerAlgorithmId: owner.DasAlgorithmId, 93 | ExpiredAt: v.CurrentSubAccountData.ExpiredAt, 94 | } 95 | list = append(list, tmp) 96 | } 97 | 98 | if err := t.DbDao.CreateSnapshotRegister(list); err != nil { 99 | return fmt.Errorf("CreateSnapshotRegister err: %s", err.Error()) 100 | } 101 | return nil 102 | } 103 | 104 | func (t *ToolSnapshot) addSubAccountRegister(info dao.TableSnapshotTxInfo, tx *types.Transaction) error { 105 | log.Info("addSubAccountRegister:", info.Action, info.Hash) 106 | 107 | contractSub, err := core.GetDasContractInfo(common.DASContractNameSubAccountCellType) 108 | if err != nil { 109 | return fmt.Errorf("GetDasContractInfo err: %s", err.Error()) 110 | } 111 | var parentAccountId string 112 | for _, v := range tx.Outputs { 113 | if v.Type != nil && contractSub.IsSameTypeId(v.Type.CodeHash) { 114 | parentAccountId = common.Bytes2Hex(v.Type.Args) 115 | break 116 | } 117 | } 118 | 119 | var sanb witness.SubAccountNewBuilder 120 | mapSubAcc, err := sanb.SubAccountNewMapFromTx(tx) 121 | if err != nil { 122 | return fmt.Errorf("SubAccountNewMapFromTx err: %s", err.Error()) 123 | } 124 | var list []dao.TableSnapshotRegisterInfo 125 | for k, v := range mapSubAcc { 126 | if info.Action == common.DasActionUpdateSubAccount && v.Action != common.SubActionCreate { 127 | continue 128 | } 129 | owner, _, err := t.DasCore.Daf().ArgsToHex(v.CurrentSubAccountData.Lock.Args) 130 | if err != nil { 131 | return fmt.Errorf("ArgsToHex err: %s", err.Error()) 132 | } 133 | tmp := dao.TableSnapshotRegisterInfo{ 134 | BlockNumber: info.BlockNumber, 135 | AccountId: k, 136 | ParentAccountId: parentAccountId, 137 | Hash: info.Hash, 138 | Account: v.CurrentSubAccountData.Account(), 139 | BlockTimestamp: info.BlockTimestamp, 140 | Owner: owner.AddressHex, 141 | RegisteredAt: v.CurrentSubAccountData.RegisteredAt, 142 | OwnerAlgorithmId: owner.DasAlgorithmId, 143 | ExpiredAt: v.CurrentSubAccountData.ExpiredAt, 144 | } 145 | list = append(list, tmp) 146 | } 147 | 148 | if err := t.DbDao.CreateSnapshotRegister(list); err != nil { 149 | return fmt.Errorf("CreateSnapshotRegister err: %s", err.Error()) 150 | } 151 | return nil 152 | } 153 | -------------------------------------------------------------------------------- /snapshot/snapshot.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "context" 5 | "das_database/config" 6 | "das_database/dao" 7 | "das_database/notify" 8 | "fmt" 9 | "github.com/dotbitHQ/das-lib/common" 10 | "github.com/dotbitHQ/das-lib/core" 11 | "github.com/dotbitHQ/das-lib/http_api" 12 | "github.com/dotbitHQ/das-lib/http_api/logger" 13 | "github.com/nervosnetwork/ckb-sdk-go/types" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | var log = logger.NewLogger("snapshot", logger.LevelDebug) 19 | 20 | type ToolSnapshot struct { 21 | Ctx context.Context 22 | Cancel context.CancelFunc 23 | Wg *sync.WaitGroup 24 | DbDao *dao.DbDao 25 | DasCore *core.DasCore 26 | ConcurrencyNum uint64 27 | ConfirmNum uint64 28 | 29 | currentBlockNumber uint64 30 | parserType dao.ParserType 31 | mapTransactionHandle map[common.DasAction][]FuncTransactionHandle 32 | errTxCount int 33 | errSnapshotCount int 34 | } 35 | 36 | type FuncTransactionHandle func(info dao.TableSnapshotTxInfo, tx *types.Transaction) error 37 | 38 | func (t *ToolSnapshot) init() error { 39 | t.parserType = dao.ParserTypeSnapshot 40 | t.registerTransactionHandle() 41 | if err := t.initCurrentBlockNumber(); err != nil { 42 | return fmt.Errorf("initCurrentBlockNumber err: %s", err.Error()) 43 | } 44 | return nil 45 | } 46 | func (t *ToolSnapshot) Run(open bool) error { 47 | if !open { 48 | return nil 49 | } 50 | if err := t.init(); err != nil { 51 | return fmt.Errorf("ToolSnapshot init err: %s", err.Error()) 52 | } 53 | t.RunTxSnapshot() 54 | 55 | t.RunDataSnapshot() 56 | return nil 57 | } 58 | 59 | func (t *ToolSnapshot) registerTransactionHandle() { 60 | t.mapTransactionHandle = make(map[string][]FuncTransactionHandle) 61 | 62 | t.mapTransactionHandle[common.DasActionTransferAccount] = []FuncTransactionHandle{t.addAccountPermissions} 63 | t.mapTransactionHandle[common.DasActionEditManager] = []FuncTransactionHandle{t.addAccountPermissions} 64 | t.mapTransactionHandle[common.DasActionBuyAccount] = []FuncTransactionHandle{t.addAccountPermissions} 65 | t.mapTransactionHandle[common.DasActionCancelAccountSale] = []FuncTransactionHandle{t.addAccountPermissions} 66 | t.mapTransactionHandle[common.DasActionAcceptOffer] = []FuncTransactionHandle{t.addAccountPermissions} 67 | t.mapTransactionHandle[common.DasActionStartAccountSale] = []FuncTransactionHandle{t.addAccountPermissions} 68 | t.mapTransactionHandle[common.DasActionConfirmProposal] = []FuncTransactionHandle{t.addAccountPermissionsByDasActionConfirmProposal, t.addAccountRegisterByDasActionConfirmProposal} 69 | t.mapTransactionHandle[common.DasActionRenewAccount] = []FuncTransactionHandle{t.addAccountPermissions} 70 | t.mapTransactionHandle[common.DasActionForceRecoverAccountStatus] = []FuncTransactionHandle{t.addAccountPermissions} 71 | t.mapTransactionHandle[common.DasActionBidExpiredAccountAuction] = []FuncTransactionHandle{t.addAccountPermissions} 72 | 73 | t.mapTransactionHandle[common.DasActionUnlockAccountForCrossChain] = []FuncTransactionHandle{t.addAccountPermissions} 74 | t.mapTransactionHandle[common.DasActionLockAccountForCrossChain] = []FuncTransactionHandle{t.addAccountPermissions} 75 | t.mapTransactionHandle[common.DasActionRecycleExpiredAccount] = []FuncTransactionHandle{t.addAccountPermissionsByDasActionRecycleExpiredAccount} 76 | 77 | t.mapTransactionHandle[common.DasActionCreateSubAccount] = []FuncTransactionHandle{t.addSubAccountPermissionsByDasActionCreateSubAccount, t.addSubAccountRegisterByDasActionCreateSubAccount} 78 | t.mapTransactionHandle[common.DasActionEditSubAccount] = []FuncTransactionHandle{t.addSubAccountPermissionsByDasActionEditSubAccount} 79 | t.mapTransactionHandle[common.DasActionUpdateSubAccount] = []FuncTransactionHandle{t.addSubAccountPermissions, t.addSubAccountRegister} 80 | 81 | t.mapTransactionHandle[common.DasActionBidExpiredAccountAuction] = []FuncTransactionHandle{t.addAccountPermissions} 82 | 83 | t.mapTransactionHandle[common.DidCellActionUpdate] = []FuncTransactionHandle{t.addAccountPermissionsForDidCell} 84 | } 85 | 86 | func (t *ToolSnapshot) RunDataSnapshot() { 87 | t.Wg.Add(1) 88 | tickerParser := time.NewTicker(time.Second * 10) 89 | go func() { 90 | defer http_api.RecoverPanic() 91 | for { 92 | select { 93 | case <-tickerParser.C: 94 | if err := t.runDataSnapshot(); err != nil { 95 | log.Error("runDataSnapshot err:", err.Error()) 96 | if t.errSnapshotCount < 100 { 97 | t.errSnapshotCount++ 98 | notify.SendLarkErrNotify("runDataSnapshot", err.Error()) 99 | } 100 | } else { 101 | t.errSnapshotCount = 0 102 | } 103 | case <-t.Ctx.Done(): 104 | t.Wg.Done() 105 | return 106 | } 107 | } 108 | }() 109 | } 110 | 111 | func (t *ToolSnapshot) runDataSnapshot() error { 112 | // get currentBlockNumber 113 | currentBlockNumber := uint64(0) 114 | txS, err := t.DbDao.GetTxSnapshotSchedule() 115 | if err != nil { 116 | return fmt.Errorf("GetTxSnapshotSchedule err: %s", err.Error()) 117 | } else if txS.Id > 0 { 118 | currentBlockNumber = txS.BlockNumber 119 | } else { 120 | if err := t.DbDao.InitSnapshotSchedule(); err != nil { 121 | return fmt.Errorf("InitSnapshotSchedule err: %s", err.Error()) 122 | } 123 | } 124 | log.Debug("runDataSnapshot:", currentBlockNumber) 125 | 126 | // get parser list 127 | list, err := t.DbDao.GetTxSnapshotByBlockNumber(currentBlockNumber, config.Cfg.Snapshot.SnapshotNum) 128 | if err != nil { 129 | return fmt.Errorf("GetTxSnapshotByBlockNumber err: %s", err.Error()) 130 | } 131 | 132 | // parser 133 | for _, v := range list { 134 | if er := t.doDataSnapshotParser(v); er != nil { 135 | return fmt.Errorf("doDataSnapshotParser err: %s", er.Error()) 136 | } 137 | if v.BlockNumber > currentBlockNumber { 138 | currentBlockNumber = v.BlockNumber 139 | // update 140 | if err := t.DbDao.UpdateTxSnapshotSchedule(currentBlockNumber); err != nil { 141 | return fmt.Errorf("UpdateTxSnapshotSchedule err: %s", err.Error()) 142 | } 143 | } 144 | } 145 | 146 | return nil 147 | } 148 | 149 | func (t *ToolSnapshot) doDataSnapshotParser(info dao.TableSnapshotTxInfo) error { 150 | res, err := t.DasCore.Client().GetTransaction(t.Ctx, types.HexToHash(info.Hash)) 151 | if err != nil { 152 | return fmt.Errorf("GetTransaction err: %s", err.Error()) 153 | } 154 | 155 | if handleList, ok := t.mapTransactionHandle[info.Action]; ok { 156 | for _, handle := range handleList { 157 | if err := handle(info, res.Transaction); err != nil { 158 | return fmt.Errorf("handle err: %s", err.Error()) 159 | } 160 | } 161 | } 162 | 163 | return nil 164 | } 165 | -------------------------------------------------------------------------------- /snapshot/snapshot_test.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/dotbitHQ/das-lib/common" 7 | "github.com/dotbitHQ/das-lib/core" 8 | "github.com/nervosnetwork/ckb-sdk-go/rpc" 9 | "github.com/nervosnetwork/ckb-sdk-go/types" 10 | "sort" 11 | "sync" 12 | "testing" 13 | ) 14 | 15 | func TestCheckContractCodeHash(t *testing.T) { 16 | ctxServer, _ := context.WithCancel(context.Background()) 17 | wgServer := sync.WaitGroup{} 18 | 19 | ckbUrl := "https://testnet.ckb.dev/" 20 | ckbClient, err := rpc.DialWithIndexer(ckbUrl, ckbUrl) 21 | if err != nil { 22 | t.Fatal(err) 23 | } 24 | 25 | env := core.InitEnv(common.DasNetTypeTestnet2) 26 | opts := []core.DasCoreOption{ 27 | core.WithClient(ckbClient), 28 | core.WithDasContractArgs(env.ContractArgs), 29 | core.WithDasContractCodeHash(env.ContractCodeHash), 30 | core.WithDasNetType(common.DasNetTypeTestnet2), 31 | core.WithTHQCodeHash(env.THQCodeHash), 32 | } 33 | dc := core.NewDasCore(ctxServer, &wgServer, opts...) 34 | dc.InitDasContract(env.MapContract) 35 | 36 | res, err := dc.Client().GetTransaction(ctxServer, types.HexToHash("0x97697e27b8690a9cf10f297150f1305e5305f8c1d514619196829e8efceb856b")) 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | var s ToolSnapshot 41 | fmt.Println(s.checkContractCodeHash(res.Transaction)) 42 | } 43 | 44 | func TestBlockList(t *testing.T) { 45 | blockListTmp := make([]*types.Block, 0) 46 | blockListTmp = append(blockListTmp, &types.Block{Header: &types.Header{Number: 5007343}}) 47 | blockListTmp = append(blockListTmp, &types.Block{Header: &types.Header{Number: 5007335}}) 48 | blockListTmp = append(blockListTmp, &types.Block{Header: &types.Header{Number: 5007498}}) 49 | sort.Sort(blockList(blockListTmp)) 50 | for i := range blockListTmp { 51 | fmt.Println(blockListTmp[i].Header.Number) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /timer/charset.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "das_database/config" 5 | "github.com/dotbitHQ/das-lib/common" 6 | "github.com/dotbitHQ/das-lib/witness" 7 | "github.com/nervosnetwork/ckb-sdk-go/types" 8 | "time" 9 | ) 10 | 11 | func (p *ParserTimer) RunFixCharset() { 12 | if config.Cfg.Server.FixCharset { 13 | tickerCharset := time.NewTicker(time.Second * 10) 14 | p.Wg.Add(1) 15 | go func() { 16 | ok := false 17 | for { 18 | select { 19 | case <-tickerCharset.C: 20 | ok = p.doFixCharset() 21 | case <-p.Ctx.Done(): 22 | p.Wg.Done() 23 | return 24 | } 25 | if ok { 26 | break 27 | } 28 | } 29 | }() 30 | } 31 | } 32 | 33 | func (p *ParserTimer) doFixCharset() bool { 34 | list, err := p.DbDao.GetNeedFixCharsetAccountList() 35 | if err != nil { 36 | log.Error("GetNeedFixCharsetAccountList err: ", err.Error()) 37 | return false 38 | } 39 | if len(list) == 0 { 40 | log.Info("doFixCharset ok") 41 | return true 42 | } 43 | 44 | var hashList = make(map[string]struct{}) 45 | for _, v := range list { 46 | hashList[v.ConfirmProposalHash] = struct{}{} 47 | } 48 | 49 | var accCharset = make(map[string]uint64) 50 | for k, _ := range hashList { 51 | tx, err := p.DasCore.Client().GetTransaction(p.Ctx, types.HexToHash(k)) 52 | if err != nil { 53 | log.Error("GetTransaction err: ", err.Error()) 54 | continue 55 | } 56 | accMap, err := witness.AccountIdCellDataBuilderFromTx(tx.Transaction, common.DataTypeNew) 57 | if err != nil { 58 | log.Error("AccountIdCellDataBuilderFromTx err: ", err.Error()) 59 | continue 60 | } 61 | for _, v := range accMap { 62 | charsetNum := common.ConvertAccountCharsToCharsetNum(v.AccountChars) 63 | accCharset[v.AccountId] = charsetNum 64 | } 65 | } 66 | // 67 | if err := p.DbDao.UpdateAccountCharsetNum(accCharset); err != nil { 68 | log.Error("UpdateAccountCharsetNum err: ", err.Error()) 69 | } 70 | 71 | return false 72 | } 73 | -------------------------------------------------------------------------------- /timer/timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "context" 5 | "das_database/dao" 6 | "github.com/dotbitHQ/das-lib/core" 7 | "github.com/dotbitHQ/das-lib/http_api" 8 | "github.com/dotbitHQ/das-lib/http_api/logger" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var log = logger.NewLogger("timer", logger.LevelDebug) 14 | 15 | type ParserTimer struct { 16 | DbDao *dao.DbDao 17 | Ctx context.Context 18 | Wg *sync.WaitGroup 19 | DasCore *core.DasCore 20 | } 21 | 22 | func (p *ParserTimer) RunUpdateTokenPrice() { 23 | p.updateTokenMap() 24 | 25 | tickerToken := time.NewTicker(time.Second * 180) 26 | //tickerUSD := time.NewTicker(time.Second * 300) 27 | 28 | p.Wg.Add(1) 29 | go func() { 30 | defer http_api.RecoverPanic() 31 | for { 32 | select { 33 | case <-tickerToken.C: 34 | log.Debug("RunUpdateTokenPriceList start ...", time.Now().Format("2006-01-02 15:04:05")) 35 | p.updateTokenPriceInfoList() 36 | p.updateTokenMap() 37 | log.Debug("RunUpdateTokenPriceList end ...", time.Now().Format("2006-01-02 15:04:05")) 38 | //case <-tickerUSD.C: 39 | // log.Info("RunUpdateUSDRate start ...", time.Now().Format("2006-01-02 15:04:05")) 40 | // p.updateUSDRate() 41 | // log.Info("RunUpdateUSDRate end ...", time.Now().Format("2006-01-02 15:04:05")) 42 | case <-p.Ctx.Done(): 43 | p.Wg.Done() 44 | return 45 | } 46 | } 47 | }() 48 | } 49 | -------------------------------------------------------------------------------- /timer/timer_gecko.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/parnurzeal/gorequest" 7 | "github.com/shopspring/decimal" 8 | "net/http" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | type GeckoTokenInfo struct { 15 | Id string `json:"id"` 16 | Symbol string `json:"symbol"` 17 | Name string `json:"name"` 18 | ContractAddress string `json:"contract_address"` 19 | Links struct { 20 | Homepage []string `json:"homepage"` 21 | } `json:"links"` 22 | Image struct { 23 | Large string `json:"large"` 24 | } `json:"image"` 25 | Cny decimal.Decimal `json:"cny"` 26 | Price decimal.Decimal `json:"price"` 27 | Change24h decimal.Decimal `json:"change_24_h"` 28 | Vol24h decimal.Decimal `json:"vol_24_h"` 29 | MarketCap decimal.Decimal `json:"market_cap"` 30 | LastUpdatedAt int64 `json:"last_updated_at"` 31 | } 32 | 33 | // https://binance-docs.github.io/apidocs/spot/cn/#8ff46b58de 34 | func GetTokenPriceNew(ids []string) ([]GeckoTokenInfo, error) { 35 | var symbols []string 36 | symbols = append(symbols, "BTCUSDT", "CKBUSDT", "ETHUSDT", "TRXUSDT", "BNBUSDT", "DOGEUSDT", "POLUSDT") 37 | 38 | symbolStr := "" 39 | for _, v := range symbols { 40 | symbolStr += "%22" + v + "%22," 41 | } 42 | symbolStr = strings.Trim(symbolStr, ",") 43 | url := fmt.Sprintf("https://api1.binance.com/api/v3/ticker/price?symbols=[%s]", symbolStr) 44 | log.Info("GetTokenPriceNew:", url) 45 | 46 | var res []TokenPriceNew 47 | resp, body, errs := gorequest.New().Timeout(time.Second*30).Get(url).Retry(3, time.Second*2).End() 48 | if len(errs) > 0 { 49 | return nil, fmt.Errorf("GetTokenPrice api err:%v", errs) 50 | } else if resp.StatusCode != http.StatusOK { 51 | return nil, fmt.Errorf("GetTokenPrice api status code:%d", resp.StatusCode) 52 | } 53 | log.Info("GetTokenPriceNew:", body) 54 | if err := json.Unmarshal([]byte(body), &res); err != nil { 55 | return nil, err 56 | } 57 | list := TokenPriceNewToList(res) 58 | 59 | return list, nil 60 | } 61 | 62 | type TokenPriceNew struct { 63 | Symbol string `json:"symbol"` 64 | Price decimal.Decimal `json:"price"` 65 | } 66 | 67 | var TokenIdMap = map[string][]string{ 68 | "CKBUSDT": {"ckb_ckb", "ckb_ccc"}, 69 | "BTCUSDT": {"btc_btc"}, 70 | "ETHUSDT": {"eth_eth"}, 71 | "BNBUSDT": {"bsc_bnb"}, 72 | "TRXUSDT": {"tron_trx"}, 73 | "MATICUSDT": {"polygon_matic"}, 74 | "DOGEUSDT": {"doge_doge"}, 75 | "POLUSDT": {"polygon_pol"}, 76 | } 77 | 78 | func TokenPriceNewToList(res []TokenPriceNew) []GeckoTokenInfo { 79 | list := make([]GeckoTokenInfo, 0) 80 | for _, v := range res { 81 | now := time.Now().Unix() 82 | for _, tokenId := range TokenIdMap[v.Symbol] { 83 | list = append(list, GeckoTokenInfo{ 84 | Id: tokenId, 85 | Price: v.Price, 86 | LastUpdatedAt: now, 87 | }) 88 | } 89 | } 90 | return list 91 | } 92 | 93 | type Rate struct { 94 | Title string `gorm:"-" json:"-"` 95 | Name string `gorm:"column:name" json:"name"` 96 | Symbol string `gorm:"column:symbol" json:"symbol"` 97 | Value float64 `gorm:"column:value" json:"value"` 98 | CheckValue float64 `gorm:"-" json:"-"` 99 | } 100 | 101 | type ResultData struct { 102 | Result []struct { 103 | DisplayData struct { 104 | ResultData struct { 105 | TplData struct { 106 | Value string `json:"money2_num"` 107 | } `json:"tplData"` 108 | } `json:"resultData"` 109 | } `json:"DisplayData"` 110 | } `json:"Result"` 111 | } 112 | 113 | func GetCnyRate() (*Rate, error) { 114 | var rate = Rate{"", "CNY", "¥", 0, 1.5} 115 | url := "https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=1%E7%BE%8E%E5%85%83%E7%AD%89%E4%BA%8E%E5%A4%9A%E5%B0%91%E4%BA%BA%E6%B0%91%E5%B8%81&resource_id=5293&alr=1" 116 | 117 | var result ResultData 118 | res, _, errs := gorequest.New().Timeout(10 * time.Second).Get(url).EndStruct(&result) 119 | if errs != nil { 120 | return nil, fmt.Errorf("http req err: %v", errs) 121 | } 122 | if res.StatusCode != http.StatusOK { 123 | return nil, fmt.Errorf("http req err: %v", res.StatusCode) 124 | } 125 | if len(result.Result) > 0 { 126 | valueStr := strings.Replace(result.Result[0].DisplayData.ResultData.TplData.Value, ",", "", -1) 127 | if value, err := strconv.ParseFloat(valueStr, 64); err != nil { 128 | return nil, fmt.Errorf("json.Unmarshal err: %s", err.Error()) 129 | } else { 130 | rate.Value = value 131 | } 132 | } 133 | return &rate, nil 134 | } 135 | -------------------------------------------------------------------------------- /timer/timer_test.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "context" 5 | "das_database/config" 6 | "das_database/dao" 7 | "fmt" 8 | "github.com/scorpiotzh/toolib" 9 | "sync" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | func getInit() (*dao.DbDao, error) { 15 | if err := config.InitCfg("../config/config.yaml"); err != nil { 16 | return nil, fmt.Errorf("InitCfg err: %s", err) 17 | } 18 | cfgMysql := config.Cfg.DB.Mysql 19 | db, err := dao.NewGormDataBase(cfgMysql.Addr, cfgMysql.User, cfgMysql.Password, cfgMysql.DbName, cfgMysql.MaxOpenConn, cfgMysql.MaxIdleConn) 20 | if err != nil { 21 | return nil, fmt.Errorf("NewGormDataBase err:%s", err.Error()) 22 | } 23 | dbDao, err := dao.Initialize(db) 24 | if err != nil { 25 | return nil, fmt.Errorf("Initialize err:%s ", err.Error()) 26 | } 27 | return dbDao, nil 28 | } 29 | 30 | func TestGetTokenInfo(t *testing.T) { 31 | dbDao, err := getInit() 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | parserTimer := ParserTimer{ 36 | DbDao: dbDao, 37 | Ctx: context.Background(), 38 | Wg: &sync.WaitGroup{}, 39 | } 40 | parserTimer.RunUpdateTokenPrice() 41 | tokenInfo := GetTokenPriceInfo(TokenIdCkb) 42 | fmt.Println(toolib.JsonString(tokenInfo)) 43 | } 44 | 45 | func TestGetTokenPriceBinance(t *testing.T) { 46 | fmt.Println(GetTokenPriceNew(nil)) 47 | } 48 | 49 | func TestGetCnyRate(t *testing.T) { 50 | fmt.Println(GetCnyRate()) 51 | } 52 | 53 | func TestDailyRegister(t *testing.T) { 54 | fmt.Println(time.Now().Add(-time.Hour * 24).Format("2006-01-02")) 55 | 56 | now := time.Now() 57 | origin := time.Date(2021, 7, 22, 0, 0, 0, 0, time.Local) 58 | nowUnix := now.Unix() 59 | originUnix := origin.Unix() 60 | 61 | days := (nowUnix - originUnix) / (3600 * 24) 62 | for i := int64(0); i < days; i++ { 63 | fmt.Println(origin.Format("2006-01-02")) 64 | origin = origin.Add(time.Hour * 24) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /timer/timer_token.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "das_database/dao" 5 | "das_database/notify" 6 | "github.com/scorpiotzh/toolib" 7 | "github.com/shopspring/decimal" 8 | "sync" 9 | ) 10 | 11 | const ( 12 | TokenIdCkb = "ckb_ckb" 13 | TokenIdEth = "eth_eth" 14 | TokenIdTron = "tron_trx" 15 | ) 16 | 17 | var ( 18 | tokenLock sync.RWMutex 19 | mapToken map[string]dao.TableTokenPriceInfo 20 | ) 21 | 22 | func (p *ParserTimer) updateTokenMap() { 23 | list, err := p.DbDao.SearchTokenPriceInfoList() 24 | if err != nil { 25 | log.Errorf("SearchTokenPriceInfoList err:%s", err.Error()) 26 | } 27 | 28 | tokenLock.Lock() 29 | defer tokenLock.Unlock() 30 | mapToken = make(map[string]dao.TableTokenPriceInfo, 0) 31 | for i, v := range list { 32 | mapToken[v.TokenId] = list[i] 33 | } 34 | } 35 | 36 | func GetTokenPriceInfo(tokenId string) dao.TableTokenPriceInfo { 37 | tokenLock.RLock() 38 | defer tokenLock.RUnlock() 39 | t, _ := mapToken[tokenId] 40 | return t 41 | } 42 | 43 | func GetTokenPriceInfoList() map[string]dao.TableTokenPriceInfo { 44 | tokenLock.Lock() 45 | defer tokenLock.Unlock() 46 | return mapToken 47 | } 48 | 49 | func (p *ParserTimer) updateTokenPriceInfoList() { 50 | var geckoIds []string 51 | if list, err := p.DbDao.SearchTokenPriceInfoList(); err != nil { 52 | log.Error("SearchTokenPriceInfoList err:", err.Error()) 53 | } else { 54 | for _, v := range list { 55 | geckoIds = append(geckoIds, v.GeckoId) 56 | } 57 | } 58 | 59 | if list, err := GetTokenPriceNew(geckoIds); err != nil { 60 | log.Error("GetTokenPriceNew err:", err.Error()) 61 | notify.SendLarkErrNotify("GetTokenPriceNew", err.Error()) 62 | } else { 63 | var tokenList []dao.TableTokenPriceInfo 64 | for _, v := range list { 65 | tokenList = append(tokenList, dao.TableTokenPriceInfo{ 66 | TokenId: v.Id, 67 | Price: v.Price, 68 | LastUpdatedAt: v.LastUpdatedAt, 69 | }) 70 | } 71 | if err := p.DbDao.UpdateTokenPriceInfoList(tokenList); err != nil { 72 | log.Error("UpdateTokenPriceInfoList err:", err.Error()) 73 | } 74 | } 75 | } 76 | 77 | func (p *ParserTimer) updateUSDRate() { 78 | rate, err := GetCnyRate() 79 | if err != nil { 80 | log.Error("GetCnyRate err: ", err.Error()) 81 | notify.SendLarkErrNotify("GetCnyRate", err.Error()) 82 | } 83 | log.Info("updateUSDRate:", toolib.JsonString(&rate)) 84 | if rate != nil && rate.Value > 0 { 85 | dec := decimal.NewFromInt(1).DivRound(decimal.NewFromFloat(rate.Value), 4) 86 | if err = p.DbDao.UpdateCNYToUSDRate([]string{"wx_cny"}, dec); err != nil { 87 | log.Errorf("UpdateCNYToUSDRate err:%s", err) 88 | } 89 | } 90 | } 91 | --------------------------------------------------------------------------------