├── .circleci └── config.yml ├── .dockerignore ├── .gitignore ├── CHANGELOG.md ├── CHANGEV2.md ├── COPYING ├── README.md ├── abci ├── app │ ├── app.go │ └── v1 │ │ ├── aal.go │ │ ├── app.go │ │ ├── as_service.go │ │ ├── as_service_price.go │ │ ├── chain.go │ │ ├── check_tx.go │ │ ├── common.go │ │ ├── custom_error.go │ │ ├── deliver_tx.go │ │ ├── error_code.go │ │ ├── helper.go │ │ ├── ial.go │ │ ├── identity.go │ │ ├── message.go │ │ ├── namespace.go │ │ ├── ndid.go │ │ ├── ndid_chain.go │ │ ├── ndid_error_code.go │ │ ├── ndid_identity.go │ │ ├── ndid_namespace.go │ │ ├── ndid_node.go │ │ ├── ndid_request.go │ │ ├── ndid_service.go │ │ ├── ndid_service_price.go │ │ ├── node.go │ │ ├── node_supported_feature.go │ │ ├── prometheus.go │ │ ├── query.go │ │ ├── request.go │ │ ├── request_as.go │ │ ├── request_idp.go │ │ ├── request_type.go │ │ ├── service.go │ │ ├── state.go │ │ ├── state_initial.go │ │ ├── state_test.go │ │ ├── suppress_node_identity_modification_notification.go │ │ ├── token.go │ │ ├── types │ │ ├── node_role.go │ │ └── signature_algorithm.go │ │ └── validator.go ├── code │ └── code.go ├── commands.go ├── server.go ├── utils │ ├── map.go │ └── utils.go └── version │ └── version.go ├── config └── tendermint │ ├── AS │ └── config │ │ ├── config.toml │ │ ├── genesis.json │ │ ├── node_key.json │ │ └── priv_validator_key.json │ ├── IdP │ └── config │ │ ├── config.toml │ │ ├── genesis.json │ │ ├── node_key.json │ │ └── priv_validator_key.json │ ├── RP │ └── config │ │ ├── config.toml │ │ ├── genesis.json │ │ ├── node_key.json │ │ └── priv_validator_key.json │ └── proxy │ └── config │ ├── config.toml │ ├── genesis.json │ ├── node_key.json │ └── priv_validator_key.json ├── docker ├── Dockerfile ├── build.sh ├── buildx.sh ├── docker-compose.build.yml ├── docker-compose.test_dev.yml ├── docker-compose.yml ├── docker-entrypoint.sh └── start-node.sh ├── go.mod ├── go.sum ├── patches ├── tm_cleveldb_cache_and_bloom_filter.patch └── tm_goleveldb_bloom_filter.patch ├── protos ├── data │ ├── data.pb.go │ └── data.proto ├── gen_proto_go.sh ├── param │ ├── param.pb.go │ └── param.proto └── tendermint │ ├── tendermint.pb.go │ └── tendermint.proto ├── scripts ├── run_dev.sh ├── run_dev_as.sh ├── run_dev_as_no_reset.sh ├── run_dev_idp.sh ├── run_dev_idp_no_reset.sh ├── run_dev_no_reset.sh ├── run_dev_proxy.sh ├── run_dev_proxy_no_reset.sh ├── run_dev_rp.sh └── run_dev_rp_no_reset.sh └── test ├── as └── as.go ├── common └── common.go ├── data └── data.go ├── idp └── idp.go ├── main_test.go ├── ndid └── ndid.go ├── query └── query.go └── utils └── utils.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: cimg/go:1.22 6 | working_directory: ~/ndidplatform/smart-contract 7 | steps: 8 | - checkout 9 | - run: 10 | name: Install tools, snappy, and leveldb 11 | command: | 12 | sudo apt-get update && sudo apt-get install -y --no-install-recommends \ 13 | g++ \ 14 | gcc \ 15 | make \ 16 | git \ 17 | libsnappy-dev \ 18 | libleveldb-dev \ 19 | ca-certificates 20 | # - run: 21 | # name: Install LevelDB 22 | # command: | 23 | # wget -q https://github.com/google/leveldb/archive/v1.20.tar.gz && \ 24 | # tar -zxvf v1.20.tar.gz && \ 25 | # cd leveldb-1.20/ && \ 26 | # make 27 | # sudo cp -r out-static/lib* out-shared/lib* /usr/local/lib/ && \ 28 | # sudo mkdir -p /usr/local/include/leveldb && \ 29 | # sudo cp -r include/leveldb /usr/local/include/ && \ 30 | # sudo ldconfig /usr/local/lib 31 | - run: 32 | name: Download go modules 33 | command: | 34 | go mod download 35 | - run: 36 | name: Build Tendermint with ABCI app 37 | command: | 38 | go build \ 39 | -ldflags "-X github.com/ndidplatform/smart-contract/v9/abci/version.GitCommit=`git rev-parse --short=8 HEAD`" \ 40 | -tags "cleveldb" \ 41 | -o ./did-tendermint \ 42 | ./abci 43 | - run: 44 | name: Reset Tendermint data 45 | command: | 46 | ABCI_DB_DIR_PATH=abci_db ./did-tendermint --home ./config/tendermint/IdP unsafe-reset-all 47 | - run: 48 | name: Start Tendermint with ABCI app 49 | command: | 50 | ABCI_DB_DIR_PATH=abci_db ./did-tendermint --home ./config/tendermint/IdP node 51 | background: true 52 | 53 | - run: sleep 15 54 | - run: 55 | name: Test ABCI app 56 | command: | 57 | cd test 58 | TENDERMINT_ADDRESS=http://localhost:45000 go test -v 59 | push_to_docker_hub: 60 | docker: 61 | - image: cimg/base:stable 62 | steps: 63 | - checkout 64 | - setup_remote_docker: 65 | version: 20.10.11 66 | - run: 67 | name: Build docker images 68 | command: | 69 | cd docker 70 | REPO_NAME=${REPO_NAME:-$DOCKER_USER} 71 | DOCKER_TAG=${DOCKER_TAG:-latest} 72 | ./build.sh 73 | - run: 74 | name: Push to docker hub 75 | command: | 76 | if [ ! "$DOCKER_USER" -o ! "$DOCKER_PASS" ] 77 | then 78 | echo "Missing required environment variables" 79 | echo "- DOCKER_USER" 80 | echo "- DOCKER_PASS" 81 | exit 1 82 | fi 83 | REPO_NAME=${REPO_NAME:-$DOCKER_USER} 84 | DOCKER_TAG=${DOCKER_TAG:-latest} 85 | docker login -u $DOCKER_USER -p $DOCKER_PASS 86 | docker push $REPO_NAME/did-tendermint:$DOCKER_TAG 87 | push_dev_to_docker_hub: 88 | docker: 89 | - image: cimg/base:stable 90 | steps: 91 | - checkout 92 | - setup_remote_docker: 93 | version: 20.10.11 94 | - run: 95 | name: Build docker images 96 | command: | 97 | cd docker 98 | REPO_NAME=${REPO_NAME:-$DOCKER_USER} 99 | DOCKER_TAG=${DOCKER_TAG_DEV:-development} 100 | ./build.sh 101 | - run: 102 | name: Push to docker hub 103 | command: | 104 | if [ ! "$DOCKER_USER" -o ! "$DOCKER_PASS" ] 105 | then 106 | echo "Missing required environment variables" 107 | echo "- DOCKER_USER" 108 | echo "- DOCKER_PASS" 109 | exit 1 110 | fi 111 | REPO_NAME=${REPO_NAME:-$DOCKER_USER} 112 | DOCKER_TAG=${DOCKER_TAG_DEV:-development} 113 | docker login -u $DOCKER_USER -p $DOCKER_PASS 114 | docker push $REPO_NAME/did-tendermint:$DOCKER_TAG 115 | workflows: 116 | version: 2 117 | build_and_deploy: 118 | jobs: 119 | - build 120 | - push_to_docker_hub: 121 | filters: 122 | branches: 123 | only: master 124 | requires: 125 | - build 126 | - push_dev_to_docker_hub: 127 | filters: 128 | branches: 129 | only: development 130 | requires: 131 | - build -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | 2 | # misc 3 | .DS_Store 4 | 5 | *.swp 6 | 7 | main.go 8 | 9 | # localDB 10 | localDB/ 11 | vendor/ 12 | 13 | # tendermint data 14 | config/tendermint/IdP/data/ 15 | config/tendermint/RP/data/ 16 | config/tendermint/AS/data/ 17 | config/tendermint/IdP/config/* 18 | config/tendermint/RP/config/* 19 | config/tendermint/AS/config/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | 3 | # misc 4 | .DS_Store 5 | 6 | *.swp 7 | 8 | build/ 9 | 10 | # localDB 11 | localDB/ 12 | IdP_DB/ 13 | RP_DB/ 14 | AS_DB/ 15 | tmp/ 16 | 17 | # dependencies 18 | vendor/ 19 | 20 | # tendermint data 21 | config/tendermint/IdP/data/ 22 | config/tendermint/RP/data/ 23 | config/tendermint/AS/data/ 24 | config/tendermint/proxy/data/ 25 | config/tendermint/IdP/config/addrbook.json 26 | config/tendermint/RP/config/addrbook.json 27 | config/tendermint/AS/config/addrbook.json 28 | config/tendermint/proxy/config/addrbook.json 29 | config/tendermint/IdP/config/write-file-atomic* 30 | config/tendermint/RP/config/write-file-atomic* 31 | config/tendermint/AS/config/write-file-atomic* 32 | config/tendermint/proxy/config/write-file-atomic* -------------------------------------------------------------------------------- /abci/app/app.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "context" 27 | "fmt" 28 | "os" 29 | "strconv" 30 | 31 | dbm "github.com/cometbft/cometbft-db" 32 | abcitypes "github.com/cometbft/cometbft/abci/types" 33 | tmos "github.com/cometbft/cometbft/libs/os" 34 | "github.com/sirupsen/logrus" 35 | 36 | appV1 "github.com/ndidplatform/smart-contract/v9/abci/app/v1" 37 | // appV2 "github.com/ndidplatform/smart-contract/v9/abci/app2/v2" 38 | ) 39 | 40 | type ABCIApplicationInterface struct { 41 | appV1 *appV1.ABCIApplication 42 | // appV2 *appV2.ABCIApplication 43 | CurrentBlockHeight int64 44 | } 45 | 46 | func NewABCIApplicationInterface() *ABCIApplicationInterface { 47 | logger := logrus.WithFields(logrus.Fields{"module": "abci-app"}) 48 | 49 | var dbType = getEnv("ABCI_DB_TYPE", "goleveldb") 50 | var dbDir = getEnv("ABCI_DB_DIR_PATH", "./DID") 51 | 52 | if err := tmos.EnsureDir(dbDir, 0700); err != nil { 53 | panic(fmt.Errorf("could not create DB directory: %v", err.Error())) 54 | } 55 | name := "didDB" 56 | db, err := dbm.NewDB(name, dbm.BackendType(dbType), dbDir) 57 | if err != nil { 58 | panic(fmt.Errorf("could not create DB instance: %v", err.Error())) 59 | } 60 | 61 | var initialStateDir = getEnv("ABCI_INITIAL_STATE_DIR_PATH", "") 62 | 63 | var retainBlockCountStr = getEnv("TENDERMINT_RETAIN_BLOCK_COUNT", "") 64 | var retainBlockCount int64 65 | if retainBlockCountStr == "" { 66 | retainBlockCount = 0 67 | } else { 68 | retainBlockCount, err = strconv.ParseInt(retainBlockCountStr, 10, 64) 69 | if err != nil { 70 | panic(fmt.Errorf("could not parse TENDERMINT_RETAIN_BLOCK_COUNT: %v", err.Error())) 71 | } 72 | } 73 | 74 | return &ABCIApplicationInterface{ 75 | appV1: appV1.NewABCIApplication(logger, db, initialStateDir, retainBlockCount), 76 | // appV2: appV2.NewABCIApplication(logger, db, initialStateDir, retainBlockCount), 77 | } 78 | } 79 | 80 | func (app *ABCIApplicationInterface) Info(_ context.Context, info *abcitypes.RequestInfo) (*abcitypes.ResponseInfo, error) { 81 | return app.appV1.Info(info) 82 | } 83 | 84 | func (app *ABCIApplicationInterface) CheckTx(_ context.Context, check *abcitypes.RequestCheckTx) (*abcitypes.ResponseCheckTx, error) { 85 | // IMPORTANT: Need to move app state load to this struct level if using multiple ABCI app versions 86 | // otherwise app.CurrentBlockHeight will always be 0 on process start 87 | switch { 88 | case app.CurrentBlockHeight >= 0: 89 | return app.appV1.CheckTx(check) 90 | default: 91 | return app.appV1.CheckTx(check) 92 | } 93 | } 94 | 95 | func (app *ABCIApplicationInterface) FinalizeBlock(_ context.Context, req *abcitypes.RequestFinalizeBlock) (*abcitypes.ResponseFinalizeBlock, error) { 96 | app.CurrentBlockHeight = req.Height 97 | switch { 98 | case app.CurrentBlockHeight >= 0: 99 | return app.appV1.FinalizeBlock(req) 100 | default: 101 | return app.appV1.FinalizeBlock(req) 102 | } 103 | } 104 | 105 | func (app *ABCIApplicationInterface) Commit(_ context.Context, commit *abcitypes.RequestCommit) (*abcitypes.ResponseCommit, error) { 106 | return app.appV1.Commit(commit) 107 | } 108 | 109 | func (app *ABCIApplicationInterface) Query(_ context.Context, req *abcitypes.RequestQuery) (*abcitypes.ResponseQuery, error) { 110 | return app.appV1.Query(req) 111 | } 112 | 113 | func (app *ABCIApplicationInterface) InitChain(_ context.Context, chain *abcitypes.RequestInitChain) (*abcitypes.ResponseInitChain, error) { 114 | return app.appV1.InitChain(chain) 115 | } 116 | 117 | func (app *ABCIApplicationInterface) PrepareProposal(ctx context.Context, proposal *abcitypes.RequestPrepareProposal) (*abcitypes.ResponsePrepareProposal, error) { 118 | return app.appV1.PrepareProposal(ctx, proposal) 119 | } 120 | 121 | func (app *ABCIApplicationInterface) ProcessProposal(ctx context.Context, proposal *abcitypes.RequestProcessProposal) (*abcitypes.ResponseProcessProposal, error) { 122 | return app.appV1.ProcessProposal(ctx, proposal) 123 | } 124 | 125 | func (app *ABCIApplicationInterface) ListSnapshots(ctx context.Context, snapshots *abcitypes.RequestListSnapshots) (*abcitypes.ResponseListSnapshots, error) { 126 | return app.appV1.ListSnapshots(ctx, snapshots) 127 | } 128 | 129 | func (app *ABCIApplicationInterface) OfferSnapshot(ctx context.Context, snapshot *abcitypes.RequestOfferSnapshot) (*abcitypes.ResponseOfferSnapshot, error) { 130 | return app.appV1.OfferSnapshot(ctx, snapshot) 131 | } 132 | 133 | func (app *ABCIApplicationInterface) LoadSnapshotChunk(ctx context.Context, chunk *abcitypes.RequestLoadSnapshotChunk) (*abcitypes.ResponseLoadSnapshotChunk, error) { 134 | return app.appV1.LoadSnapshotChunk(ctx, chunk) 135 | } 136 | 137 | func (app *ABCIApplicationInterface) ApplySnapshotChunk(ctx context.Context, chunk *abcitypes.RequestApplySnapshotChunk) (*abcitypes.ResponseApplySnapshotChunk, error) { 138 | return app.appV1.ApplySnapshotChunk(ctx, chunk) 139 | } 140 | 141 | func (app ABCIApplicationInterface) ExtendVote(ctx context.Context, extend *abcitypes.RequestExtendVote) (*abcitypes.ResponseExtendVote, error) { 142 | return app.appV1.ExtendVote(ctx, extend) 143 | } 144 | 145 | func (app *ABCIApplicationInterface) VerifyVoteExtension(ctx context.Context, verify *abcitypes.RequestVerifyVoteExtension) (*abcitypes.ResponseVerifyVoteExtension, error) { 146 | return app.appV1.VerifyVoteExtension(ctx, verify) 147 | } 148 | 149 | func getEnv(key, defaultValue string) string { 150 | value, exists := os.LookupEnv(key) 151 | if !exists { 152 | value = defaultValue 153 | } 154 | return value 155 | } 156 | -------------------------------------------------------------------------------- /abci/app/v1/aal.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | "google.golang.org/protobuf/proto" 30 | 31 | "github.com/ndidplatform/smart-contract/v9/abci/code" 32 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 33 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 34 | ) 35 | 36 | type SetSupportedAALListParam struct { 37 | SupportedAALList []float64 `json:"supported_aal_list"` 38 | } 39 | 40 | func (app *ABCIApplication) validateSetSupportedAALList(funcParam SetSupportedAALListParam, callerNodeID string, committedState bool, checkTx bool) error { 41 | // permission 42 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 43 | if err != nil { 44 | return err 45 | } 46 | if !ok { 47 | return &ApplicationError{ 48 | Code: code.NoPermissionForCallNDIDMethod, 49 | Message: "This node does not have permission to call NDID method", 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func (app *ABCIApplication) setSupportedAALListCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 57 | var funcParam SetSupportedAALListParam 58 | err := json.Unmarshal(param, &funcParam) 59 | if err != nil { 60 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 61 | } 62 | 63 | err = app.validateSetSupportedAALList(funcParam, callerNodeID, true, true) 64 | if err != nil { 65 | if appErr, ok := err.(*ApplicationError); ok { 66 | return NewResponseCheckTx(appErr.Code, appErr.Message) 67 | } 68 | return NewResponseCheckTx(code.UnknownError, err.Error()) 69 | } 70 | 71 | return NewResponseCheckTx(code.OK, "") 72 | } 73 | 74 | func (app *ABCIApplication) setSupportedAALList(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 75 | app.logger.Infof("SetSupportedAALList, Parameter: %s", param) 76 | var funcParam SetSupportedAALListParam 77 | err := json.Unmarshal(param, &funcParam) 78 | if err != nil { 79 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 80 | } 81 | 82 | err = app.validateSetSupportedAALList(funcParam, callerNodeID, false, false) 83 | if err != nil { 84 | if appErr, ok := err.(*ApplicationError); ok { 85 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 86 | } 87 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 88 | } 89 | 90 | var supportedAALList data.SupportedAALList 91 | supportedAALList.AalList = funcParam.SupportedAALList 92 | supportedAALListByte, err := utils.ProtoDeterministicMarshal(&supportedAALList) 93 | if err != nil { 94 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 95 | } 96 | app.state.Set(supportedAALListKeyBytes, supportedAALListByte) 97 | return app.NewExecTxResult(code.OK, "success", "") 98 | } 99 | 100 | // type GetSupportedAALListParam struct { 101 | // } 102 | 103 | type GetSupportedAALListResult struct { 104 | SupportedAALList []float64 `json:"supported_aal_list"` 105 | } 106 | 107 | func (app *ABCIApplication) GetSupportedAALList(param []byte, committedState bool) *abcitypes.ResponseQuery { 108 | app.logger.Infof("GetSupportedAALList, Parameter: %s", param) 109 | // var funcParam GetSupportedAALListParam 110 | // err := json.Unmarshal(param, &funcParam) 111 | // if err != nil { 112 | // return app.NewResponseQuery(nil, err.Error(), app.state.Height) 113 | // } 114 | 115 | var result GetSupportedAALListResult 116 | result.SupportedAALList = make([]float64, 0) 117 | 118 | supportedAALValue, err := app.state.Get(supportedAALListKeyBytes, committedState) 119 | if err != nil { 120 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 121 | } 122 | if supportedAALValue == nil { 123 | resultJSON, err := json.Marshal(result) 124 | if err != nil { 125 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 126 | } 127 | 128 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 129 | } 130 | 131 | var supportedAALList data.SupportedAALList 132 | err = proto.Unmarshal(supportedAALValue, &supportedAALList) 133 | if err != nil { 134 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 135 | } 136 | 137 | result.SupportedAALList = supportedAALList.AalList 138 | 139 | resultJSON, err := json.Marshal(result) 140 | if err != nil { 141 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 142 | } 143 | 144 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 145 | } 146 | -------------------------------------------------------------------------------- /abci/app/v1/chain.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | ) 30 | 31 | type IsInitEndedResult struct { 32 | InitEnded bool `json:"init_ended"` 33 | } 34 | 35 | func (app *ABCIApplication) isInitEnded(param []byte) *abcitypes.ResponseQuery { 36 | app.logger.Infof("IsInitEnded, Parameter: %s", param) 37 | var result IsInitEndedResult 38 | result.InitEnded = false 39 | value, err := app.state.Get(initStateKeyBytes, true) 40 | if err != nil { 41 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 42 | } 43 | if string(value) == "false" { 44 | result.InitEnded = true 45 | } 46 | returnValue, err := json.Marshal(result) 47 | if err != nil { 48 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 49 | } 50 | return app.NewResponseQuery(returnValue, "success", app.state.Height) 51 | } 52 | 53 | func (app *ABCIApplication) getChainHistory(param []byte) *abcitypes.ResponseQuery { 54 | app.logger.Infof("GetChainHistory, Parameter: %s", param) 55 | chainHistoryInfoKey := "ChainHistoryInfo" 56 | value, err := app.state.Get([]byte(chainHistoryInfoKey), true) 57 | if err != nil { 58 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 59 | } 60 | return app.NewResponseQuery(value, "success", app.state.Height) 61 | } 62 | -------------------------------------------------------------------------------- /abci/app/v1/common.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | var modeFunctionMap = map[string]bool{ 26 | "RegisterIdentity": true, 27 | "AddIdentity": true, 28 | "AddAccessor": true, 29 | "RevokeAccessor": true, 30 | "RevokeIdentityAssociation": true, 31 | "UpdateIdentityModeList": true, 32 | "RevokeAndAddAccessor": true, 33 | } 34 | 35 | var ( 36 | masterNDIDKeyBytes = []byte("MasterNDID") 37 | initStateKeyBytes = []byte("InitState") 38 | lastBlockKeyBytes = []byte("lastBlock") 39 | idpListKeyBytes = []byte("IdPList") 40 | allNamespaceKeyBytes = []byte("AllNamespace") 41 | servicePriceMinEffectiveDatetimeDelayKeyBytes = []byte("ServicePriceMinEffectiveDatetimeDelay") 42 | supportedIALListKeyBytes = []byte("SupportedIALList") 43 | supportedAALListKeyBytes = []byte("SupportedAALList") 44 | ) 45 | 46 | const ( 47 | keySeparator = "|" 48 | nonceKeyPrefix = "n" 49 | nodeIDKeyPrefix = "NodeID" 50 | nodeKeyKeyPrefix = "NodeKey" 51 | behindProxyNodeKeyPrefix = "BehindProxyNode" 52 | tokenKeyPrefix = "Token" 53 | tokenPriceFuncKeyPrefix = "TokenPriceFunc" 54 | serviceKeyPrefix = "Service" 55 | serviceDestinationKeyPrefix = "ServiceDestination" 56 | approvedServiceKeyPrefix = "ApproveKey" 57 | providedServicesKeyPrefix = "ProvideService" 58 | refGroupCodeKeyPrefix = "RefGroupCode" 59 | identityToRefCodeKeyPrefix = "identityToRefCodeKey" 60 | accessorToRefCodeKeyPrefix = "accessorToRefCodeKey" 61 | allowedModeListKeyPrefix = "AllowedModeList" 62 | requestKeyPrefix = "Request" 63 | messageKeyPrefix = "Message" 64 | dataSignatureKeyPrefix = "SignData" 65 | errorCodeKeyPrefix = "ErrorCode" 66 | errorCodeListKeyPrefix = "ErrorCodeList" 67 | servicePriceCeilingKeyPrefix = "ServicePriceCeiling" 68 | servicePriceMinEffectiveDatetimeDelayKeyPrefix = "ServicePriceMinEffectiveDatetimeDelay" 69 | servicePriceListKeyPrefix = "ServicePriceListKey" 70 | requestTypeKeyPrefix = "RequestType" 71 | suppressedIdentityModificationNotificationNodePrefix = "SuppressedIdentityModificationNotificationNode" 72 | nodeSupportedFeatureKeyPrefix = "NodeSupportedFeature" 73 | validatorKeyPrefix = "Validator" 74 | ) 75 | -------------------------------------------------------------------------------- /abci/app/v1/custom_error.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | type ApplicationError struct { 4 | Code uint32 5 | Message string 6 | } 7 | 8 | func (e *ApplicationError) Error() string { 9 | return e.Message 10 | } 11 | -------------------------------------------------------------------------------- /abci/app/v1/error_code.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | "strings" 28 | 29 | "google.golang.org/protobuf/proto" 30 | 31 | abcitypes "github.com/cometbft/cometbft/abci/types" 32 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 33 | ) 34 | 35 | type GetErrorCodeListParam struct { 36 | Type string `json:"type"` 37 | } 38 | 39 | type GetErrorCodeListResult struct { 40 | ErrorCode int32 `json:"error_code"` 41 | Description string `json:"description"` 42 | } 43 | 44 | func (app *ABCIApplication) getErrorCodeList(param []byte) *abcitypes.ResponseQuery { 45 | var funcParam GetErrorCodeListParam 46 | err := json.Unmarshal(param, &funcParam) 47 | if err != nil { 48 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 49 | } 50 | 51 | // convert funcParam to lowercase and fetch the code list 52 | funcParam.Type = strings.ToLower(funcParam.Type) 53 | errorCodeListKey := errorCodeListKeyPrefix + keySeparator + funcParam.Type 54 | errorCodeListBytes, err := app.state.Get([]byte(errorCodeListKey), false) 55 | if err != nil { 56 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 57 | } 58 | 59 | var errorCodeList data.ErrorCodeList 60 | err = proto.Unmarshal(errorCodeListBytes, &errorCodeList) 61 | if err != nil { 62 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 63 | } 64 | 65 | // parse result into response format 66 | result := make([]*GetErrorCodeListResult, 0, len(errorCodeList.ErrorCode)) 67 | for _, errorCode := range errorCodeList.ErrorCode { 68 | result = append(result, &GetErrorCodeListResult{ 69 | ErrorCode: errorCode.ErrorCode, 70 | Description: errorCode.Description, 71 | }) 72 | } 73 | 74 | returnValue, err := json.Marshal(result) 75 | if err != nil { 76 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 77 | } 78 | return app.NewResponseQuery(returnValue, "success", app.state.Height) 79 | } 80 | -------------------------------------------------------------------------------- /abci/app/v1/helper.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | func contains(a string, list []string) bool { 26 | for _, b := range list { 27 | if b == a { 28 | return true 29 | } 30 | } 31 | return false 32 | } 33 | 34 | func containsInt32(a int32, list []int32) bool { 35 | for _, b := range list { 36 | if b == a { 37 | return true 38 | } 39 | } 40 | return false 41 | } 42 | 43 | func MaxInt32(v []int32) int32 { 44 | var m int32 45 | for i, e := range v { 46 | if i == 0 || e < m { 47 | m = e 48 | } 49 | } 50 | return m 51 | } 52 | -------------------------------------------------------------------------------- /abci/app/v1/ial.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | "google.golang.org/protobuf/proto" 30 | 31 | "github.com/ndidplatform/smart-contract/v9/abci/code" 32 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 33 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 34 | ) 35 | 36 | type SetSupportedIALListParam struct { 37 | SupportedIALList []float64 `json:"supported_ial_list"` 38 | } 39 | 40 | func (app *ABCIApplication) validateSetSupportedIALList(funcParam SetSupportedIALListParam, callerNodeID string, committedState bool, checktx bool) error { 41 | // permission 42 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 43 | if err != nil { 44 | return err 45 | } 46 | if !ok { 47 | return &ApplicationError{ 48 | Code: code.NoPermissionForCallNDIDMethod, 49 | Message: "This node does not have permission to call NDID method", 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func (app *ABCIApplication) setSupportedIALListCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 57 | var funcParam SetSupportedIALListParam 58 | err := json.Unmarshal(param, &funcParam) 59 | if err != nil { 60 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 61 | } 62 | 63 | err = app.validateSetSupportedIALList(funcParam, callerNodeID, true, true) 64 | if err != nil { 65 | if appErr, ok := err.(*ApplicationError); ok { 66 | return NewResponseCheckTx(appErr.Code, appErr.Message) 67 | } 68 | return NewResponseCheckTx(code.UnknownError, err.Error()) 69 | } 70 | 71 | return NewResponseCheckTx(code.OK, "") 72 | } 73 | 74 | func (app *ABCIApplication) setSupportedIALList(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 75 | app.logger.Infof("SetSupportedIALList, Parameter: %s", param) 76 | var funcParam SetSupportedIALListParam 77 | err := json.Unmarshal(param, &funcParam) 78 | if err != nil { 79 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 80 | } 81 | 82 | err = app.validateSetSupportedIALList(funcParam, callerNodeID, false, false) 83 | if err != nil { 84 | if appErr, ok := err.(*ApplicationError); ok { 85 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 86 | } 87 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 88 | } 89 | 90 | var supportedIALList data.SupportedIALList 91 | supportedIALList.IalList = funcParam.SupportedIALList 92 | supportedIALListByte, err := utils.ProtoDeterministicMarshal(&supportedIALList) 93 | if err != nil { 94 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 95 | } 96 | app.state.Set(supportedIALListKeyBytes, supportedIALListByte) 97 | return app.NewExecTxResult(code.OK, "success", "") 98 | } 99 | 100 | // type GetSupportedIALListParam struct { 101 | // } 102 | 103 | type GetSupportedIALListResult struct { 104 | SupportedIALList []float64 `json:"supported_ial_list"` 105 | } 106 | 107 | func (app *ABCIApplication) GetSupportedIALList(param []byte, committedState bool) *abcitypes.ResponseQuery { 108 | app.logger.Infof("GetSupportedIALList, Parameter: %s", param) 109 | // var funcParam GetSupportedIALListParam 110 | // err := json.Unmarshal(param, &funcParam) 111 | // if err != nil { 112 | // return app.NewResponseQuery(nil, err.Error(), app.state.Height) 113 | // } 114 | 115 | var result GetSupportedIALListResult 116 | result.SupportedIALList = make([]float64, 0) 117 | 118 | supportedIALValue, err := app.state.Get(supportedIALListKeyBytes, committedState) 119 | if err != nil { 120 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 121 | } 122 | if supportedIALValue == nil { 123 | resultJSON, err := json.Marshal(result) 124 | if err != nil { 125 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 126 | } 127 | 128 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 129 | } 130 | 131 | var supportedIALList data.SupportedIALList 132 | err = proto.Unmarshal(supportedIALValue, &supportedIALList) 133 | if err != nil { 134 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 135 | } 136 | 137 | result.SupportedIALList = supportedIALList.IalList 138 | 139 | resultJSON, err := json.Marshal(result) 140 | if err != nil { 141 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 142 | } 143 | 144 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 145 | } 146 | -------------------------------------------------------------------------------- /abci/app/v1/message.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | "google.golang.org/protobuf/proto" 30 | 31 | "github.com/ndidplatform/smart-contract/v9/abci/code" 32 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 33 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 34 | ) 35 | 36 | type CreateMessageParam struct { 37 | MessageID string `json:"message_id"` 38 | Message string `json:"message"` 39 | Purpose string `json:"purpose"` 40 | } 41 | 42 | func (app *ABCIApplication) validateCreateMessage(funcParam CreateMessageParam, callerNodeID string, committedState bool, checktx bool) error { 43 | // permission 44 | ok, err := app.isRPNodeByNodeID(callerNodeID, committedState) 45 | if err != nil { 46 | return err 47 | } 48 | if !ok { 49 | return &ApplicationError{ 50 | Code: code.NoPermissionForCallRPMethod, 51 | Message: "This node does not have permission to call RP method", 52 | } 53 | } 54 | 55 | return nil 56 | } 57 | 58 | func (app *ABCIApplication) createMessageCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 59 | var funcParam CreateMessageParam 60 | err := json.Unmarshal(param, &funcParam) 61 | if err != nil { 62 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 63 | } 64 | 65 | err = app.validateCreateMessage(funcParam, callerNodeID, true, true) 66 | if err != nil { 67 | if appErr, ok := err.(*ApplicationError); ok { 68 | return NewResponseCheckTx(appErr.Code, appErr.Message) 69 | } 70 | return NewResponseCheckTx(code.UnknownError, err.Error()) 71 | } 72 | 73 | return NewResponseCheckTx(code.OK, "") 74 | } 75 | 76 | func (app *ABCIApplication) createMessage(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 77 | app.logger.Infof("CreateMessage, Parameter: %s", param) 78 | var funcParam CreateMessageParam 79 | err := json.Unmarshal(param, &funcParam) 80 | if err != nil { 81 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 82 | } 83 | 84 | err = app.validateCreateMessage(funcParam, callerNodeID, false, false) 85 | if err != nil { 86 | if appErr, ok := err.(*ApplicationError); ok { 87 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 88 | } 89 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 90 | } 91 | 92 | // log chain ID 93 | app.logger.Infof("CreateMessage, Chain ID: %s", app.CurrentChain) 94 | var message data.Message 95 | // set request data 96 | message.MessageId = funcParam.MessageID 97 | 98 | key := messageKeyPrefix + keySeparator + message.MessageId 99 | messageIDExist, err := app.state.Has([]byte(key), false) 100 | if err != nil { 101 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 102 | } 103 | if messageIDExist { 104 | return app.NewExecTxResult(code.DuplicateMessageID, "Duplicate message ID", "") 105 | } 106 | 107 | message.Message = funcParam.Message 108 | message.Purpose = funcParam.Purpose 109 | 110 | // set Owner 111 | message.Owner = callerNodeID 112 | // set creation_block_height 113 | message.CreationBlockHeight = app.state.CurrentBlockHeight 114 | // set chain_id 115 | message.ChainId = app.CurrentChain 116 | 117 | value, err := utils.ProtoDeterministicMarshal(&message) 118 | if err != nil { 119 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 120 | } 121 | app.state.Set([]byte(key), []byte(value)) 122 | if err != nil { 123 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 124 | } 125 | return app.NewExecTxResult(code.OK, "success", message.MessageId) 126 | } 127 | 128 | type GetMessageParam struct { 129 | MessageID string `json:"message_id"` 130 | } 131 | 132 | type GetMessageResult struct { 133 | Message string `json:"message"` 134 | } 135 | 136 | func (app *ABCIApplication) getMessage(param []byte, height int64) *abcitypes.ResponseQuery { 137 | app.logger.Infof("GetMessage, Parameter: %s", param) 138 | var funcParam GetMessageParam 139 | err := json.Unmarshal(param, &funcParam) 140 | if err != nil { 141 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 142 | } 143 | key := messageKeyPrefix + keySeparator + funcParam.MessageID 144 | value, err := app.state.Get([]byte(key), true) 145 | if err != nil { 146 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 147 | } 148 | 149 | if value == nil { 150 | valueJSON := []byte("{}") 151 | return app.NewResponseQuery(valueJSON, "not found", app.state.Height) 152 | } 153 | var message data.Message 154 | err = proto.Unmarshal([]byte(value), &message) 155 | if err != nil { 156 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 157 | } 158 | 159 | var res GetMessageResult 160 | res.Message = message.Message 161 | 162 | valueJSON, err := json.Marshal(res) 163 | if err != nil { 164 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 165 | } 166 | return app.NewResponseQuery(valueJSON, "success", app.state.Height) 167 | } 168 | 169 | type GetMessageDetailResult struct { 170 | MessageID string `json:"message_id"` 171 | Message string `json:"message"` 172 | Purpose string `json:"purpose"` 173 | RequesterNodeID string `json:"requester_node_id"` 174 | CreationBlockHeight int64 `json:"creation_block_height"` 175 | CreationChainID string `json:"creation_chain_id"` 176 | } 177 | 178 | func (app *ABCIApplication) getMessageDetail(param []byte, height int64, committedState bool) *abcitypes.ResponseQuery { 179 | app.logger.Infof("GetMessageDetail, Parameter: %s", param) 180 | var funcParam GetMessageParam 181 | err := json.Unmarshal(param, &funcParam) 182 | if err != nil { 183 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 184 | } 185 | 186 | key := messageKeyPrefix + keySeparator + funcParam.MessageID 187 | var value []byte 188 | value, err = app.state.Get([]byte(key), committedState) 189 | if err != nil { 190 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 191 | } 192 | 193 | if value == nil { 194 | valueJSON := []byte("{}") 195 | return app.NewResponseQuery(valueJSON, "not found", app.state.Height) 196 | } 197 | 198 | var result GetMessageDetailResult 199 | var message data.Message 200 | err = proto.Unmarshal([]byte(value), &message) 201 | if err != nil { 202 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 203 | } 204 | 205 | result.MessageID = message.MessageId 206 | result.Message = message.Message 207 | 208 | // Set purpose 209 | result.Purpose = message.Purpose 210 | 211 | // Set requester_node_id 212 | result.RequesterNodeID = message.Owner 213 | 214 | // Set creation_block_height 215 | result.CreationBlockHeight = message.CreationBlockHeight 216 | 217 | // Set creation_chain_id 218 | result.CreationChainID = message.ChainId 219 | 220 | resultJSON, err := json.Marshal(result) 221 | if err != nil { 222 | value = []byte("") 223 | return app.NewResponseQuery(value, err.Error(), app.state.Height) 224 | } 225 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 226 | } 227 | -------------------------------------------------------------------------------- /abci/app/v1/namespace.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | "google.golang.org/protobuf/proto" 29 | 30 | abcitypes "github.com/cometbft/cometbft/abci/types" 31 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 32 | ) 33 | 34 | func (app *ABCIApplication) getNamespaceList(param []byte) *abcitypes.ResponseQuery { 35 | app.logger.Infof("GetNamespaceList, Parameter: %s", param) 36 | value, err := app.state.Get(allNamespaceKeyBytes, true) 37 | if err != nil { 38 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 39 | } 40 | if value == nil { 41 | value = []byte("[]") 42 | return app.NewResponseQuery(value, "not found", app.state.Height) 43 | } 44 | 45 | result := make([]*data.Namespace, 0) 46 | // filter flag==true 47 | var namespaces data.NamespaceList 48 | err = proto.Unmarshal([]byte(value), &namespaces) 49 | if err != nil { 50 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 51 | } 52 | for _, namespace := range namespaces.Namespaces { 53 | if namespace.Active { 54 | result = append(result, namespace) 55 | } 56 | } 57 | returnValue, err := json.Marshal(result) 58 | if err != nil { 59 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 60 | } 61 | return app.NewResponseQuery(returnValue, "success", app.state.Height) 62 | } 63 | 64 | func (app *ABCIApplication) GetNamespaceMap(committedState bool) (result map[string]bool) { 65 | result = make(map[string]bool, 0) 66 | allNamespaceValue, err := app.state.Get(allNamespaceKeyBytes, committedState) 67 | if err != nil { 68 | return nil 69 | } 70 | if allNamespaceValue == nil { 71 | return result 72 | } 73 | var namespaces data.NamespaceList 74 | err = proto.Unmarshal([]byte(allNamespaceValue), &namespaces) 75 | if err != nil { 76 | return result 77 | } 78 | for _, namespace := range namespaces.Namespaces { 79 | if namespace.Active { 80 | result[namespace.Namespace] = true 81 | } 82 | } 83 | return result 84 | } 85 | 86 | func (app *ABCIApplication) GetNamespaceAllowedIdentifierCountMap(committedState bool) (result map[string]int) { 87 | result = make(map[string]int, 0) 88 | allNamespaceValue, err := app.state.Get(allNamespaceKeyBytes, committedState) 89 | if err != nil { 90 | return nil 91 | } 92 | if allNamespaceValue == nil { 93 | return result 94 | } 95 | var namespaces data.NamespaceList 96 | err = proto.Unmarshal([]byte(allNamespaceValue), &namespaces) 97 | if err != nil { 98 | return result 99 | } 100 | for _, namespace := range namespaces.Namespaces { 101 | if namespace.Active { 102 | if namespace.AllowedIdentifierCountInReferenceGroup == -1 { 103 | result[namespace.Namespace] = 0 104 | } else { 105 | result[namespace.Namespace] = int(namespace.AllowedIdentifierCountInReferenceGroup) 106 | } 107 | } 108 | } 109 | return result 110 | } 111 | -------------------------------------------------------------------------------- /abci/app/v1/ndid.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | var regulatorMethod = map[string]bool{ 26 | "InitNDID": true, 27 | "RegisterNode": true, 28 | "AddNodeToken": true, 29 | "ReduceNodeToken": true, 30 | "SetNodeToken": true, 31 | "SetPriceFunc": true, 32 | "AddNamespace": true, 33 | "DisableNamespace": true, 34 | "SetValidator": true, 35 | "AddService": true, 36 | "DisableService": true, 37 | "UpdateNodeByNDID": true, 38 | "UpdateService": true, 39 | "RegisterServiceDestinationByNDID": true, 40 | "DisableNode": true, 41 | "DisableServiceDestinationByNDID": true, 42 | "EnableNode": true, 43 | "EnableServiceDestinationByNDID": true, 44 | "EnableNamespace": true, 45 | "EnableService": true, 46 | "SetTimeOutBlockRegisterIdentity": true, 47 | "AddNodeToProxyNode": true, 48 | "UpdateNodeProxyNode": true, 49 | "RemoveNodeFromProxyNode": true, 50 | "AddErrorCode": true, 51 | "RemoveErrorCode": true, 52 | "SetInitData": true, 53 | "EndInit": true, 54 | "SetLastBlock": true, 55 | "SetSupportedIALList": true, 56 | "SetSupportedAALList": true, 57 | "SetAllowedModeList": true, 58 | "UpdateNamespace": true, 59 | "SetAllowedMinIalForRegisterIdentityAtFirstIdp": true, 60 | "SetServicePriceCeiling": true, 61 | "SetServicePriceMinEffectiveDatetimeDelay": true, 62 | "AddRequestType": true, 63 | "RemoveRequestType": true, 64 | "AddSuppressedIdentityModificationNotificationNode": true, 65 | "RemoveSuppressedIdentityModificationNotificationNode": true, 66 | "AddAllowedNodeSupportedFeature": true, 67 | "RemoveAllowedNodeSupportedFeature": true, 68 | } 69 | -------------------------------------------------------------------------------- /abci/app/v1/ndid_error_code.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | "fmt" 28 | "strings" 29 | 30 | abcitypes "github.com/cometbft/cometbft/abci/types" 31 | "google.golang.org/protobuf/proto" 32 | 33 | "github.com/ndidplatform/smart-contract/v9/abci/code" 34 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 35 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 36 | ) 37 | 38 | func (*ABCIApplication) checkErrorCodeType(errorCodeType string) bool { 39 | return contains(errorCodeType, []string{"idp", "as"}) 40 | } 41 | 42 | type AddErrorCodeParam struct { 43 | ErrorCode int32 `json:"error_code"` 44 | Description string `json:"description"` 45 | Type string `json:"type"` 46 | } 47 | 48 | func (app *ABCIApplication) validateAddErrorCode(funcParam AddErrorCodeParam, callerNodeID string, committedState bool, checktx bool) error { 49 | // permission 50 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 51 | if err != nil { 52 | return err 53 | } 54 | if !ok { 55 | return &ApplicationError{ 56 | Code: code.NoPermissionForCallNDIDMethod, 57 | Message: "This node does not have permission to call NDID method", 58 | } 59 | } 60 | 61 | // stateless 62 | 63 | funcParam.Type = strings.ToLower(funcParam.Type) 64 | if !app.checkErrorCodeType(funcParam.Type) { 65 | return &ApplicationError{ 66 | Code: code.InvalidErrorCode, 67 | Message: "Invalid error code type", 68 | } 69 | } 70 | if funcParam.ErrorCode == 0 { 71 | return &ApplicationError{ 72 | Code: code.InvalidErrorCode, 73 | Message: "ErrorCode cannot be 0", 74 | } 75 | } 76 | 77 | if checktx { 78 | return nil 79 | } 80 | 81 | // stateful 82 | 83 | errorKey := errorCodeKeyPrefix + keySeparator + funcParam.Type + keySeparator + fmt.Sprintf("%d", funcParam.ErrorCode) 84 | hasErrorKey, err := app.state.Has([]byte(errorKey), committedState) 85 | if err != nil { 86 | return &ApplicationError{ 87 | Code: code.AppStateError, 88 | Message: err.Error(), 89 | } 90 | } 91 | if hasErrorKey { 92 | return &ApplicationError{ 93 | Code: code.InvalidErrorCode, 94 | Message: "ErrorCode already exists", 95 | } 96 | } 97 | 98 | return nil 99 | } 100 | 101 | func (app *ABCIApplication) addErrorCodeCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 102 | var funcParam AddErrorCodeParam 103 | err := json.Unmarshal(param, &funcParam) 104 | if err != nil { 105 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 106 | } 107 | 108 | err = app.validateAddErrorCode(funcParam, callerNodeID, true, true) 109 | if err != nil { 110 | if appErr, ok := err.(*ApplicationError); ok { 111 | return NewResponseCheckTx(appErr.Code, appErr.Message) 112 | } 113 | return NewResponseCheckTx(code.UnknownError, err.Error()) 114 | } 115 | 116 | return NewResponseCheckTx(code.OK, "") 117 | } 118 | 119 | func (app *ABCIApplication) addErrorCode(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 120 | app.logger.Infof("AddErrorCode, Parameter: %s", param) 121 | var funcParam AddErrorCodeParam 122 | err := json.Unmarshal(param, &funcParam) 123 | if err != nil { 124 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 125 | } 126 | 127 | err = app.validateAddErrorCode(funcParam, callerNodeID, false, false) 128 | if err != nil { 129 | if appErr, ok := err.(*ApplicationError); ok { 130 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 131 | } 132 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 133 | } 134 | 135 | // convert error type to lower case 136 | funcParam.Type = strings.ToLower(funcParam.Type) 137 | 138 | errorCode := data.ErrorCode{ 139 | ErrorCode: funcParam.ErrorCode, 140 | Description: funcParam.Description, 141 | } 142 | 143 | // add error code 144 | errorCodeBytes, err := utils.ProtoDeterministicMarshal(&errorCode) 145 | if err != nil { 146 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 147 | } 148 | errorKey := errorCodeKeyPrefix + keySeparator + funcParam.Type + keySeparator + fmt.Sprintf("%d", errorCode.ErrorCode) 149 | app.state.Set([]byte(errorKey), []byte(errorCodeBytes)) 150 | 151 | // add error code to ErrorCodeList 152 | var errorCodeList data.ErrorCodeList 153 | errorsKey := errorCodeListKeyPrefix + keySeparator + funcParam.Type 154 | errorCodeListBytes, err := app.state.Get([]byte(errorsKey), false) 155 | if err != nil { 156 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 157 | } 158 | if errorCodeListBytes != nil { 159 | err := proto.Unmarshal(errorCodeListBytes, &errorCodeList) 160 | if err != nil { 161 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 162 | } 163 | } 164 | errorCodeList.ErrorCode = append(errorCodeList.ErrorCode, &errorCode) 165 | errorCodeListBytes, err = utils.ProtoDeterministicMarshal(&errorCodeList) 166 | if err != nil { 167 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 168 | } 169 | app.state.Set([]byte(errorsKey), []byte(errorCodeListBytes)) 170 | 171 | return app.NewExecTxResult(code.OK, "success", "") 172 | } 173 | 174 | type RemoveErrorCodeParam struct { 175 | ErrorCode int32 `json:"error_code"` 176 | Type string `json:"type"` 177 | } 178 | 179 | func (app *ABCIApplication) validateRemoveErrorCode(funcParam RemoveErrorCodeParam, callerNodeID string, committedState bool, checktx bool) error { 180 | // permission 181 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 182 | if err != nil { 183 | return err 184 | } 185 | if !ok { 186 | return &ApplicationError{ 187 | Code: code.NoPermissionForCallNDIDMethod, 188 | Message: "This node does not have permission to call NDID method", 189 | } 190 | } 191 | 192 | if checktx { 193 | return nil 194 | } 195 | 196 | // stateful 197 | 198 | errorKey := errorCodeKeyPrefix + keySeparator + funcParam.Type + keySeparator + fmt.Sprintf("%d", funcParam.ErrorCode) 199 | hasErrorKey, err := app.state.Has([]byte(errorKey), committedState) 200 | if err != nil { 201 | return &ApplicationError{ 202 | Code: code.AppStateError, 203 | Message: err.Error(), 204 | } 205 | } 206 | if !hasErrorKey { 207 | return &ApplicationError{ 208 | Code: code.InvalidErrorCode, 209 | Message: "ErrorCode does not exist", 210 | } 211 | } 212 | 213 | return nil 214 | } 215 | 216 | func (app *ABCIApplication) removeErrorCodeCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 217 | var funcParam RemoveErrorCodeParam 218 | err := json.Unmarshal(param, &funcParam) 219 | if err != nil { 220 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 221 | } 222 | 223 | err = app.validateRemoveErrorCode(funcParam, callerNodeID, true, true) 224 | if err != nil { 225 | if appErr, ok := err.(*ApplicationError); ok { 226 | return NewResponseCheckTx(appErr.Code, appErr.Message) 227 | } 228 | return NewResponseCheckTx(code.UnknownError, err.Error()) 229 | } 230 | 231 | return NewResponseCheckTx(code.OK, "") 232 | } 233 | 234 | func (app *ABCIApplication) removeErrorCode(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 235 | app.logger.Infof("RemoveErrorCode, Parameter: %s", param) 236 | var funcParam RemoveErrorCodeParam 237 | err := json.Unmarshal(param, &funcParam) 238 | if err != nil { 239 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 240 | } 241 | 242 | err = app.validateRemoveErrorCode(funcParam, callerNodeID, false, false) 243 | if err != nil { 244 | if appErr, ok := err.(*ApplicationError); ok { 245 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 246 | } 247 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 248 | } 249 | 250 | // remove error code from ErrorCode index 251 | errorKey := errorCodeKeyPrefix + keySeparator + funcParam.Type + keySeparator + fmt.Sprintf("%d", funcParam.ErrorCode) 252 | err = app.state.Delete([]byte(errorKey)) 253 | if err != nil { 254 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 255 | } 256 | 257 | // remove ErrorCode from ErrorCodeList 258 | var errorCodeList data.ErrorCodeList 259 | errorsKey := errorCodeListKeyPrefix + keySeparator + funcParam.Type 260 | errorCodeListBytes, err := app.state.Get([]byte(errorsKey), false) 261 | if err != nil { 262 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 263 | } 264 | if errorCodeListBytes != nil { 265 | err := proto.Unmarshal(errorCodeListBytes, &errorCodeList) 266 | if err != nil { 267 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 268 | } 269 | } 270 | 271 | newErrorCodeList := data.ErrorCodeList{ 272 | ErrorCode: make([]*data.ErrorCode, 0, len(errorCodeList.ErrorCode)), 273 | } 274 | for _, errorCode := range errorCodeList.ErrorCode { 275 | if errorCode.ErrorCode != funcParam.ErrorCode { 276 | newErrorCodeList.ErrorCode = append(newErrorCodeList.ErrorCode, errorCode) 277 | } 278 | } 279 | 280 | if len(newErrorCodeList.ErrorCode) != len(errorCodeList.ErrorCode)-1 { 281 | return app.NewExecTxResult(code.InvalidErrorCode, "ErrorCode does not exist", "") 282 | } 283 | 284 | errorCodeListBytes, err = utils.ProtoDeterministicMarshal(&newErrorCodeList) 285 | if err != nil { 286 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 287 | } 288 | app.state.Set([]byte(errorsKey), []byte(errorCodeListBytes)) 289 | 290 | return app.NewExecTxResult(code.OK, "success", "") 291 | } 292 | -------------------------------------------------------------------------------- /abci/app/v1/ndid_identity.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | 30 | "github.com/ndidplatform/smart-contract/v9/abci/code" 31 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 32 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 33 | ) 34 | 35 | type TimeOutBlockRegisterIdentity struct { 36 | TimeOutBlock int64 `json:"time_out_block"` 37 | } 38 | 39 | func (app *ABCIApplication) validateSetTimeOutBlockRegisterIdentity(funcParam TimeOutBlockRegisterIdentity, callerNodeID string, committedState bool, checktx bool) error { 40 | // permission 41 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 42 | if err != nil { 43 | return err 44 | } 45 | if !ok { 46 | return &ApplicationError{ 47 | Code: code.NoPermissionForCallNDIDMethod, 48 | Message: "This node does not have permission to call NDID method", 49 | } 50 | } 51 | 52 | return nil 53 | } 54 | 55 | func (app *ABCIApplication) setTimeOutBlockRegisterIdentityCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 56 | var funcParam TimeOutBlockRegisterIdentity 57 | err := json.Unmarshal(param, &funcParam) 58 | if err != nil { 59 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 60 | } 61 | 62 | err = app.validateSetTimeOutBlockRegisterIdentity(funcParam, callerNodeID, true, true) 63 | if err != nil { 64 | if appErr, ok := err.(*ApplicationError); ok { 65 | return NewResponseCheckTx(appErr.Code, appErr.Message) 66 | } 67 | return NewResponseCheckTx(code.UnknownError, err.Error()) 68 | } 69 | 70 | return NewResponseCheckTx(code.OK, "") 71 | } 72 | 73 | func (app *ABCIApplication) setTimeOutBlockRegisterIdentity(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 74 | app.logger.Infof("SetTimeOutBlockRegisterIdentity, Parameter: %s", param) 75 | var funcParam TimeOutBlockRegisterIdentity 76 | err := json.Unmarshal(param, &funcParam) 77 | if err != nil { 78 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 79 | } 80 | 81 | err = app.validateSetTimeOutBlockRegisterIdentity(funcParam, callerNodeID, false, false) 82 | if err != nil { 83 | if appErr, ok := err.(*ApplicationError); ok { 84 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 85 | } 86 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 87 | } 88 | 89 | key := "TimeOutBlockRegisterIdentity" 90 | var timeOut data.TimeOutBlockRegisterIdentity 91 | timeOut.TimeOutBlock = funcParam.TimeOutBlock 92 | // Check time out block > 0 93 | if timeOut.TimeOutBlock <= 0 { 94 | return app.NewExecTxResult(code.TimeOutBlockIsMustGreaterThanZero, "Time out block is must greater than 0", "") 95 | } 96 | value, err := utils.ProtoDeterministicMarshal(&timeOut) 97 | if err != nil { 98 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 99 | } 100 | app.state.Set([]byte(key), []byte(value)) 101 | return app.NewExecTxResult(code.OK, "success", "") 102 | } 103 | 104 | type SetAllowedMinIalForRegisterIdentityAtFirstIdpParam struct { 105 | MinIal float64 `json:"min_ial"` 106 | } 107 | 108 | func (app *ABCIApplication) validateSetAllowedMinIalForRegisterIdentityAtFirstIdp(funcParam SetAllowedMinIalForRegisterIdentityAtFirstIdpParam, callerNodeID string, committedState bool, checktx bool) error { 109 | // permission 110 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 111 | if err != nil { 112 | return err 113 | } 114 | if !ok { 115 | return &ApplicationError{ 116 | Code: code.NoPermissionForCallNDIDMethod, 117 | Message: "This node does not have permission to call NDID method", 118 | } 119 | } 120 | 121 | return nil 122 | } 123 | 124 | func (app *ABCIApplication) setAllowedMinIalForRegisterIdentityAtFirstIdpCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 125 | var funcParam SetAllowedMinIalForRegisterIdentityAtFirstIdpParam 126 | err := json.Unmarshal(param, &funcParam) 127 | if err != nil { 128 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 129 | } 130 | 131 | err = app.validateSetAllowedMinIalForRegisterIdentityAtFirstIdp(funcParam, callerNodeID, true, true) 132 | if err != nil { 133 | if appErr, ok := err.(*ApplicationError); ok { 134 | return NewResponseCheckTx(appErr.Code, appErr.Message) 135 | } 136 | return NewResponseCheckTx(code.UnknownError, err.Error()) 137 | } 138 | 139 | return NewResponseCheckTx(code.OK, "") 140 | } 141 | 142 | func (app *ABCIApplication) setAllowedMinIalForRegisterIdentityAtFirstIdp(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 143 | app.logger.Infof("SetAllowedMinIalForRegisterIdentityAtFirstIdp, Parameter: %s", param) 144 | var funcParam SetAllowedMinIalForRegisterIdentityAtFirstIdpParam 145 | err := json.Unmarshal(param, &funcParam) 146 | if err != nil { 147 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 148 | } 149 | 150 | err = app.validateSetAllowedMinIalForRegisterIdentityAtFirstIdp(funcParam, callerNodeID, false, false) 151 | if err != nil { 152 | if appErr, ok := err.(*ApplicationError); ok { 153 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 154 | } 155 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 156 | } 157 | 158 | allowedMinIalKey := "AllowedMinIalForRegisterIdentityAtFirstIdp" 159 | var allowedMinIal data.AllowedMinIalForRegisterIdentityAtFirstIdp 160 | allowedMinIal.MinIal = funcParam.MinIal 161 | allowedMinIalByte, err := utils.ProtoDeterministicMarshal(&allowedMinIal) 162 | if err != nil { 163 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 164 | } 165 | app.state.Set([]byte(allowedMinIalKey), allowedMinIalByte) 166 | return app.NewExecTxResult(code.OK, "success", "") 167 | } 168 | -------------------------------------------------------------------------------- /abci/app/v1/ndid_request.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | 30 | "github.com/ndidplatform/smart-contract/v9/abci/code" 31 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 32 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 33 | ) 34 | 35 | type SetAllowedModeListParam struct { 36 | Purpose string `json:"purpose"` 37 | AllowedModeList []int32 `json:"allowed_mode_list"` 38 | } 39 | 40 | func (app *ABCIApplication) validateSetAllowedModeList(funcParam SetAllowedModeListParam, callerNodeID string, committedState bool, checktx bool) error { 41 | // permission 42 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 43 | if err != nil { 44 | return err 45 | } 46 | if !ok { 47 | return &ApplicationError{ 48 | Code: code.NoPermissionForCallNDIDMethod, 49 | Message: "This node does not have permission to call NDID method", 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func (app *ABCIApplication) setAllowedModeListCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 57 | var funcParam SetAllowedModeListParam 58 | err := json.Unmarshal(param, &funcParam) 59 | if err != nil { 60 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 61 | } 62 | 63 | err = app.validateSetAllowedModeList(funcParam, callerNodeID, true, true) 64 | if err != nil { 65 | if appErr, ok := err.(*ApplicationError); ok { 66 | return NewResponseCheckTx(appErr.Code, appErr.Message) 67 | } 68 | return NewResponseCheckTx(code.UnknownError, err.Error()) 69 | } 70 | 71 | return NewResponseCheckTx(code.OK, "") 72 | } 73 | 74 | func (app *ABCIApplication) setAllowedModeList(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 75 | app.logger.Infof("SetAllowedModeList, Parameter: %s", param) 76 | var funcParam SetAllowedModeListParam 77 | err := json.Unmarshal(param, &funcParam) 78 | if err != nil { 79 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 80 | } 81 | 82 | err = app.validateSetAllowedModeList(funcParam, callerNodeID, false, false) 83 | if err != nil { 84 | if appErr, ok := err.(*ApplicationError); ok { 85 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 86 | } 87 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 88 | } 89 | 90 | allowedModeKey := allowedModeListKeyPrefix + keySeparator + funcParam.Purpose 91 | var allowedModeList data.AllowedModeList 92 | allowedModeList.Mode = funcParam.AllowedModeList 93 | allowedModeListByte, err := utils.ProtoDeterministicMarshal(&allowedModeList) 94 | if err != nil { 95 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 96 | } 97 | app.state.Set([]byte(allowedModeKey), allowedModeListByte) 98 | return app.NewExecTxResult(code.OK, "success", "") 99 | } 100 | -------------------------------------------------------------------------------- /abci/app/v1/node_supported_feature.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | goleveldbutil "github.com/syndtr/goleveldb/leveldb/util" 30 | 31 | "github.com/ndidplatform/smart-contract/v9/abci/code" 32 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 33 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 34 | ) 35 | 36 | type AddAllowedNodeSupportedFeatureParam struct { 37 | Name string `json:"name"` 38 | } 39 | 40 | func (app *ABCIApplication) validateAddAllowedNodeSupportedFeature(funcParam AddAllowedNodeSupportedFeatureParam, callerNodeID string, committedState bool, checktx bool) error { 41 | // permission 42 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 43 | if err != nil { 44 | return err 45 | } 46 | if !ok { 47 | return &ApplicationError{ 48 | Code: code.NoPermissionForCallNDIDMethod, 49 | Message: "This node does not have permission to call NDID method", 50 | } 51 | } 52 | 53 | if checktx { 54 | return nil 55 | } 56 | 57 | // stateful 58 | 59 | key := nodeSupportedFeatureKeyPrefix + keySeparator + funcParam.Name 60 | exists, err := app.state.Has([]byte(key), committedState) 61 | if err != nil { 62 | return &ApplicationError{ 63 | Code: code.AppStateError, 64 | Message: err.Error(), 65 | } 66 | } 67 | if exists { 68 | return &ApplicationError{ 69 | Code: code.NodeSupportedFeatureAlreadyExists, 70 | Message: "node supported feature already exists", 71 | } 72 | } 73 | 74 | return nil 75 | } 76 | 77 | func (app *ABCIApplication) addAllowedNodeSupportedFeatureCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 78 | var funcParam AddAllowedNodeSupportedFeatureParam 79 | err := json.Unmarshal(param, &funcParam) 80 | if err != nil { 81 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 82 | } 83 | 84 | err = app.validateAddAllowedNodeSupportedFeature(funcParam, callerNodeID, true, true) 85 | if err != nil { 86 | if appErr, ok := err.(*ApplicationError); ok { 87 | return NewResponseCheckTx(appErr.Code, appErr.Message) 88 | } 89 | return NewResponseCheckTx(code.UnknownError, err.Error()) 90 | } 91 | 92 | return NewResponseCheckTx(code.OK, "") 93 | } 94 | 95 | // regulator only 96 | func (app *ABCIApplication) addAllowedNodeSupportedFeature(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 97 | app.logger.Infof("AddAllowedNodeSupportedFeature, Parameter: %s", param) 98 | var funcParam AddAllowedNodeSupportedFeatureParam 99 | err := json.Unmarshal(param, &funcParam) 100 | if err != nil { 101 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 102 | } 103 | 104 | err = app.validateAddAllowedNodeSupportedFeature(funcParam, callerNodeID, false, false) 105 | if err != nil { 106 | if appErr, ok := err.(*ApplicationError); ok { 107 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 108 | } 109 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 110 | } 111 | 112 | key := nodeSupportedFeatureKeyPrefix + keySeparator + funcParam.Name 113 | 114 | var nodeSupportedFeature data.NodeSupportedFeature 115 | value, err := utils.ProtoDeterministicMarshal(&nodeSupportedFeature) 116 | if err != nil { 117 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 118 | } 119 | 120 | app.state.Set([]byte(key), value) 121 | 122 | return app.NewExecTxResult(code.OK, "success", "") 123 | } 124 | 125 | type RemoveAllowedNodeSupportedFeatureParam struct { 126 | Name string `json:"name"` 127 | } 128 | 129 | func (app *ABCIApplication) validateRemoveAllowedNodeSupportedFeature(funcParam RemoveAllowedNodeSupportedFeatureParam, callerNodeID string, committedState bool, checktx bool) error { 130 | // permission 131 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 132 | if err != nil { 133 | return err 134 | } 135 | if !ok { 136 | return &ApplicationError{ 137 | Code: code.NoPermissionForCallNDIDMethod, 138 | Message: "This node does not have permission to call NDID method", 139 | } 140 | } 141 | 142 | if checktx { 143 | return nil 144 | } 145 | 146 | // stateful 147 | 148 | key := nodeSupportedFeatureKeyPrefix + keySeparator + funcParam.Name 149 | exists, err := app.state.Has([]byte(key), committedState) 150 | if err != nil { 151 | return &ApplicationError{ 152 | Code: code.AppStateError, 153 | Message: err.Error(), 154 | } 155 | } 156 | if !exists { 157 | return &ApplicationError{ 158 | Code: code.NodeSupportedFeatureDoesNotExist, 159 | Message: "node supported feature does not exist", 160 | } 161 | } 162 | 163 | return nil 164 | } 165 | 166 | func (app *ABCIApplication) removeAllowedNodeSupportedFeatureCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 167 | var funcParam RemoveAllowedNodeSupportedFeatureParam 168 | err := json.Unmarshal(param, &funcParam) 169 | if err != nil { 170 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 171 | } 172 | 173 | err = app.validateRemoveAllowedNodeSupportedFeature(funcParam, callerNodeID, true, true) 174 | if err != nil { 175 | if appErr, ok := err.(*ApplicationError); ok { 176 | return NewResponseCheckTx(appErr.Code, appErr.Message) 177 | } 178 | return NewResponseCheckTx(code.UnknownError, err.Error()) 179 | } 180 | 181 | return NewResponseCheckTx(code.OK, "") 182 | } 183 | 184 | // regulator only 185 | func (app *ABCIApplication) removeAllowedNodeSupportedFeature(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 186 | app.logger.Infof("RemoveAllowedNodeSupportedFeature, Parameter: %s", param) 187 | var funcParam RemoveAllowedNodeSupportedFeatureParam 188 | err := json.Unmarshal(param, &funcParam) 189 | if err != nil { 190 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 191 | } 192 | 193 | err = app.validateRemoveAllowedNodeSupportedFeature(funcParam, callerNodeID, false, false) 194 | if err != nil { 195 | if appErr, ok := err.(*ApplicationError); ok { 196 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 197 | } 198 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 199 | } 200 | 201 | key := nodeSupportedFeatureKeyPrefix + keySeparator + funcParam.Name 202 | 203 | app.state.Delete([]byte(key)) 204 | 205 | return app.NewExecTxResult(code.OK, "success", "") 206 | } 207 | 208 | type GetAllowedNodeSupportedFeatureListParam struct { 209 | Prefix string `json:"prefix"` 210 | } 211 | 212 | func (app *ABCIApplication) getAllowedNodeSupportedFeatureList(param []byte, height int64) *abcitypes.ResponseQuery { 213 | app.logger.Infof("GetAllowedNodeSupportedFeatureList, Parameter: %s", param) 214 | var funcParam GetAllowedNodeSupportedFeatureListParam 215 | err := json.Unmarshal(param, &funcParam) 216 | if err != nil { 217 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 218 | } 219 | 220 | result := make([]string, 0) 221 | 222 | nodeSupportedFeatureKeyIteratorBasePrefix := nodeSupportedFeatureKeyPrefix + keySeparator 223 | nodeSupportedFeatureKeyIteratorPrefix := nodeSupportedFeatureKeyIteratorBasePrefix + funcParam.Prefix 224 | r := goleveldbutil.BytesPrefix([]byte(nodeSupportedFeatureKeyIteratorPrefix)) 225 | iter, err := app.state.db.Iterator(r.Start, r.Limit) 226 | if err != nil { 227 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 228 | } 229 | for ; iter.Valid(); iter.Next() { 230 | key := iter.Key() 231 | 232 | runes := []rune(string(key)) 233 | nodeSupportedFeature := string(runes[len(nodeSupportedFeatureKeyIteratorBasePrefix):]) 234 | 235 | result = append(result, nodeSupportedFeature) 236 | } 237 | iter.Close() 238 | 239 | resultJSON, err := json.Marshal(result) 240 | if err != nil { 241 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 242 | } 243 | 244 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 245 | } 246 | -------------------------------------------------------------------------------- /abci/app/v1/prometheus.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "time" 27 | 28 | "github.com/prometheus/client_golang/prometheus" 29 | ) 30 | 31 | func init() { 32 | prometheus.MustRegister(checkTxCounter) 33 | prometheus.MustRegister(checkTxFailCounter) 34 | prometheus.MustRegister(checkTxDurationHistogram) 35 | prometheus.MustRegister(deliverTxCounter) 36 | prometheus.MustRegister(deliverTxFailCounter) 37 | prometheus.MustRegister(deliverTxDurationHistogram) 38 | prometheus.MustRegister(queryCounter) 39 | prometheus.MustRegister(queryDurationHistogram) 40 | prometheus.MustRegister(commitDurationHistogram) 41 | prometheus.MustRegister(dbSaveDurationHistogram) 42 | prometheus.MustRegister(appHashDurationHistogram) 43 | } 44 | 45 | func recordCheckTxMetrics(fName string) { 46 | checkTxCounter.With(prometheus.Labels{"function": fName}).Inc() 47 | } 48 | 49 | var ( 50 | checkTxCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ 51 | Subsystem: "abci", 52 | Name: "check_tx_total", 53 | Help: "Total number of CheckTx function called", 54 | }, 55 | []string{"function"}) 56 | ) 57 | 58 | func recordCheckTxFailMetrics(fName string) { 59 | checkTxFailCounter.With(prometheus.Labels{"function": fName}).Inc() 60 | } 61 | 62 | var ( 63 | checkTxFailCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ 64 | Subsystem: "abci", 65 | Name: "check_tx_fails_total", 66 | Help: "Total number of failed CheckTx", 67 | }, 68 | []string{"function"}) 69 | ) 70 | 71 | func recordCheckTxDurationMetrics(duration time.Duration, fName string) { 72 | checkTxDurationHistogram.WithLabelValues(fName).Observe(duration.Seconds()) 73 | } 74 | 75 | var ( 76 | checkTxDurationHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 77 | Subsystem: "abci", 78 | Name: "check_tx_duration_seconds", 79 | Help: "Duration of CheckTx in seconds", 80 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 81 | }, 82 | []string{"function"}, 83 | ) 84 | ) 85 | 86 | func recordDeliverTxMetrics(fName string) { 87 | deliverTxCounter.With(prometheus.Labels{"function": fName}).Inc() 88 | } 89 | 90 | var ( 91 | deliverTxCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ 92 | Subsystem: "abci", 93 | Name: "deliver_tx_total", 94 | Help: "Total number of DeliverTx function called", 95 | }, 96 | []string{"function"}, 97 | ) 98 | ) 99 | 100 | func recordDeliverTxFailMetrics(fName string) { 101 | deliverTxFailCounter.With(prometheus.Labels{"function": fName}).Inc() 102 | } 103 | 104 | var ( 105 | deliverTxFailCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ 106 | Subsystem: "abci", 107 | Name: "deliver_tx_fails_total", 108 | Help: "Total number of failed DeliverTx", 109 | }, 110 | []string{"function"}, 111 | ) 112 | ) 113 | 114 | func recordDeliverTxDurationMetrics(duration time.Duration, fName string) { 115 | deliverTxDurationHistogram.WithLabelValues(fName).Observe(duration.Seconds()) 116 | } 117 | 118 | var ( 119 | deliverTxDurationHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 120 | Subsystem: "abci", 121 | Name: "deliver_tx_duration_seconds", 122 | Help: "Duration of DeliverTx in seconds", 123 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 124 | }, 125 | []string{"function"}, 126 | ) 127 | ) 128 | 129 | func recordQueryMetrics(fName string) { 130 | queryCounter.With(prometheus.Labels{"function": fName}).Inc() 131 | } 132 | 133 | var ( 134 | queryCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ 135 | Subsystem: "abci", 136 | Name: "query_total", 137 | Help: "Total number of Query function called", 138 | }, 139 | []string{"function"}, 140 | ) 141 | ) 142 | 143 | func recordQueryDurationMetrics(duration time.Duration, fName string) { 144 | queryDurationHistogram.WithLabelValues(fName).Observe(duration.Seconds()) 145 | } 146 | 147 | var ( 148 | queryDurationHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 149 | Subsystem: "abci", 150 | Name: "query_duration_seconds", 151 | Help: "Duration of Query in seconds", 152 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 153 | }, 154 | []string{"function"}, 155 | ) 156 | ) 157 | 158 | func recordCommitDurationMetrics(duration time.Duration) { 159 | commitDurationHistogram.Observe(duration.Seconds()) 160 | } 161 | 162 | var ( 163 | commitDurationHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{ 164 | Subsystem: "abci", 165 | Name: "commit_duration_seconds", 166 | Help: "Duration of Commit in seconds", 167 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 168 | }, 169 | ) 170 | ) 171 | 172 | func recordDBSaveDurationMetrics(duration time.Duration) { 173 | dbSaveDurationHistogram.Observe(duration.Seconds()) 174 | } 175 | 176 | var ( 177 | dbSaveDurationHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{ 178 | Subsystem: "abci", 179 | Name: "db_save_duration_seconds", 180 | Help: "Duration of DB save in seconds", 181 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 182 | }, 183 | ) 184 | ) 185 | 186 | func recordAppHashDurationMetrics(duration time.Duration) { 187 | appHashDurationHistogram.Observe(duration.Seconds()) 188 | } 189 | 190 | var ( 191 | appHashDurationHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{ 192 | Subsystem: "abci", 193 | Name: "app_hash_duration_seconds", 194 | Help: "Duration of app hash calculation in seconds", 195 | Buckets: []float64{0.05, 0.1, 0.25, 0.5, 0.75, 1}, 196 | }, 197 | ) 198 | ) 199 | -------------------------------------------------------------------------------- /abci/app/v1/query.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | abcitypes "github.com/cometbft/cometbft/abci/types" 27 | 28 | "github.com/ndidplatform/smart-contract/v9/abci/code" 29 | ) 30 | 31 | // NewResponseQuery returns *abcitypes.ResponseQuery 32 | func (app *ABCIApplication) NewResponseQuery(value []byte, log string, height int64) *abcitypes.ResponseQuery { 33 | app.logger.Infof("Query result: %s", string(value)) 34 | var res *abcitypes.ResponseQuery = &abcitypes.ResponseQuery{} 35 | res.Value = value 36 | res.Log = log 37 | res.Height = height 38 | return res 39 | } 40 | 41 | // QueryRouter is Pointer to function 42 | func (app *ABCIApplication) QueryRouter(method string, param []byte, height int64) *abcitypes.ResponseQuery { 43 | result := app.callQuery(method, param, height) 44 | return result 45 | } 46 | 47 | func (app *ABCIApplication) callQuery(name string, param []byte, height int64) *abcitypes.ResponseQuery { 48 | switch name { 49 | case "GetNodeSigningPublicKey": 50 | return app.getNodeSigningPublicKey(param) 51 | case "GetNodeEncryptionPublicKey": 52 | return app.getNodeEncryptionPublicKey(param) 53 | case "GetIdpNodes": 54 | return app.getIdpNodes(param) 55 | case "GetRequest": 56 | return app.getRequest(param, height) 57 | case "GetRequestDetail": 58 | return app.getRequestDetail(param, height, true) 59 | case "GetAsNodesByServiceId": 60 | return app.getAsNodesByServiceId(param) 61 | case "GetMqAddresses": 62 | return app.getMqAddresses(param) 63 | case "GetNodeToken": 64 | return app.getNodeToken(param, true) 65 | case "GetPriceFunc": 66 | return app.getPriceFunc(param, true) 67 | case "GetServiceDetail": 68 | return app.getServiceDetail(param) 69 | case "GetNamespaceList": 70 | return app.getNamespaceList(param) 71 | case "CheckExistingIdentity": 72 | return app.checkExistingIdentity(param) 73 | case "GetAccessorKey": 74 | return app.getAccessorKey(param) 75 | case "GetServiceList": 76 | return app.getServiceList(param) 77 | case "GetNodeSigningMasterPublicKey": 78 | return app.getNodeSigningMasterPublicKey(param) 79 | case "GetNodeInfo": 80 | return app.getNodeInfo(param) 81 | case "GetNodePublicKeyList": 82 | return app.getNodePublicKeyList(param) 83 | case "CheckExistingAccessorID": 84 | return app.checkExistingAccessorID(param) 85 | case "GetIdentityInfo": 86 | return app.getIdentityInfo(param) 87 | case "GetDataSignature": 88 | return app.getDataSignature(param) 89 | case "GetServicesByAsID": 90 | return app.getServicesByAsID(param) 91 | case "GetIdpNodesInfo": 92 | return app.getIdpNodesInfo(param) 93 | case "GetAsNodesInfoByServiceId": 94 | return app.getAsNodesInfoByServiceId(param) 95 | case "GetNodesBehindProxyNode": 96 | return app.getNodesBehindProxyNode(param) 97 | case "GetNodeIDList": 98 | return app.getNodeIDList(param) 99 | case "GetAccessorOwner": 100 | return app.getAccessorOwner(param) 101 | case "GetErrorCodeList": 102 | return app.getErrorCodeList(param) 103 | case "IsInitEnded": 104 | return app.isInitEnded(param) 105 | case "GetChainHistory": 106 | return app.getChainHistory(param) 107 | case "GetReferenceGroupCode": 108 | return app.GetReferenceGroupCode(param) 109 | case "GetReferenceGroupCodeByAccessorID": 110 | return app.GetReferenceGroupCodeByAccessorID(param) 111 | case "GetSupportedIALList": 112 | return app.GetSupportedIALList(param, true) 113 | case "GetSupportedAALList": 114 | return app.GetSupportedAALList(param, true) 115 | case "GetAllowedModeList": 116 | return app.GetAllowedModeList(param) 117 | case "GetAllowedMinIalForRegisterIdentityAtFirstIdp": 118 | return app.GetAllowedMinIalForRegisterIdentityAtFirstIdp(param) 119 | case "GetServicePriceList": 120 | return app.getServicePriceList(param) 121 | case "GetServicePriceCeiling": 122 | return app.getServicePriceCeiling(param) 123 | case "GetServicePriceMinEffectiveDatetimeDelay": 124 | return app.getServicePriceMinEffectiveDatetimeDelay(param) 125 | case "GetMessage": 126 | return app.getMessage(param, height) 127 | case "GetMessageDetail": 128 | return app.getMessageDetail(param, height, true) 129 | case "GetRequestTypeList": 130 | return app.getRequestTypeList(param, height) 131 | case "GetSuppressedIdentityModificationNotificationNodeList": 132 | return app.getSuppressedIdentityModificationNotificationNodeList(param, height) 133 | case "IsSuppressedIdentityModificationNotificationNode": 134 | return app.isSuppressedIdentityModificationNotificationNode(param, height) 135 | case "GetAllowedNodeSupportedFeatureList": 136 | return app.getAllowedNodeSupportedFeatureList(param, height) 137 | default: 138 | return &abcitypes.ResponseQuery{Code: code.UnknownMethod, Log: "Unknown method name"} 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /abci/app/v1/request_idp.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | "fmt" 28 | 29 | abcitypes "github.com/cometbft/cometbft/abci/types" 30 | "google.golang.org/protobuf/proto" 31 | 32 | "github.com/ndidplatform/smart-contract/v9/abci/code" 33 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 34 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 35 | ) 36 | 37 | type CreateIdpResponseParam struct { 38 | Aal float64 `json:"aal"` 39 | Ial float64 `json:"ial"` 40 | RequestID string `json:"request_id"` 41 | Signature string `json:"signature"` 42 | Status string `json:"status"` 43 | ErrorCode *int32 `json:"error_code"` 44 | } 45 | 46 | func (app *ABCIApplication) validateCreateIdpResponse(funcParam CreateIdpResponseParam, callerNodeID string, committedState bool, checktx bool) error { 47 | // permission 48 | nodeDetailKey := nodeIDKeyPrefix + keySeparator + callerNodeID 49 | nodeDetailValue, err := app.state.Get([]byte(nodeDetailKey), committedState) 50 | if err != nil { 51 | return &ApplicationError{ 52 | Code: code.AppStateError, 53 | Message: err.Error(), 54 | } 55 | } 56 | if nodeDetailValue == nil { 57 | return &ApplicationError{ 58 | Code: code.NodeIDNotFound, 59 | Message: "Node ID not found", 60 | } 61 | } 62 | var nodeDetail data.NodeDetail 63 | err = proto.Unmarshal([]byte(nodeDetailValue), &nodeDetail) 64 | if err != nil { 65 | return &ApplicationError{ 66 | Code: code.UnmarshalError, 67 | Message: err.Error(), 68 | } 69 | } 70 | 71 | ok := app.isIDPorIDPAgentNode(&nodeDetail) 72 | if !ok { 73 | return &ApplicationError{ 74 | Code: code.NoPermissionForCallIdPMethod, 75 | Message: "This node does not have permission to call IdP or IdP agent method", 76 | } 77 | } 78 | 79 | if checktx { 80 | return nil 81 | } 82 | 83 | // stateful 84 | 85 | // get request 86 | requestKey := requestKeyPrefix + keySeparator + funcParam.RequestID 87 | requestValue, err := app.state.GetVersioned([]byte(requestKey), 0, committedState) 88 | if err != nil { 89 | return &ApplicationError{ 90 | Code: code.AppStateError, 91 | Message: err.Error(), 92 | } 93 | } 94 | if requestValue == nil { 95 | return &ApplicationError{ 96 | Code: code.RequestIDNotFound, 97 | Message: "Request ID not found", 98 | } 99 | } 100 | var request data.Request 101 | err = proto.Unmarshal([]byte(requestValue), &request) 102 | if err != nil { 103 | return &ApplicationError{ 104 | Code: code.UnmarshalError, 105 | Message: err.Error(), 106 | } 107 | } 108 | 109 | // Check closed request 110 | if request.Closed { 111 | return &ApplicationError{ 112 | Code: code.RequestIsClosed, 113 | Message: "Can't response a request that's closed", 114 | } 115 | } 116 | // Check timed out request 117 | if request.TimedOut { 118 | return &ApplicationError{ 119 | Code: code.RequestIsTimedOut, 120 | Message: "Can't response a request that's timed out", 121 | } 122 | } 123 | 124 | // Check nodeID exists in idp_id_list 125 | exist := false 126 | for _, idpID := range request.IdpIdList { 127 | if idpID == callerNodeID { 128 | exist = true 129 | break 130 | } 131 | } 132 | if !exist { 133 | return &ApplicationError{ 134 | Code: code.NodeIDDoesNotExistInIdPList, 135 | Message: "Node ID does not exist in IdP list", 136 | } 137 | } 138 | 139 | // Check duplicate response from the same IdP 140 | for _, currentResponse := range request.ResponseList { 141 | if currentResponse.IdpId == callerNodeID { 142 | return &ApplicationError{ 143 | Code: code.DuplicateIdPResponse, 144 | Message: "Duplicate IdP response", 145 | } 146 | } 147 | } 148 | 149 | // Check min_idp 150 | var nonErrorResponseCount int64 = 0 151 | for _, response := range request.ResponseList { 152 | if response.Status != "" { 153 | nonErrorResponseCount++ 154 | } 155 | } 156 | if nonErrorResponseCount >= request.MinIdp { 157 | return &ApplicationError{ 158 | Code: code.RequestIsCompleted, 159 | Message: "Can't response to a request that is completed", 160 | } 161 | } 162 | var remainingPossibleResponseCount int64 = int64(len(request.IdpIdList)) - int64(len(request.ResponseList)) 163 | if nonErrorResponseCount+remainingPossibleResponseCount < request.MinIdp { 164 | return &ApplicationError{ 165 | Code: code.RequestCannotBeFulfilled, 166 | Message: "Can't response to a request that cannot be fulfilled", 167 | } 168 | } 169 | 170 | if funcParam.ErrorCode == nil { 171 | // Check AAL 172 | if request.MinAal > funcParam.Aal { 173 | return &ApplicationError{ 174 | Code: code.AALError, 175 | Message: "Response's AAL is less than min AAL", 176 | } 177 | } 178 | // Check IAL 179 | if request.MinIal > funcParam.Ial { 180 | return &ApplicationError{ 181 | Code: code.IALError, 182 | Message: "Response's IAL is less than min IAL", 183 | } 184 | } 185 | 186 | // Check IAL and AAL with response node's MaxIal and MaxAal 187 | if funcParam.Aal > nodeDetail.MaxAal { 188 | return &ApplicationError{ 189 | Code: code.AALError, 190 | Message: "Response's AAL is greater than max AAL", 191 | } 192 | } 193 | if funcParam.Ial > nodeDetail.MaxIal { 194 | return &ApplicationError{ 195 | Code: code.IALError, 196 | Message: "Response's IAL is greater than max IAL", 197 | } 198 | } 199 | } else { 200 | // Check error code exists 201 | errorCodeKey := errorCodeKeyPrefix + keySeparator + "idp" + keySeparator + fmt.Sprintf("%d", *funcParam.ErrorCode) 202 | hasErrorCodeKey, err := app.state.Has([]byte(errorCodeKey), committedState) 203 | if err != nil { 204 | return &ApplicationError{ 205 | Code: code.AppStateError, 206 | Message: err.Error(), 207 | } 208 | } 209 | if !hasErrorCodeKey { 210 | return &ApplicationError{ 211 | Code: code.InvalidErrorCode, 212 | Message: "ErrorCode does not exist", 213 | } 214 | } 215 | } 216 | 217 | return nil 218 | } 219 | 220 | func (app *ABCIApplication) createIdpResponseCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 221 | var funcParam CreateIdpResponseParam 222 | err := json.Unmarshal(param, &funcParam) 223 | if err != nil { 224 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 225 | } 226 | 227 | err = app.validateCreateIdpResponse(funcParam, callerNodeID, true, true) 228 | if err != nil { 229 | if appErr, ok := err.(*ApplicationError); ok { 230 | return NewResponseCheckTx(appErr.Code, appErr.Message) 231 | } 232 | return NewResponseCheckTx(code.UnknownError, err.Error()) 233 | } 234 | 235 | return NewResponseCheckTx(code.OK, "") 236 | } 237 | 238 | func (app *ABCIApplication) createIdpResponse(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 239 | app.logger.Infof("CreateIdpResponse, Parameter: %s", param) 240 | var funcParam CreateIdpResponseParam 241 | err := json.Unmarshal(param, &funcParam) 242 | if err != nil { 243 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 244 | } 245 | 246 | err = app.validateCreateIdpResponse(funcParam, callerNodeID, false, false) 247 | if err != nil { 248 | if appErr, ok := err.(*ApplicationError); ok { 249 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 250 | } 251 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 252 | } 253 | 254 | // get request 255 | requestKey := requestKeyPrefix + keySeparator + funcParam.RequestID 256 | value, err := app.state.GetVersioned([]byte(requestKey), 0, false) 257 | if err != nil { 258 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 259 | } 260 | var request data.Request 261 | err = proto.Unmarshal([]byte(value), &request) 262 | if err != nil { 263 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 264 | } 265 | 266 | response := data.Response{ 267 | IdpId: callerNodeID, 268 | } 269 | 270 | if funcParam.ErrorCode == nil { 271 | // normal response 272 | response.Ial = funcParam.Ial 273 | response.Aal = funcParam.Aal 274 | response.Status = funcParam.Status 275 | response.Signature = funcParam.Signature 276 | } else { 277 | // error response 278 | response.ErrorCode = *funcParam.ErrorCode 279 | } 280 | 281 | request.ResponseList = append(request.ResponseList, &response) 282 | 283 | value, err = utils.ProtoDeterministicMarshal(&request) 284 | if err != nil { 285 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 286 | } 287 | err = app.state.SetVersioned([]byte(requestKey), []byte(value)) 288 | if err != nil { 289 | return app.NewExecTxResult(code.AppStateError, err.Error(), "") 290 | } 291 | 292 | return app.NewExecTxResult(code.OK, "success", funcParam.RequestID) 293 | } 294 | -------------------------------------------------------------------------------- /abci/app/v1/request_type.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | abcitypes "github.com/cometbft/cometbft/abci/types" 29 | goleveldbutil "github.com/syndtr/goleveldb/leveldb/util" 30 | 31 | "github.com/ndidplatform/smart-contract/v9/abci/code" 32 | "github.com/ndidplatform/smart-contract/v9/abci/utils" 33 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 34 | ) 35 | 36 | type AddRequestTypeParam struct { 37 | Name string `json:"name"` 38 | } 39 | 40 | func (app *ABCIApplication) validateAddRequestType(funcParam AddRequestTypeParam, callerNodeID string, committedState bool, checktx bool) error { 41 | // permission 42 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 43 | if err != nil { 44 | return err 45 | } 46 | if !ok { 47 | return &ApplicationError{ 48 | Code: code.NoPermissionForCallNDIDMethod, 49 | Message: "This node does not have permission to call NDID method", 50 | } 51 | } 52 | 53 | if checktx { 54 | return nil 55 | } 56 | 57 | // stateful 58 | 59 | key := requestTypeKeyPrefix + keySeparator + funcParam.Name 60 | exists, err := app.state.Has([]byte(key), committedState) 61 | if err != nil { 62 | return &ApplicationError{ 63 | Code: code.AppStateError, 64 | Message: err.Error(), 65 | } 66 | } 67 | if exists { 68 | return &ApplicationError{ 69 | Code: code.RequestTypeAlreadyExists, 70 | Message: "request type already exists", 71 | } 72 | } 73 | 74 | return nil 75 | } 76 | 77 | func (app *ABCIApplication) addRequestTypeCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 78 | var funcParam AddRequestTypeParam 79 | err := json.Unmarshal(param, &funcParam) 80 | if err != nil { 81 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 82 | } 83 | 84 | err = app.validateAddRequestType(funcParam, callerNodeID, true, true) 85 | if err != nil { 86 | if appErr, ok := err.(*ApplicationError); ok { 87 | return NewResponseCheckTx(appErr.Code, appErr.Message) 88 | } 89 | return NewResponseCheckTx(code.UnknownError, err.Error()) 90 | } 91 | 92 | return NewResponseCheckTx(code.OK, "") 93 | } 94 | 95 | // regulator only 96 | func (app *ABCIApplication) addRequestType(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 97 | app.logger.Infof("AddRequestType, Parameter: %s", param) 98 | var funcParam AddRequestTypeParam 99 | err := json.Unmarshal(param, &funcParam) 100 | if err != nil { 101 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 102 | } 103 | 104 | err = app.validateAddRequestType(funcParam, callerNodeID, false, false) 105 | if err != nil { 106 | if appErr, ok := err.(*ApplicationError); ok { 107 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 108 | } 109 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 110 | } 111 | 112 | key := requestTypeKeyPrefix + keySeparator + funcParam.Name 113 | 114 | var requestType data.RequestType 115 | value, err := utils.ProtoDeterministicMarshal(&requestType) 116 | if err != nil { 117 | return app.NewExecTxResult(code.MarshalError, err.Error(), "") 118 | } 119 | 120 | app.state.Set([]byte(key), value) 121 | 122 | return app.NewExecTxResult(code.OK, "success", "") 123 | } 124 | 125 | type RemoveRequestTypeParam struct { 126 | Name string `json:"name"` 127 | } 128 | 129 | func (app *ABCIApplication) validateRemoveRequestType(funcParam RemoveRequestTypeParam, callerNodeID string, committedState bool, checktx bool) error { 130 | // permission 131 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 132 | if err != nil { 133 | return err 134 | } 135 | if !ok { 136 | return &ApplicationError{ 137 | Code: code.NoPermissionForCallNDIDMethod, 138 | Message: "This node does not have permission to call NDID method", 139 | } 140 | } 141 | 142 | if checktx { 143 | return nil 144 | } 145 | 146 | // stateful 147 | 148 | key := requestTypeKeyPrefix + keySeparator + funcParam.Name 149 | exists, err := app.state.Has([]byte(key), committedState) 150 | if err != nil { 151 | return &ApplicationError{ 152 | Code: code.AppStateError, 153 | Message: err.Error(), 154 | } 155 | } 156 | if !exists { 157 | return &ApplicationError{ 158 | Code: code.RequestTypeDoesNotExist, 159 | Message: "request type does not exist", 160 | } 161 | } 162 | 163 | return nil 164 | } 165 | 166 | func (app *ABCIApplication) removeRequestTypeCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 167 | var funcParam RemoveRequestTypeParam 168 | err := json.Unmarshal(param, &funcParam) 169 | if err != nil { 170 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 171 | } 172 | 173 | err = app.validateRemoveRequestType(funcParam, callerNodeID, true, true) 174 | if err != nil { 175 | if appErr, ok := err.(*ApplicationError); ok { 176 | return NewResponseCheckTx(appErr.Code, appErr.Message) 177 | } 178 | return NewResponseCheckTx(code.UnknownError, err.Error()) 179 | } 180 | 181 | return NewResponseCheckTx(code.OK, "") 182 | } 183 | 184 | // regulator only 185 | func (app *ABCIApplication) removeRequestType(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 186 | app.logger.Infof("RemoveRequestType, Parameter: %s", param) 187 | var funcParam RemoveRequestTypeParam 188 | err := json.Unmarshal(param, &funcParam) 189 | if err != nil { 190 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 191 | } 192 | 193 | err = app.validateRemoveRequestType(funcParam, callerNodeID, false, false) 194 | if err != nil { 195 | if appErr, ok := err.(*ApplicationError); ok { 196 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 197 | } 198 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 199 | } 200 | 201 | key := requestTypeKeyPrefix + keySeparator + funcParam.Name 202 | 203 | app.state.Delete([]byte(key)) 204 | 205 | return app.NewExecTxResult(code.OK, "success", "") 206 | } 207 | 208 | type GetRequestTypeListParam struct { 209 | Prefix string `json:"prefix"` 210 | } 211 | 212 | func (app *ABCIApplication) getRequestTypeList(param []byte, height int64) *abcitypes.ResponseQuery { 213 | app.logger.Infof("GetRequestTypeList, Parameter: %s", param) 214 | var funcParam GetRequestTypeListParam 215 | err := json.Unmarshal(param, &funcParam) 216 | if err != nil { 217 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 218 | } 219 | 220 | result := make([]string, 0) 221 | 222 | requestTypeKeyIteratorBasePrefix := requestTypeKeyPrefix + keySeparator 223 | requestTypeKeyIteratorPrefix := requestTypeKeyIteratorBasePrefix + funcParam.Prefix 224 | r := goleveldbutil.BytesPrefix([]byte(requestTypeKeyIteratorPrefix)) 225 | iter, err := app.state.db.Iterator(r.Start, r.Limit) 226 | if err != nil { 227 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 228 | } 229 | for ; iter.Valid(); iter.Next() { 230 | key := iter.Key() 231 | 232 | runes := []rune(string(key)) 233 | requestType := string(runes[len(requestTypeKeyIteratorBasePrefix):]) 234 | 235 | result = append(result, requestType) 236 | } 237 | iter.Close() 238 | 239 | resultJSON, err := json.Marshal(result) 240 | if err != nil { 241 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 242 | } 243 | 244 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 245 | } 246 | -------------------------------------------------------------------------------- /abci/app/v1/service.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "encoding/json" 27 | 28 | "google.golang.org/protobuf/proto" 29 | 30 | abcitypes "github.com/cometbft/cometbft/abci/types" 31 | data "github.com/ndidplatform/smart-contract/v9/protos/data" 32 | ) 33 | 34 | type ServiceDetail struct { 35 | ServiceID string `json:"service_id"` 36 | ServiceName string `json:"service_name"` 37 | DataSchema string `json:"data_schema"` 38 | DataSchemaVersion string `json:"data_schema_version"` 39 | Active bool `json:"active"` 40 | } 41 | 42 | type GetServiceDetailParam struct { 43 | ServiceID string `json:"service_id"` 44 | } 45 | 46 | func (app *ABCIApplication) getServiceDetail(param []byte) *abcitypes.ResponseQuery { 47 | app.logger.Infof("GetServiceDetail, Parameter: %s", param) 48 | var funcParam GetServiceDetailParam 49 | err := json.Unmarshal(param, &funcParam) 50 | if err != nil { 51 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 52 | } 53 | key := serviceKeyPrefix + keySeparator + funcParam.ServiceID 54 | value, err := app.state.Get([]byte(key), true) 55 | if err != nil { 56 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 57 | } 58 | if value == nil { 59 | value = []byte("{}") 60 | return app.NewResponseQuery(value, "not found", app.state.Height) 61 | } 62 | var service data.ServiceDetail 63 | err = proto.Unmarshal(value, &service) 64 | if err != nil { 65 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 66 | } 67 | returnValue, err := json.Marshal(&service) 68 | if err != nil { 69 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 70 | } 71 | return app.NewResponseQuery(returnValue, "success", app.state.Height) 72 | } 73 | 74 | func (app *ABCIApplication) getServiceList(param []byte) *abcitypes.ResponseQuery { 75 | app.logger.Infof("GetServiceList, Parameter: %s", param) 76 | key := "AllService" 77 | value, err := app.state.Get([]byte(key), true) 78 | if err != nil { 79 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 80 | } 81 | if value == nil { 82 | result := make([]ServiceDetail, 0) 83 | value, err := json.Marshal(result) 84 | if err != nil { 85 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 86 | } 87 | return app.NewResponseQuery(value, "not found", app.state.Height) 88 | } 89 | result := make([]*data.ServiceDetail, 0) 90 | // filter flag==true 91 | var services data.ServiceDetailList 92 | err = proto.Unmarshal([]byte(value), &services) 93 | if err != nil { 94 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 95 | } 96 | for _, service := range services.Services { 97 | if service.Active { 98 | result = append(result, service) 99 | } 100 | } 101 | returnValue, err := json.Marshal(result) 102 | if err != nil { 103 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 104 | } 105 | return app.NewResponseQuery(returnValue, "success", app.state.Height) 106 | } 107 | 108 | func (app *ABCIApplication) getServiceNameByServiceID(serviceID string) string { 109 | key := serviceKeyPrefix + keySeparator + serviceID 110 | value, err := app.state.Get([]byte(key), true) 111 | if err != nil { 112 | panic(err) 113 | } 114 | if value == nil { 115 | return "" 116 | } 117 | var result ServiceDetail 118 | err = json.Unmarshal([]byte(value), &result) 119 | if err != nil { 120 | return "" 121 | } 122 | return result.ServiceName 123 | } 124 | 125 | type GetServicesByAsIDParam struct { 126 | AsID string `json:"as_id"` 127 | } 128 | 129 | type GetServicesByAsIDResult struct { 130 | Services []Service `json:"services"` 131 | } 132 | 133 | type Service struct { 134 | ServiceID string `json:"service_id"` 135 | MinIal float64 `json:"min_ial"` 136 | MinAal float64 `json:"min_aal"` 137 | Active bool `json:"active"` 138 | Suspended bool `json:"suspended"` 139 | SupportedNamespaceList []string `json:"supported_namespace_list"` 140 | } 141 | 142 | func (app *ABCIApplication) getServicesByAsID(param []byte) *abcitypes.ResponseQuery { 143 | app.logger.Infof("GetServicesByAsID, Parameter: %s", param) 144 | var funcParam GetServicesByAsIDParam 145 | err := json.Unmarshal(param, &funcParam) 146 | if err != nil { 147 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 148 | } 149 | var result GetServicesByAsIDResult 150 | result.Services = make([]Service, 0) 151 | provideServiceKey := providedServicesKeyPrefix + keySeparator + funcParam.AsID 152 | provideServiceValue, err := app.state.Get([]byte(provideServiceKey), true) 153 | if err != nil { 154 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 155 | } 156 | if provideServiceValue == nil { 157 | resultJSON, err := json.Marshal(result) 158 | if err != nil { 159 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 160 | } 161 | return app.NewResponseQuery(resultJSON, "not found", app.state.Height) 162 | } 163 | var services data.ServiceList 164 | err = proto.Unmarshal([]byte(provideServiceValue), &services) 165 | if err != nil { 166 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 167 | } 168 | nodeDetailKey := nodeIDKeyPrefix + keySeparator + funcParam.AsID 169 | nodeDetailValue, err := app.state.Get([]byte(nodeDetailKey), true) 170 | if err != nil { 171 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 172 | } 173 | if nodeDetailValue == nil { 174 | resultJSON, err := json.Marshal(result) 175 | if err != nil { 176 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 177 | } 178 | return app.NewResponseQuery(resultJSON, "not found", app.state.Height) 179 | } 180 | var nodeDetail data.NodeDetail 181 | err = proto.Unmarshal([]byte(nodeDetailValue), &nodeDetail) 182 | if err != nil { 183 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 184 | } 185 | for index, provideService := range services.Services { 186 | serviceKey := serviceKeyPrefix + keySeparator + provideService.ServiceId 187 | serviceValue, err := app.state.Get([]byte(serviceKey), true) 188 | if err != nil { 189 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 190 | } 191 | if serviceValue == nil { 192 | continue 193 | } 194 | var service data.ServiceDetail 195 | err = proto.Unmarshal([]byte(serviceValue), &service) 196 | if err != nil { 197 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 198 | } 199 | if nodeDetail.Active && service.Active { 200 | // Set suspended from NDID 201 | approveServiceKey := approvedServiceKeyPrefix + keySeparator + provideService.ServiceId + keySeparator + funcParam.AsID 202 | approveServiceJSON, err := app.state.Get([]byte(approveServiceKey), true) 203 | if err != nil { 204 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 205 | } 206 | if approveServiceJSON == nil { 207 | continue 208 | } 209 | var approveService data.ApproveService 210 | err = proto.Unmarshal([]byte(approveServiceJSON), &approveService) 211 | if err == nil { 212 | services.Services[index].Suspended = !approveService.Active 213 | } 214 | var newRow Service 215 | newRow.Active = services.Services[index].Active 216 | newRow.MinAal = services.Services[index].MinAal 217 | newRow.MinIal = services.Services[index].MinIal 218 | newRow.ServiceID = services.Services[index].ServiceId 219 | newRow.Suspended = services.Services[index].Suspended 220 | newRow.SupportedNamespaceList = services.Services[index].SupportedNamespaceList 221 | result.Services = append(result.Services, newRow) 222 | } 223 | } 224 | resultJSON, err := json.Marshal(result) 225 | if err != nil { 226 | return app.NewResponseQuery(nil, err.Error(), app.state.Height) 227 | } 228 | if len(result.Services) == 0 { 229 | return app.NewResponseQuery(resultJSON, "not found", app.state.Height) 230 | } 231 | return app.NewResponseQuery(resultJSON, "success", app.state.Height) 232 | } 233 | -------------------------------------------------------------------------------- /abci/app/v1/state_initial.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "bufio" 27 | "crypto/sha256" 28 | "encoding/json" 29 | "io" 30 | "io/ioutil" 31 | "os" 32 | "path/filepath" 33 | "time" 34 | 35 | "github.com/sirupsen/logrus" 36 | ) 37 | 38 | const ( 39 | initialStateDataFilename string = "data" 40 | initialStateMetadataFilename string = "metadata" 41 | ) 42 | 43 | const ( 44 | syncWriteEvery = 50000 45 | ) 46 | 47 | const ( 48 | logProgressEvery = 100000 49 | ) 50 | 51 | type InitialStateMetadata struct { 52 | TotalKeyCount int64 `json:"total_key_count"` 53 | } 54 | 55 | func (appState *AppState) LoadInitialState(logger *logrus.Entry, initialStateDir string) (hash []byte, err error) { 56 | startTime := time.Now() 57 | 58 | metadataJSON, err := ioutil.ReadFile(filepath.Join(initialStateDir, initialStateMetadataFilename)) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | // read metadata 64 | var initialStateMetadata InitialStateMetadata 65 | err = json.Unmarshal(metadataJSON, &initialStateMetadata) 66 | if err != nil { 67 | panic(err) 68 | } 69 | 70 | logger.Infof( 71 | "Initial state data total key count: %d", 72 | initialStateMetadata.TotalKeyCount, 73 | ) 74 | 75 | dataFile, err := os.Open(filepath.Join(initialStateDir, initialStateDataFilename)) 76 | if err != nil { 77 | return nil, err 78 | } 79 | defer dataFile.Close() 80 | 81 | hashDigest := sha256.New() 82 | 83 | keyCount := int64(0) 84 | 85 | reader := bufio.NewReader(dataFile) 86 | for { 87 | line, err := reader.ReadString('\n') 88 | 89 | if err != nil { 90 | if err == io.EOF { 91 | break 92 | } else { 93 | logger.Fatalf("initial state data read error at line: %d err: %+v", keyCount+1, err) 94 | return nil, err 95 | } 96 | } 97 | 98 | var kv KeyValue 99 | err = json.Unmarshal([]byte(line), &kv) 100 | if err != nil { 101 | panic(err) 102 | } 103 | 104 | hashDigest.Write(kv.Key) 105 | hashDigest.Write(actionSet) 106 | hashDigest.Write(kv.Value) 107 | 108 | if keyCount+1%syncWriteEvery == 0 || keyCount+1 == initialStateMetadata.TotalKeyCount { 109 | err = appState.db.SetSync(kv.Key, kv.Value) 110 | if err != nil { 111 | return nil, err 112 | } 113 | } else { 114 | err = appState.db.Set(kv.Key, kv.Value) 115 | if err != nil { 116 | return nil, err 117 | } 118 | } 119 | 120 | keyCount++ 121 | 122 | if keyCount%logProgressEvery == 0 { 123 | logger.Infof( 124 | "Initial state data keys written: %d/%d (%.2f%%)", 125 | keyCount, 126 | initialStateMetadata.TotalKeyCount, 127 | (float64(keyCount)/float64(initialStateMetadata.TotalKeyCount))*100, 128 | ) 129 | } 130 | } 131 | 132 | logger.Infof("Initial state data loaded, time used: %s", time.Since(startTime)) 133 | 134 | hash = hashDigest.Sum(nil) 135 | 136 | return hash, nil 137 | } 138 | -------------------------------------------------------------------------------- /abci/app/v1/types/node_role.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type NodeRole string 4 | 5 | const ( 6 | NodeRoleNdid NodeRole = "NDID" 7 | NodeRoleRp NodeRole = "RP" 8 | NodeRoleIdp NodeRole = "IdP" 9 | NodeRoleAs NodeRole = "AS" 10 | NodeRoleProxy NodeRole = "Proxy" 11 | ) 12 | -------------------------------------------------------------------------------- /abci/app/v1/types/signature_algorithm.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type SignatureAlgorithm string 4 | 5 | const ( 6 | SignatureAlgorithmRSAPSSSHA256 SignatureAlgorithm = "RSASSA_PSS_SHA_256" 7 | SignatureAlgorithmRSAPSSSHA384 SignatureAlgorithm = "RSASSA_PSS_SHA_384" 8 | SignatureAlgorithmRSAPSSSHA512 SignatureAlgorithm = "RSASSA_PSS_SHA_512" 9 | SignatureAlgorithmRSAPKCS1V15SHA256 SignatureAlgorithm = "RSASSA_PKCS1_V1_5_SHA_256" 10 | SignatureAlgorithmRSAPKCS1V15SHA384 SignatureAlgorithm = "RSASSA_PKCS1_V1_5_SHA_384" 11 | SignatureAlgorithmRSAPKCS1V15SHA512 SignatureAlgorithm = "RSASSA_PKCS1_V1_5_SHA_512" 12 | 13 | SignatureAlgorithmECDSASHA256 SignatureAlgorithm = "ECDSA_SHA_256" 14 | SignatureAlgorithmECDSASHA384 SignatureAlgorithm = "ECDSA_SHA_384" 15 | 16 | SignatureAlgorithmEd25519 SignatureAlgorithm = "Ed25519" 17 | ) 18 | -------------------------------------------------------------------------------- /abci/app/v1/validator.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package app 24 | 25 | import ( 26 | "bytes" 27 | "encoding/base64" 28 | "encoding/json" 29 | "fmt" 30 | 31 | abcitypes "github.com/cometbft/cometbft/abci/types" 32 | "github.com/cometbft/cometbft/crypto/ed25519" 33 | 34 | "github.com/ndidplatform/smart-contract/v9/abci/code" 35 | ) 36 | 37 | func (app *ABCIApplication) Validators() (validators []abcitypes.Validator) { 38 | app.logger.Infof("Validators") 39 | itr, err := app.state.db.Iterator(nil, nil) 40 | if err != nil { 41 | panic(err) 42 | } 43 | defer itr.Close() 44 | for ; itr.Valid(); itr.Next() { 45 | key := itr.Key() 46 | validator := new(abcitypes.Validator) 47 | err := abcitypes.ReadMessage(bytes.NewBuffer(key), validator) 48 | if err != nil { 49 | panic(err) 50 | } 51 | validators = append(validators, *validator) 52 | } 53 | return 54 | } 55 | 56 | // add, update, or remove a validator 57 | func (app *ABCIApplication) updateValidator(v abcitypes.ValidatorUpdate) *abcitypes.ExecTxResult { 58 | pubKeyBase64 := base64.StdEncoding.EncodeToString(v.PubKey.GetEd25519()) 59 | key := []byte(validatorKeyPrefix + keySeparator + pubKeyBase64) 60 | 61 | if v.Power == 0 { 62 | // remove validator 63 | hasKey, err := app.state.Has(key, false) 64 | if err != nil { 65 | panic(err) 66 | } 67 | if !hasKey { 68 | return app.NewExecTxResult(code.NotExistValidator, fmt.Sprintf("Cannot remove non-existent validator %X", key), "") 69 | } 70 | app.state.Delete(key) 71 | } else { 72 | // add or update validator 73 | value := bytes.NewBuffer(make([]byte, 0)) 74 | if err := abcitypes.WriteMessage(&v, value); err != nil { 75 | return app.NewExecTxResult(code.EncodingError, fmt.Sprintf("Error encoding validator: %v", err), "") 76 | } 77 | app.state.Set(key, value.Bytes()) 78 | } 79 | 80 | app.valUpdates[pubKeyBase64] = v 81 | return app.NewExecTxResult(code.OK, "success", "") 82 | } 83 | 84 | type SetValidatorParam struct { 85 | PublicKey string `json:"public_key"` 86 | Power int64 `json:"power"` 87 | } 88 | 89 | func (app *ABCIApplication) validateSetValidator(funcParam SetValidatorParam, callerNodeID string, committedState bool, checktx bool) error { 90 | // permission 91 | ok, err := app.isNDIDNodeByNodeID(callerNodeID, committedState) 92 | if err != nil { 93 | return err 94 | } 95 | if !ok { 96 | return &ApplicationError{ 97 | Code: code.NoPermissionForCallNDIDMethod, 98 | Message: "This node does not have permission to call NDID method", 99 | } 100 | } 101 | 102 | // stateless 103 | 104 | // validate ed25519 public key 105 | pubKey, err := base64.StdEncoding.DecodeString(funcParam.PublicKey) 106 | if err != nil { 107 | return &ApplicationError{ 108 | Code: code.DecodingError, 109 | Message: err.Error(), 110 | } 111 | } 112 | if len(pubKey) != ed25519.PubKeySize { 113 | err = fmt.Errorf("invalid Ed25519 public key size. Got %d, expected %d", len(pubKey), ed25519.PubKeySize) 114 | return &ApplicationError{ 115 | Code: code.InvalidValidatorPublicKey, 116 | Message: err.Error(), 117 | } 118 | } 119 | 120 | if funcParam.Power < 0 { 121 | return &ApplicationError{ 122 | Code: code.InvalidValidatorVotingPower, 123 | Message: "voting power can't be negative", 124 | } 125 | } 126 | 127 | return nil 128 | } 129 | 130 | func (app *ABCIApplication) setValidatorCheckTx(param []byte, callerNodeID string) *abcitypes.ResponseCheckTx { 131 | var funcParam SetValidatorParam 132 | err := json.Unmarshal(param, &funcParam) 133 | if err != nil { 134 | return NewResponseCheckTx(code.UnmarshalError, err.Error()) 135 | } 136 | 137 | err = app.validateSetValidator(funcParam, callerNodeID, true, true) 138 | if err != nil { 139 | if appErr, ok := err.(*ApplicationError); ok { 140 | return NewResponseCheckTx(appErr.Code, appErr.Message) 141 | } 142 | return NewResponseCheckTx(code.UnknownError, err.Error()) 143 | } 144 | 145 | return NewResponseCheckTx(code.OK, "") 146 | } 147 | 148 | func (app *ABCIApplication) setValidator(param []byte, callerNodeID string) *abcitypes.ExecTxResult { 149 | app.logger.Infof("SetValidator, Parameter: %s", param) 150 | var funcParam SetValidatorParam 151 | err := json.Unmarshal(param, &funcParam) 152 | if err != nil { 153 | return app.NewExecTxResult(code.UnmarshalError, err.Error(), "") 154 | } 155 | 156 | err = app.validateSetValidator(funcParam, callerNodeID, false, false) 157 | if err != nil { 158 | if appErr, ok := err.(*ApplicationError); ok { 159 | return app.NewExecTxResult(appErr.Code, appErr.Message, "") 160 | } 161 | return app.NewExecTxResult(code.UnknownError, err.Error(), "") 162 | } 163 | 164 | pubKey, err := base64.StdEncoding.DecodeString(funcParam.PublicKey) 165 | if err != nil { 166 | return app.NewExecTxResult(code.DecodingError, err.Error(), "") 167 | } 168 | 169 | return app.updateValidator(abcitypes.UpdateValidator(pubKey, funcParam.Power, ed25519.KeyType)) 170 | } 171 | -------------------------------------------------------------------------------- /abci/commands.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | 28 | "github.com/spf13/cobra" 29 | 30 | "github.com/ndidplatform/smart-contract/v9/abci/version" 31 | ) 32 | 33 | var abciVersionCmd = &cobra.Command{ 34 | Use: "abci_app_version", 35 | Short: "Show DID ABCI app version info", 36 | Run: func(cmd *cobra.Command, args []string) { 37 | fmt.Println(version.Version) 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /abci/server.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package main 24 | 25 | import ( 26 | "fmt" 27 | "os" 28 | "path/filepath" 29 | "strconv" 30 | "time" 31 | 32 | "github.com/sirupsen/logrus" 33 | 34 | abcitypes "github.com/cometbft/cometbft/abci/types" 35 | cmd "github.com/cometbft/cometbft/cmd/cometbft/commands" 36 | "github.com/cometbft/cometbft/cmd/cometbft/commands/debug" 37 | cfg "github.com/cometbft/cometbft/config" 38 | "github.com/cometbft/cometbft/libs/cli" 39 | cmtlog "github.com/cometbft/cometbft/libs/log" 40 | nm "github.com/cometbft/cometbft/node" 41 | "github.com/cometbft/cometbft/p2p" 42 | "github.com/cometbft/cometbft/privval" 43 | "github.com/cometbft/cometbft/proxy" 44 | 45 | abciApp "github.com/ndidplatform/smart-contract/v9/abci/app" 46 | ) 47 | 48 | const ( 49 | fileDatetimeFormat = "02-01-2006_15-04-05" 50 | logTargetConsole = "console" 51 | logTargetFile = "file" 52 | ) 53 | 54 | func init() { 55 | // Set default logrus 56 | 57 | var logLevel = getEnv("ABCI_LOG_LEVEL", "debug") 58 | var logTarget = getEnv("ABCI_LOG_TARGET", logTargetConsole) 59 | 60 | currentTime := time.Now() 61 | currentTimeStr := currentTime.Format(fileDatetimeFormat) 62 | 63 | var logFilePath = getEnv("ABCI_LOG_FILE_PATH", "./abci-"+strconv.Itoa(os.Getpid())+"-"+currentTimeStr+".log") 64 | 65 | if logTarget == logTargetConsole { 66 | logrus.SetOutput(os.Stdout) 67 | } else if logTarget == logTargetFile { 68 | logFile, _ := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) 69 | logrus.SetOutput(logFile) 70 | } else { 71 | panic(fmt.Errorf("unknown log target: \"%s\". Only \"console\" and \"file\" are allowed", logTarget)) 72 | } 73 | 74 | switch logLevel { 75 | case "error": 76 | logrus.SetLevel(logrus.ErrorLevel) 77 | case "warn": 78 | logrus.SetLevel(logrus.WarnLevel) 79 | case "info": 80 | logrus.SetLevel(logrus.InfoLevel) 81 | default: 82 | logrus.SetLevel(logrus.DebugLevel) 83 | } 84 | 85 | customFormatter := new(logrus.TextFormatter) 86 | customFormatter.TimestampFormat = "2006-01-02 15:04:05" 87 | customFormatter.FullTimestamp = true 88 | logrus.SetFormatter(customFormatter) 89 | // mainLogger = logrus.WithFields(logrus.Fields{"module": "abci-app"}) 90 | } 91 | 92 | // Ref: https://github.com/cometbft/cometbft/blob/main/cmd/cometbft/main.go 93 | func main() { 94 | 95 | //prometheus 96 | // var prometheusPort = getEnv("PROMETHEUS_PORT", "2112") 97 | // http.Handle("/metrics", promhttp.Handler()) 98 | // go http.ListenAndServe(":"+prometheusPort, nil) 99 | 100 | rootCmd := cmd.RootCmd 101 | rootCmd.AddCommand( 102 | cmd.GenValidatorCmd, 103 | cmd.InitFilesCmd, 104 | cmd.LightCmd, 105 | cmd.ResetAllCmd, 106 | cmd.ResetPrivValidatorCmd, 107 | cmd.ResetStateCmd, 108 | cmd.ShowValidatorCmd, 109 | cmd.TestnetFilesCmd, 110 | cmd.ShowNodeIDCmd, 111 | cmd.GenNodeKeyCmd, 112 | cmd.VersionCmd, 113 | cmd.RollbackStateCmd, 114 | cmd.CompactGoLevelDBCmd, 115 | cmd.InspectCmd, 116 | debug.DebugCmd, 117 | cli.NewCompletionCmd(rootCmd, true), 118 | // custom commands 119 | abciVersionCmd, 120 | ) 121 | 122 | // NOTE: 123 | // Users wishing to: 124 | // * Use an external signer for their validators 125 | // * Supply an in-proc abci app 126 | // * Supply a genesis doc file from another source 127 | // * Provide their own DB implementation 128 | // can copy this file and use something other than the 129 | 130 | nodeFunc := newNode 131 | 132 | // Create & start node 133 | rootCmd.AddCommand(cmd.NewRunNodeCmd(nodeFunc)) 134 | 135 | cmd := cli.PrepareBaseCmd(rootCmd, "CMT", os.ExpandEnv(filepath.Join("$HOME", cfg.DefaultTendermintDir))) 136 | if err := cmd.Execute(); err != nil { 137 | panic(err) 138 | } 139 | } 140 | 141 | func newNode(config *cfg.Config, logger cmtlog.Logger) (*nm.Node, error) { 142 | var app abcitypes.Application = abciApp.NewABCIApplicationInterface() 143 | 144 | // read private validator 145 | pv := privval.LoadFilePV( 146 | config.PrivValidatorKeyFile(), 147 | config.PrivValidatorStateFile(), 148 | ) 149 | 150 | // read node key 151 | nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile()) 152 | if err != nil { 153 | return nil, fmt.Errorf("failed to load node's key: %w", err) 154 | } 155 | 156 | // create node 157 | node, err := nm.NewNode( 158 | config, 159 | pv, 160 | nodeKey, 161 | proxy.NewLocalClientCreator(app), 162 | nm.DefaultGenesisDocProviderFunc(config), 163 | cfg.DefaultDBProvider, 164 | nm.DefaultMetricsProvider(config.Instrumentation), 165 | logger, 166 | ) 167 | if err != nil { 168 | return nil, fmt.Errorf("failed to create new Tendermint node: %w", err) 169 | } 170 | 171 | return node, nil 172 | } 173 | 174 | func getEnv(key, defaultValue string) string { 175 | value, exists := os.LookupEnv(key) 176 | if !exists { 177 | value = defaultValue 178 | } 179 | return value 180 | } 181 | -------------------------------------------------------------------------------- /abci/utils/map.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package utils 24 | 25 | import ( 26 | "sync" 27 | ) 28 | 29 | type StringMap struct { 30 | sync.RWMutex 31 | internal map[string]string 32 | } 33 | 34 | func NewStringMap() *StringMap { 35 | return &StringMap{ 36 | internal: make(map[string]string), 37 | } 38 | } 39 | 40 | func (rm *StringMap) Load(key string) (value string, ok bool) { 41 | rm.RLock() 42 | result, ok := rm.internal[key] 43 | rm.RUnlock() 44 | return result, ok 45 | } 46 | 47 | func (rm *StringMap) Delete(key string) { 48 | rm.Lock() 49 | delete(rm.internal, key) 50 | rm.Unlock() 51 | } 52 | 53 | func (rm *StringMap) Store(key, value string) { 54 | rm.Lock() 55 | rm.internal[key] = value 56 | rm.Unlock() 57 | } 58 | 59 | type StringByteArrayMap struct { 60 | sync.RWMutex 61 | internal map[string][]byte 62 | } 63 | 64 | func NewStringByteArrayMap() *StringByteArrayMap { 65 | return &StringByteArrayMap{ 66 | internal: make(map[string][]byte), 67 | } 68 | } 69 | 70 | func (rm *StringByteArrayMap) Load(key string) (value []byte, ok bool) { 71 | rm.RLock() 72 | result, ok := rm.internal[key] 73 | rm.RUnlock() 74 | return result, ok 75 | } 76 | 77 | func (rm *StringByteArrayMap) Delete(key string) { 78 | rm.Lock() 79 | delete(rm.internal, key) 80 | rm.Unlock() 81 | } 82 | 83 | func (rm *StringByteArrayMap) Store(key string, value []byte) { 84 | rm.Lock() 85 | rm.internal[key] = value 86 | rm.Unlock() 87 | } 88 | -------------------------------------------------------------------------------- /abci/utils/utils.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package utils 24 | 25 | import ( 26 | "encoding/json" 27 | "fmt" 28 | "os" 29 | "time" 30 | 31 | "google.golang.org/protobuf/proto" 32 | ) 33 | 34 | func ProtoDeterministicMarshal(m proto.Message) ([]byte, error) { 35 | b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) 36 | if err != nil { 37 | return nil, err 38 | } 39 | retBytes := b 40 | if b == nil { 41 | retBytes = make([]byte, 0) 42 | } 43 | return retBytes, nil 44 | } 45 | 46 | func WriteEventLogTx(filename string, time time.Time, name string, function string, nonce string) { 47 | createDirIfNotExist("event_log") 48 | f, err := os.OpenFile("event_log/"+filename+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 49 | if err != nil { 50 | panic(err) 51 | } 52 | defer f.Close() 53 | var eventLog EventLogTx 54 | eventLog.Datetime = time.UnixNano() / 1000000 55 | eventLog.Name = name 56 | eventLog.Function = function 57 | eventLog.Nonce = nonce 58 | eventLogJSON, err := json.Marshal(eventLog) 59 | if err != nil { 60 | fmt.Println("error:", err) 61 | } 62 | _, err = f.WriteString(string(eventLogJSON) + "\r\n") 63 | if err != nil { 64 | panic(err) 65 | } 66 | } 67 | 68 | type EventLogTx struct { 69 | Datetime int64 `json:"datetime"` 70 | Name string `json:"name"` 71 | Function string `json:"function"` 72 | Nonce string `json:"nonce"` 73 | } 74 | 75 | func WriteEventLogBeginBlock(filename string, time time.Time, name string, height int64, numTxs int64) { 76 | createDirIfNotExist("event_log") 77 | f, err := os.OpenFile("event_log/"+filename+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 78 | if err != nil { 79 | panic(err) 80 | } 81 | defer f.Close() 82 | var eventLog EventLogBeginBlock 83 | eventLog.Datetime = time.UnixNano() / 1000000 84 | eventLog.Name = name 85 | eventLog.Height = height 86 | eventLog.NumTxs = numTxs 87 | eventLogJSON, err := json.Marshal(eventLog) 88 | if err != nil { 89 | fmt.Println("error:", err) 90 | } 91 | _, err = f.WriteString(string(eventLogJSON) + "\r\n") 92 | if err != nil { 93 | panic(err) 94 | } 95 | } 96 | 97 | type EventLogBeginBlock struct { 98 | Datetime int64 `json:"datetime"` 99 | Name string `json:"name"` 100 | Height int64 `json:"height"` 101 | NumTxs int64 `json:"numTxs"` 102 | } 103 | 104 | func WriteEventLog(filename string, time time.Time, name string) { 105 | createDirIfNotExist("event_log") 106 | f, err := os.OpenFile("event_log/"+filename+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 107 | if err != nil { 108 | panic(err) 109 | } 110 | defer f.Close() 111 | var eventLog EventLog 112 | eventLog.Datetime = time.UnixNano() / 1000000 113 | eventLog.Name = name 114 | eventLogJSON, err := json.Marshal(eventLog) 115 | if err != nil { 116 | fmt.Println("error:", err) 117 | } 118 | _, err = f.WriteString(string(eventLogJSON) + "\r\n") 119 | if err != nil { 120 | panic(err) 121 | } 122 | } 123 | 124 | type EventLog struct { 125 | Datetime int64 `json:"datetime"` 126 | Name string `json:"name"` 127 | } 128 | 129 | func WriteEventLogQuery(filename string, time time.Time, name string, function string) { 130 | createDirIfNotExist("event_log") 131 | f, err := os.OpenFile("event_log/"+filename+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 132 | if err != nil { 133 | panic(err) 134 | } 135 | defer f.Close() 136 | var eventLog EventLogQuery 137 | eventLog.Datetime = time.UnixNano() / 1000000 138 | eventLog.Name = name 139 | eventLog.Function = function 140 | eventLogJSON, err := json.Marshal(eventLog) 141 | if err != nil { 142 | fmt.Println("error:", err) 143 | } 144 | _, err = f.WriteString(string(eventLogJSON) + "\r\n") 145 | if err != nil { 146 | panic(err) 147 | } 148 | } 149 | 150 | type EventLogQuery struct { 151 | Datetime int64 `json:"datetime"` 152 | Name string `json:"name"` 153 | Function string `json:"function"` 154 | } 155 | 156 | func WriteDurationLog(filename string, durationTime int64, function string, optionalParams ...string) { 157 | createDirIfNotExist("event_log") 158 | f, err := os.OpenFile("event_log/"+filename+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 159 | if err != nil { 160 | panic(err) 161 | } 162 | defer f.Close() 163 | 164 | var methodName string 165 | var nonceBase64 string 166 | 167 | if len(optionalParams) > 0 { 168 | if function == "CheckTx" { 169 | nonceBase64 = optionalParams[1] 170 | } 171 | methodName = optionalParams[0] 172 | } 173 | 174 | var eventLog DurationLog 175 | eventLog.Duration = durationTime 176 | eventLog.Function = function 177 | eventLog.Method = methodName 178 | eventLog.Nonce = nonceBase64 179 | eventLogJSON, err := json.Marshal(eventLog) 180 | if err != nil { 181 | fmt.Println("error:", err) 182 | } 183 | _, err = f.WriteString(string(eventLogJSON) + "\r\n") 184 | if err != nil { 185 | panic(err) 186 | } 187 | } 188 | 189 | type DurationLog struct { 190 | Duration int64 `json:"duration"` 191 | Function string `json:"function"` 192 | Method string `json:"method"` 193 | Nonce string `json:"nonce"` 194 | } 195 | 196 | func createDirIfNotExist(dir string) { 197 | if _, err := os.Stat(dir); os.IsNotExist(err) { 198 | err = os.MkdirAll(dir, 0755) 199 | if err != nil { 200 | panic(err) 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /abci/version/version.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@ndid.co.th for any further questions 20 | * 21 | */ 22 | 23 | package version 24 | 25 | var ( 26 | // GitCommit is the current HEAD set using ldflags. 27 | GitCommit string 28 | 29 | // Version is the built ABCI app version. 30 | Version string = ABCIAppSemVer 31 | 32 | // AppProtocolVersion is ABCI App protocol version. 33 | AppProtocolVersion uint64 = ABCIAppProtocolVersion 34 | ) 35 | 36 | func init() { 37 | if GitCommit != "" { 38 | Version += "-" + GitCommit 39 | } 40 | } 41 | 42 | const ( 43 | // ABCIAppSemVer is ABCI app version. 44 | ABCIAppSemVer = "9.0.0" 45 | 46 | // ABCIAppProtocolVersion is ABCI App protocol version. 47 | // Increment ONLY when backward compatibility is not possible or chain migration is needed. 48 | // Otherwise, new nodes won't be able to replay old blocks (created before ABCI code updates). 49 | ABCIAppProtocolVersion = 5 50 | ) 51 | -------------------------------------------------------------------------------- /config/tendermint/AS/config/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesis_time": "2024-03-22T11:27:07.802481591Z", 3 | "chain_id": "test-chain-NDID", 4 | "initial_height": "0", 5 | "consensus_params": { 6 | "block": { 7 | "max_bytes": "22020096", 8 | "max_gas": "-1" 9 | }, 10 | "evidence": { 11 | "max_age_num_blocks": "100000", 12 | "max_age_duration": "172800000000000", 13 | "max_bytes": "1048576" 14 | }, 15 | "validator": { 16 | "pub_key_types": [ 17 | "ed25519" 18 | ] 19 | }, 20 | "version": { 21 | "app": "0" 22 | }, 23 | "abci": { 24 | "vote_extensions_enable_height": "0" 25 | } 26 | }, 27 | "validators": [ 28 | { 29 | "address": "86123C049FB521F4CF44386AC1F62E652184790D", 30 | "pub_key": { 31 | "type": "tendermint/PubKeyEd25519", 32 | "value": "kRKM3mkPlogAhWLARAoE9nG+i+fFbZLQDMZoS1O50So=" 33 | }, 34 | "power": "10", 35 | "name": "" 36 | } 37 | ], 38 | "app_hash": "" 39 | } -------------------------------------------------------------------------------- /config/tendermint/AS/config/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"NQYCWMSCONfLIOkfBWs6ZupPF1I+tLow2VOkyPKVMwLYQvCU+XdLQOQs1TPX6pBmKbBieZfowVywiuKHX06ueg=="}} -------------------------------------------------------------------------------- /config/tendermint/AS/config/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "7D69E805D13B1748A3E1895CA5CB6BC3DE7B99EB", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "TVq7ovzVhpPEe7T9qwxfG7zkg1JzY9+dq3EyMnoUYuQ=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "dGJkQaJGjRnVReJRmEF/axjA9mJZ+IK/P0d6y5ZGk9BNWrui/NWGk8R7tP2rDF8bvOSDUnNj352rcTIyehRi5A==" 10 | } 11 | } -------------------------------------------------------------------------------- /config/tendermint/IdP/config/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesis_time": "2024-03-22T11:27:07.802481591Z", 3 | "chain_id": "test-chain-NDID", 4 | "initial_height": "0", 5 | "consensus_params": { 6 | "block": { 7 | "max_bytes": "22020096", 8 | "max_gas": "-1" 9 | }, 10 | "evidence": { 11 | "max_age_num_blocks": "100000", 12 | "max_age_duration": "172800000000000", 13 | "max_bytes": "1048576" 14 | }, 15 | "validator": { 16 | "pub_key_types": [ 17 | "ed25519" 18 | ] 19 | }, 20 | "version": { 21 | "app": "0" 22 | }, 23 | "abci": { 24 | "vote_extensions_enable_height": "0" 25 | } 26 | }, 27 | "validators": [ 28 | { 29 | "address": "86123C049FB521F4CF44386AC1F62E652184790D", 30 | "pub_key": { 31 | "type": "tendermint/PubKeyEd25519", 32 | "value": "kRKM3mkPlogAhWLARAoE9nG+i+fFbZLQDMZoS1O50So=" 33 | }, 34 | "power": "10", 35 | "name": "" 36 | } 37 | ], 38 | "app_hash": "" 39 | } -------------------------------------------------------------------------------- /config/tendermint/IdP/config/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"OZtC2C7lbf/WHkZBcQoCQ9uM1XcEpPt29RCOfNVYfPj0L7QkSrKnGLa6v7yh4RgEzMoegL7cNvEwTD7DmTJPlg=="}} -------------------------------------------------------------------------------- /config/tendermint/IdP/config/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "86123C049FB521F4CF44386AC1F62E652184790D", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "kRKM3mkPlogAhWLARAoE9nG+i+fFbZLQDMZoS1O50So=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "s5mnxZ87L4st1Aq54i3bu3zttDEdxceTGDDJok5ocV+REozeaQ+WiACFYsBECgT2cb6L58VtktAMxmhLU7nRKg==" 10 | } 11 | } -------------------------------------------------------------------------------- /config/tendermint/RP/config/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesis_time": "2024-03-22T11:27:07.802481591Z", 3 | "chain_id": "test-chain-NDID", 4 | "initial_height": "0", 5 | "consensus_params": { 6 | "block": { 7 | "max_bytes": "22020096", 8 | "max_gas": "-1" 9 | }, 10 | "evidence": { 11 | "max_age_num_blocks": "100000", 12 | "max_age_duration": "172800000000000", 13 | "max_bytes": "1048576" 14 | }, 15 | "validator": { 16 | "pub_key_types": [ 17 | "ed25519" 18 | ] 19 | }, 20 | "version": { 21 | "app": "0" 22 | }, 23 | "abci": { 24 | "vote_extensions_enable_height": "0" 25 | } 26 | }, 27 | "validators": [ 28 | { 29 | "address": "86123C049FB521F4CF44386AC1F62E652184790D", 30 | "pub_key": { 31 | "type": "tendermint/PubKeyEd25519", 32 | "value": "kRKM3mkPlogAhWLARAoE9nG+i+fFbZLQDMZoS1O50So=" 33 | }, 34 | "power": "10", 35 | "name": "" 36 | } 37 | ], 38 | "app_hash": "" 39 | } -------------------------------------------------------------------------------- /config/tendermint/RP/config/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"cwE2K1pWMhADAEocQG404wmkSsue5IQZriL8Tc4nlRVcLpB/0ON1Q37abEZ2fQYJiDrTvchmIjPnokhCThMSbA=="}} -------------------------------------------------------------------------------- /config/tendermint/RP/config/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "9FB25564CC7B1671472879780B9B5156F23DE139", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "JdIMZ1BliC7qYsph0kGSECCoEu2xgqwToBOiJ434cLM=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "jgq3/kZSuLs4DoX65lIO2ud7yFlaCO8YvDtYZv6r4h0l0gxnUGWILupiymHSQZIQIKgS7bGCrBOgE6Injfhwsw==" 10 | } 11 | } -------------------------------------------------------------------------------- /config/tendermint/proxy/config/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesis_time": "2024-03-22T11:27:07.802481591Z", 3 | "chain_id": "test-chain-NDID", 4 | "initial_height": "0", 5 | "consensus_params": { 6 | "block": { 7 | "max_bytes": "22020096", 8 | "max_gas": "-1" 9 | }, 10 | "evidence": { 11 | "max_age_num_blocks": "100000", 12 | "max_age_duration": "172800000000000", 13 | "max_bytes": "1048576" 14 | }, 15 | "validator": { 16 | "pub_key_types": [ 17 | "ed25519" 18 | ] 19 | }, 20 | "version": { 21 | "app": "0" 22 | }, 23 | "abci": { 24 | "vote_extensions_enable_height": "0" 25 | } 26 | }, 27 | "validators": [ 28 | { 29 | "address": "86123C049FB521F4CF44386AC1F62E652184790D", 30 | "pub_key": { 31 | "type": "tendermint/PubKeyEd25519", 32 | "value": "kRKM3mkPlogAhWLARAoE9nG+i+fFbZLQDMZoS1O50So=" 33 | }, 34 | "power": "10", 35 | "name": "" 36 | } 37 | ], 38 | "app_hash": "" 39 | } -------------------------------------------------------------------------------- /config/tendermint/proxy/config/node_key.json: -------------------------------------------------------------------------------- 1 | {"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"A/ZfvcU950SbWXLF4CX+OcF7Qms5SdMfQ4F8/7Kp5O6TdeaY43947BaZMHoTH8r8kvuFiaem+ah0twyoyEqSPA=="}} -------------------------------------------------------------------------------- /config/tendermint/proxy/config/priv_validator_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "9E32DB1C4ACB24EB46431AE79ECC6AA79680997D", 3 | "pub_key": { 4 | "type": "tendermint/PubKeyEd25519", 5 | "value": "cF0Ne1SkHhjTytFb4ANyj66PT1a1pki0OXUJJyKjyRo=" 6 | }, 7 | "priv_key": { 8 | "type": "tendermint/PrivKeyEd25519", 9 | "value": "kZR9CkbOaHtlN28D2XkMF+aZgF9HPkRZvDEnw2cBdiJwXQ17VKQeGNPK0VvgA3KPro9PVrWmSLQ5dQknIqPJGg==" 10 | } 11 | } -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.22-alpine3.20 AS builder 2 | 3 | # Install tools and snappy lib 4 | RUN apk update && apk add --no-cache --virtual .build-deps \ 5 | g++ \ 6 | gcc \ 7 | make \ 8 | git \ 9 | openssl \ 10 | snappy-dev \ 11 | leveldb-dev \ 12 | ca-certificates 13 | 14 | WORKDIR /ndidplatform/smart-contract 15 | COPY go.mod go.sum /ndidplatform/smart-contract/ 16 | COPY COPYING /ndidplatform/smart-contract/ 17 | COPY abci /ndidplatform/smart-contract/abci 18 | COPY protos /ndidplatform/smart-contract/protos 19 | COPY .git /ndidplatform/smart-contract/.git 20 | 21 | # COPY patches /ndidplatform/smart-contract/patches 22 | 23 | # Cannot be done with Go modules? 24 | # RUN git apply /ndidplatform/smart-contract/patches/tm_goleveldb_bloom_filter.patch && \ 25 | # git apply /ndidplatform/smart-contract/patches/tm_cleveldb_cache_and_bloom_filter.patch 26 | 27 | ENV CGO_ENABLED=1 28 | ENV CGO_LDFLAGS="-lsnappy" 29 | RUN go build \ 30 | -ldflags "-X github.com/ndidplatform/smart-contract/v9/abci/version.GitCommit=`git rev-parse --short=8 HEAD`" \ 31 | -tags "cleveldb" \ 32 | -o ./did-tendermint \ 33 | ./abci 34 | 35 | 36 | FROM alpine:3.20 37 | LABEL maintainer="NDID IT Team " 38 | 39 | # Data directory for ABCI to store state. 40 | ENV ABCI_DB_DIR_PATH=/DID 41 | 42 | # The /tendermint/data dir is used by CometBFT/Tendermint to store state. 43 | ENV CMTHOME /tendermint 44 | 45 | # Set umask to 027 46 | RUN umask 027 && echo "umask 0027" >> /etc/profile 47 | 48 | COPY --from=builder /var/cache/apk /var/cache/apk 49 | 50 | # Install snappy lib used by LevelDB. 51 | # Install bash shell for convenience. 52 | RUN apk add --no-cache \ 53 | bash \ 54 | leveldb \ 55 | snappy \ 56 | tzdata && \ 57 | rm -rf /var/cache/apk 58 | 59 | COPY --from=builder /ndidplatform/smart-contract/did-tendermint /usr/bin/did-tendermint 60 | COPY docker/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh 61 | 62 | ENTRYPOINT [ "/usr/bin/docker-entrypoint.sh", "did-tendermint" ] 63 | CMD [ "node" ] 64 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BUILD_COMMIT=$(git log -1 --format=%H) BUILD_DATE=$(date) docker-compose -f $(dirname $0)/docker-compose.build.yml build --pull $@ 4 | -------------------------------------------------------------------------------- /docker/buildx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # docker buildx create --use 4 | 5 | BUILD_COMMIT=$(git log -1 --format=%H) BUILD_DATE=$(date) docker buildx bake -f $(dirname $0)/docker-compose.build.yml --pull $@ 6 | -------------------------------------------------------------------------------- /docker/docker-compose.build.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | did-tendermint: 4 | build: 5 | context: ../ 6 | dockerfile: docker/Dockerfile 7 | labels: 8 | build.commit: ${BUILD_COMMIT} 9 | build.date: ${BUILD_DATE} 10 | x-bake: 11 | platforms: 12 | - linux/amd64 13 | - linux/arm64 14 | - linux/arm/v7 15 | - linux/arm/v6 16 | pull: true 17 | image: ${REPO_NAME:-ndidplatform}/did-tendermint:${DOCKER_TAG:-latest} 18 | -------------------------------------------------------------------------------- /docker/docker-compose.test_dev.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | # genesis node 5 | tm-1: 6 | image: ndidplatform/did-tendermint:${DOCKER_TAG:-latest} 7 | environment: 8 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 9 | - DEV_ENV=${DEV_ENV:-true} 10 | entrypoint: /usr/bin/start-node.sh 11 | command: 12 | - genesis 13 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 14 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 15 | volumes: 16 | - ./start-node.sh:/usr/bin/start-node.sh:ro 17 | security_opt: 18 | - no-new-privileges 19 | user: root 20 | ports: 21 | - 45000:${TM_RPC_PORT:-45000} 22 | - 47000:${TM_P2P_PORT:-47000} 23 | networks: 24 | - ndidplatform 25 | 26 | # secondary nodes 27 | tm-2: 28 | image: ndidplatform/did-tendermint:${DOCKER_TAG:-latest} 29 | environment: 30 | - SEED_HOSTNAME=tm-1 31 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 32 | - DEV_ENV=${DEV_ENV:-true} 33 | entrypoint: /usr/bin/start-node.sh 34 | command: 35 | - secondary 36 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 37 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 38 | volumes: 39 | - ./start-node.sh:/usr/bin/start-node.sh:ro 40 | security_opt: 41 | - no-new-privileges 42 | user: root 43 | ports: 44 | - 45001:${TM_RPC_PORT:-45000} 45 | - 47001:${TM_P2P_PORT:-47000} 46 | networks: 47 | - ndidplatform 48 | depends_on: 49 | - tm-1 50 | tm-3: 51 | image: ndidplatform/did-tendermint:${DOCKER_TAG:-latest} 52 | environment: 53 | - SEED_HOSTNAME=tm-1 54 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 55 | - DEV_ENV=${DEV_ENV:-true} 56 | entrypoint: /usr/bin/start-node.sh 57 | command: 58 | - secondary 59 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 60 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 61 | volumes: 62 | - ./start-node.sh:/usr/bin/start-node.sh:ro 63 | security_opt: 64 | - no-new-privileges 65 | user: root 66 | ports: 67 | - 45002:${TM_RPC_PORT:-45000} 68 | - 47002:${TM_P2P_PORT:-47000} 69 | networks: 70 | - ndidplatform 71 | depends_on: 72 | - tm-1 73 | tm-4: 74 | image: ndidplatform/did-tendermint:${DOCKER_TAG:-latest} 75 | environment: 76 | - SEED_HOSTNAME=tm-1 77 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 78 | - DEV_ENV=${DEV_ENV:-true} 79 | entrypoint: /usr/bin/start-node.sh 80 | command: 81 | - secondary 82 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 83 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 84 | volumes: 85 | - ./start-node.sh:/usr/bin/start-node.sh:ro 86 | security_opt: 87 | - no-new-privileges 88 | user: root 89 | ports: 90 | - 45003:${TM_RPC_PORT:-45000} 91 | - 47003:${TM_P2P_PORT:-47000} 92 | networks: 93 | - ndidplatform 94 | depends_on: 95 | - tm-1 96 | 97 | networks: 98 | ndidplatform: -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | # genesis node 5 | tm-1: 6 | image: ndidplatform/did-tendermint:latest 7 | environment: 8 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 9 | entrypoint: /usr/bin/start-node.sh 10 | command: 11 | - genesis 12 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 13 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 14 | volumes: 15 | - ./start-node.sh:/usr/bin/start-node.sh:ro 16 | security_opt: 17 | - no-new-privileges 18 | ports: 19 | - 45000:${TM_RPC_PORT:-45000} 20 | - 47000:${TM_P2P_PORT:-47000} 21 | networks: 22 | - ndidplatform 23 | 24 | # secondary nodes 25 | tm-2: 26 | image: ndidplatform/did-tendermint:latest 27 | environment: 28 | - SEED_HOSTNAME=tm-1 29 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 30 | entrypoint: /usr/bin/start-node.sh 31 | command: 32 | - secondary 33 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 34 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 35 | volumes: 36 | - ./start-node.sh:/usr/bin/start-node.sh:ro 37 | security_opt: 38 | - no-new-privileges 39 | ports: 40 | - 45001:${TM_RPC_PORT:-45000} 41 | - 47001:${TM_P2P_PORT:-47000} 42 | networks: 43 | - ndidplatform 44 | depends_on: 45 | - tm-1 46 | tm-3: 47 | image: ndidplatform/did-tendermint:latest 48 | environment: 49 | - SEED_HOSTNAME=tm-1 50 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 51 | entrypoint: /usr/bin/start-node.sh 52 | command: 53 | - secondary 54 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 55 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 56 | volumes: 57 | - ./start-node.sh:/usr/bin/start-node.sh:ro 58 | security_opt: 59 | - no-new-privileges 60 | ports: 61 | - 45002:${TM_RPC_PORT:-45000} 62 | - 47002:${TM_P2P_PORT:-47000} 63 | networks: 64 | - ndidplatform 65 | depends_on: 66 | - tm-1 67 | tm-4: 68 | image: ndidplatform/did-tendermint:latest 69 | environment: 70 | - SEED_HOSTNAME=tm-1 71 | - TM_RPC_PORT=${TM_RPC_PORT:-45000} 72 | entrypoint: /usr/bin/start-node.sh 73 | command: 74 | - secondary 75 | - --p2p.laddr=tcp://0.0.0.0:${TM_P2P_PORT:-47000} 76 | - --rpc.laddr=tcp://0.0.0.0:${TM_RPC_PORT:-45000} 77 | volumes: 78 | - ./start-node.sh:/usr/bin/start-node.sh:ro 79 | security_opt: 80 | - no-new-privileges 81 | ports: 82 | - 45003:${TM_RPC_PORT:-45000} 83 | - 47003:${TM_P2P_PORT:-47000} 84 | networks: 85 | - ndidplatform 86 | depends_on: 87 | - tm-1 88 | 89 | networks: 90 | ndidplatform: -------------------------------------------------------------------------------- /docker/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Ensure that the first argument is did-tendermint 5 | if [ "$1" != "did-tendermint" ]; then 6 | set -- "did-tendermint" "$@" 7 | fi 8 | 9 | # Check existence and owner of ABCI_DB_DIR_PATH and TMHOME 10 | if [ "$1" = "did-tendermint" -a "$(id -u)" != "0" ]; then 11 | if [ ! -d ${ABCI_DB_DIR_PATH} ]; then 12 | echo "${ABCI_DB_DIR_PATH} is not directory or missing" 13 | exit 1 14 | fi 15 | 16 | if [ ! -d ${TMHOME} ]; then 17 | echo "${TMHOME} is not directory or missing" 18 | exit 1 19 | fi 20 | 21 | user="$(id -u)" 22 | group="$(id -g)" 23 | 24 | if [ ! -z "$(find ${ABCI_DB_DIR_PATH} ! -user $user ! -group $group)" ]; then 25 | echo "${ABCI_DB_DIR_PATH} or the files inside have incorrect owner" 26 | exit 1 27 | fi 28 | 29 | if [ ! -z "$(find ${TMHOME} ! -user $user ! -group $group)" ]; then 30 | echo "${TMHOME} the files inside have incorrect owner" 31 | exit 1 32 | fi 33 | fi 34 | 35 | exec "$@" 36 | -------------------------------------------------------------------------------- /docker/start-node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install jq and curl as they are required by this script 4 | if ! which jq || ! which curl; then 5 | mkdir -p /var/cache/apk 6 | apk update 7 | apk add --no-cache curl jq 8 | rm -rf /var/cache/apk 9 | fi 10 | 11 | CMTHOME=${CMTHOME:-/tendermint} 12 | TM_RPC_PORT=${TM_RPC_PORT:-45000} 13 | TM_P2P_PORT=${TM_P2P_PORT:-47000} 14 | ABCI_PORT=${ABCI_PORT:-46000} 15 | DEV_ENV=${DEV_ENV:-false} 16 | 17 | if [ "${DEV_ENV}" == "true" ]; then 18 | ADDR_BOOK_STRICT=false 19 | ALLOW_DUPLICATE_IP=true 20 | else 21 | ADDR_BOOK_STRICT=true 22 | ALLOW_DUPLICATE_IP=false 23 | fi 24 | 25 | if [ -z "${SEED_RPC_PORT}" ]; then SEED_RPC_PORT=$TM_RPC_PORT; fi 26 | 27 | usage() { 28 | echo "Usage: $(basename ${0}) " 29 | echo "where mode can be :" 30 | echo "genesis = run this node as genesis node" 31 | echo "secondary = run this node as secondary node" 32 | echo "reset = call unsafe-reset-all" 33 | } 34 | 35 | tendermint_init() { 36 | echo "Initializing tendermint..." 37 | did-tendermint --home=${CMTHOME} init validator 38 | } 39 | 40 | tendermint_reset() { 41 | echo "Resetting tendermint..." 42 | did-tendermint --home=${CMTHOME} unsafe-reset-all 43 | } 44 | 45 | tendermint_get_genesis_from_seed() { 46 | curl -s http://${SEED_HOSTNAME}:${SEED_RPC_PORT}/genesis | jq -r .result.genesis > ${CMTHOME}/config/genesis.json 47 | } 48 | 49 | tendermint_get_id_from_seed() { 50 | if [ ! -f ${CMTHOME}/config/seed.host ]; then 51 | curl -s http://${SEED_HOSTNAME}:${SEED_RPC_PORT}/status | jq -r .result.node_info.id | tee ${CMTHOME}/config/seed.host 52 | else 53 | cat ${CMTHOME}/config/seed.host 54 | fi 55 | } 56 | 57 | tendermint_wait_for_sync_complete() { 58 | echo "Waiting for tendermint at ${1}:${2} to be ready..." 59 | while true; do 60 | [ ! "$(curl -s http://${1}:${2}/status | jq -r .result.sync_info.catching_up)" = "false" ] || break 61 | sleep 1 62 | done 63 | } 64 | 65 | tendermint_set_log_level() { 66 | sed -i -E "s/^log_level = .*$/log_level = ${1}/" ${CMTHOME}/config/config.toml 67 | } 68 | 69 | tendermint_set_db_backend_cleveldb() { 70 | sed -i -E "s/^db_backend = .*$/db_backend = \\\"cleveldb\\\"/" ${CMTHOME}/config/config.toml 71 | } 72 | 73 | tendermint_set_allow_duplicate_ip() { 74 | sed -i -E "s/^allow_duplicate_ip = (true|false)/allow_duplicate_ip = ${1}/" ${CMTHOME}/config/config.toml 75 | } 76 | 77 | tendermint_set_addr_book_strict() { 78 | sed -i -E "s/^addr_book_strict = (true|false)/addr_book_strict = ${1}/" ${CMTHOME}/config/config.toml 79 | } 80 | 81 | tendermint_set_create_empty_block() { 82 | sed -i -E "s/^create_empty_blocks = (true|false)/create_empty_blocks = ${1}/" ${CMTHOME}/config/config.toml 83 | } 84 | 85 | tendermint_set_create_empty_block_interval() { 86 | sed -i -E "s/^create_empty_blocks_interval = .*$/create_empty_blocks_interval = ${1}/" ${CMTHOME}/config/config.toml 87 | } 88 | 89 | tendermint_set_mempool_recheck() { 90 | sed -i -E "s/^recheck = (true|false)/recheck = ${1}/" ${CMTHOME}/config/config.toml 91 | } 92 | 93 | tendermint_set_mempool_size() { 94 | sed -i -E "s/^size = .*$/size = ${1}/" ${CMTHOME}/config/config.toml 95 | } 96 | 97 | tendermint_set_mempool_cache_size() { 98 | sed -i -E "s/^cache_size = .*$/cache_size = ${1}/" ${CMTHOME}/config/config.toml 99 | } 100 | 101 | tendermint_set_config_for_prod() { 102 | sed -i -E "s/^flush_throttle_timeout = .*$/flush_throttle_timeout = \\\"10ms\\\"/" ${CMTHOME}/config/config.toml 103 | sed -i -E "s/^max_packet_msg_payload_size = .*$/max_packet_msg_payload_size = 10240/" ${CMTHOME}/config/config.toml # 10KB 104 | sed -i -E "s/^send_rate = .*$/send_rate = 20971520/" ${CMTHOME}/config/config.toml # 20MB/s 105 | sed -i -E "s/^recv_rate = .*$/recv_rate = 20971520/" ${CMTHOME}/config/config.toml # 20MB/s 106 | } 107 | 108 | tendermint_set_timeout_commit() { 109 | sed -i -E "s/^timeout_commit = .*$/timeout_commit = ${1}/" ${CMTHOME}/config/config.toml 110 | } 111 | 112 | tendermint_set_skip_timeout_commit() { 113 | sed -i -E "s/^skip_timeout_commit = (true|false)/skip_timeout_commit = ${1}/" ${CMTHOME}/config/config.toml 114 | } 115 | 116 | tendermint_set_seeds() { 117 | sed -i -E "s/^seeds = .*$/seeds = \\\"${1}\\\"/" ${CMTHOME}/config/config.toml 118 | } 119 | 120 | TYPE=${1} 121 | shift 122 | 123 | if [ ! -f ${CMTHOME}/config/genesis.json ]; then 124 | case ${TYPE} in 125 | genesis) 126 | tendermint_init 127 | # tendermint_set_log_level '"debug"' 128 | # tendermint_set_db_backend_cleveldb 129 | tendermint_set_allow_duplicate_ip ${ALLOW_DUPLICATE_IP} 130 | tendermint_set_addr_book_strict ${ADDR_BOOK_STRICT} 131 | tendermint_set_create_empty_block false 132 | tendermint_set_create_empty_block_interval '"0s"' 133 | tendermint_set_mempool_recheck false 134 | tendermint_set_timeout_commit '"100ms"' 135 | tendermint_set_skip_timeout_commit true 136 | tendermint_set_mempool_size 50000 137 | # tendermint_set_mempool_cache_size 0 138 | # if [ "${DEV_ENV}" != "true" ]; then tendermint_set_config_for_prod; fi 139 | tendermint_set_config_for_prod 140 | did-tendermint node --moniker=${HOSTNAME} $@ 141 | ;; 142 | secondary) 143 | if [ -z ${SEED_HOSTNAME} ]; then echo "Error: env SEED_HOSTNAME is not set"; exit 1; fi 144 | 145 | tendermint_init 146 | # tendermint_set_log_level '"debug"' 147 | # tendermint_set_db_backend_cleveldb 148 | tendermint_set_allow_duplicate_ip ${ALLOW_DUPLICATE_IP} 149 | tendermint_set_addr_book_strict ${ADDR_BOOK_STRICT} 150 | tendermint_set_create_empty_block false 151 | tendermint_set_create_empty_block_interval '"0s"' 152 | tendermint_set_mempool_recheck false 153 | tendermint_set_timeout_commit '"100ms"' 154 | tendermint_set_skip_timeout_commit true 155 | tendermint_set_mempool_size 50000 156 | # tendermint_set_mempool_cache_size 0 157 | # if [ "${DEV_ENV}" != "true" ]; then tendermint_set_config_for_prod; fi 158 | tendermint_set_config_for_prod 159 | until tendermint_wait_for_sync_complete ${SEED_HOSTNAME} ${SEED_RPC_PORT}; do sleep 1; done 160 | until SEED_ID=$(tendermint_get_id_from_seed) && [ ! "${SEED_ID}" = "" ]; do sleep 1; done 161 | until tendermint_get_genesis_from_seed; do sleep 1; done 162 | tendermint_set_seeds ${SEED_ID}@${SEED_HOSTNAME}:${TM_P2P_PORT} 163 | did-tendermint node --moniker=${HOSTNAME} $@ 164 | ;; 165 | reset) 166 | tendermint_reset 167 | exit 0 168 | ;; 169 | *) 170 | usage 171 | exit 1 172 | ;; 173 | esac 174 | else 175 | case ${TYPE} in 176 | genesis) 177 | did-tendermint node --moniker=${HOSTNAME} $@ 178 | ;; 179 | secondary) 180 | until SEED_ID=$(tendermint_get_id_from_seed); do sleep 1; done 181 | tendermint_set_seeds ${SEED_ID}@${SEED_HOSTNAME}:${TM_P2P_PORT} 182 | did-tendermint node --moniker=${HOSTNAME} $@ 183 | ;; 184 | reset) 185 | tendermint_reset 186 | exit 0 187 | ;; 188 | *) 189 | usage 190 | exit 1 191 | ;; 192 | esac 193 | fi 194 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ndidplatform/smart-contract/v9 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/cometbft/cometbft v0.38.6 7 | github.com/cometbft/cometbft-db v0.12.0 8 | github.com/prometheus/client_golang v1.19.0 9 | github.com/satori/go.uuid v1.2.0 10 | github.com/sirupsen/logrus v1.9.3 11 | github.com/spf13/cobra v1.8.0 12 | github.com/stretchr/testify v1.9.0 13 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 14 | google.golang.org/protobuf v1.33.0 15 | ) 16 | 17 | require ( 18 | github.com/DataDog/zstd v1.4.5 // indirect 19 | github.com/beorn7/perks v1.0.1 // indirect 20 | github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect 21 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 22 | github.com/cockroachdb/errors v1.11.1 // indirect 23 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect 24 | github.com/cockroachdb/pebble v1.1.0 // indirect 25 | github.com/cockroachdb/redact v1.1.5 // indirect 26 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect 27 | github.com/cosmos/gogoproto v1.4.11 // indirect 28 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 29 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 30 | github.com/dgraph-io/badger/v4 v4.2.0 // indirect 31 | github.com/dgraph-io/ristretto v0.1.1 // indirect 32 | github.com/dustin/go-humanize v1.0.1 // indirect 33 | github.com/fsnotify/fsnotify v1.7.0 // indirect 34 | github.com/getsentry/sentry-go v0.18.0 // indirect 35 | github.com/go-kit/kit v0.12.0 // indirect 36 | github.com/go-kit/log v0.2.1 // indirect 37 | github.com/go-logfmt/logfmt v0.6.0 // indirect 38 | github.com/gogo/protobuf v1.3.2 // indirect 39 | github.com/golang/glog v1.1.2 // indirect 40 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 41 | github.com/golang/protobuf v1.5.3 // indirect 42 | github.com/golang/snappy v0.0.4 // indirect 43 | github.com/google/btree v1.1.2 // indirect 44 | github.com/google/flatbuffers v1.12.1 // indirect 45 | github.com/google/go-cmp v0.6.0 // indirect 46 | github.com/google/orderedcode v0.0.1 // indirect 47 | github.com/gorilla/websocket v1.5.0 // indirect 48 | github.com/hashicorp/hcl v1.0.0 // indirect 49 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 50 | github.com/jmhodges/levigo v1.0.0 // indirect 51 | github.com/klauspost/compress v1.17.0 // indirect 52 | github.com/kr/pretty v0.3.1 // indirect 53 | github.com/kr/text v0.2.0 // indirect 54 | github.com/lib/pq v1.10.7 // indirect 55 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect 56 | github.com/linxGnu/grocksdb v1.8.14 // indirect 57 | github.com/magiconair/properties v1.8.7 // indirect 58 | github.com/minio/highwayhash v1.0.2 // indirect 59 | github.com/mitchellh/mapstructure v1.5.0 // indirect 60 | github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae // indirect 61 | github.com/pelletier/go-toml/v2 v2.1.0 // indirect 62 | github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect 63 | github.com/pkg/errors v0.9.1 // indirect 64 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 65 | github.com/prometheus/client_model v0.5.0 // indirect 66 | github.com/prometheus/common v0.48.0 // indirect 67 | github.com/prometheus/procfs v0.12.0 // indirect 68 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect 69 | github.com/rogpeppe/go-internal v1.10.0 // indirect 70 | github.com/rs/cors v1.8.3 // indirect 71 | github.com/sagikazarmark/locafero v0.4.0 // indirect 72 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect 73 | github.com/sasha-s/go-deadlock v0.3.1 // indirect 74 | github.com/sourcegraph/conc v0.3.0 // indirect 75 | github.com/spf13/afero v1.11.0 // indirect 76 | github.com/spf13/cast v1.6.0 // indirect 77 | github.com/spf13/pflag v1.0.5 // indirect 78 | github.com/spf13/viper v1.18.1 // indirect 79 | github.com/subosito/gotenv v1.6.0 // indirect 80 | go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect 81 | go.opencensus.io v0.24.0 // indirect 82 | go.uber.org/multierr v1.10.0 // indirect 83 | golang.org/x/crypto v0.18.0 // indirect 84 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect 85 | golang.org/x/net v0.20.0 // indirect 86 | golang.org/x/sync v0.6.0 // indirect 87 | golang.org/x/sys v0.18.0 // indirect 88 | golang.org/x/text v0.14.0 // indirect 89 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect 90 | google.golang.org/grpc v1.60.0 // indirect 91 | gopkg.in/ini.v1 v1.67.0 // indirect 92 | gopkg.in/yaml.v3 v3.0.1 // indirect 93 | ) 94 | -------------------------------------------------------------------------------- /patches/tm_cleveldb_cache_and_bloom_filter.patch: -------------------------------------------------------------------------------- 1 | diff --git a/vendor/github.com/tendermint/tendermint/libs/db/c_level_db.go b/vendor/github.com/tendermint/tendermint/libs/db/c_level_db.go 2 | index decb1af5..31fc656b 100644 3 | --- a/vendor/github.com/tendermint/tendermint/libs/db/c_level_db.go 4 | +++ b/vendor/github.com/tendermint/tendermint/libs/db/c_level_db.go 5 | @@ -21,17 +21,23 @@ func init() { 6 | var _ DB = (*CLevelDB)(nil) 7 | 8 | type CLevelDB struct { 9 | - db *levigo.DB 10 | - ro *levigo.ReadOptions 11 | - wo *levigo.WriteOptions 12 | - woSync *levigo.WriteOptions 13 | + db *levigo.DB 14 | + ro *levigo.ReadOptions 15 | + wo *levigo.WriteOptions 16 | + woSync *levigo.WriteOptions 17 | + cache *levigo.Cache 18 | + filterPolicy *levigo.FilterPolicy 19 | } 20 | 21 | func NewCLevelDB(name string, dir string) (*CLevelDB, error) { 22 | dbPath := filepath.Join(dir, name+".db") 23 | 24 | + cache := levigo.NewLRUCache(500 * 1024 * 1024) // 500 MB 25 | + filter := levigo.NewBloomFilter(10) 26 | + 27 | opts := levigo.NewOptions() 28 | - opts.SetCache(levigo.NewLRUCache(1 << 30)) 29 | + opts.SetCache(cache) 30 | + opts.SetFilterPolicy(filter) 31 | opts.SetCreateIfMissing(true) 32 | db, err := levigo.Open(dbPath, opts) 33 | if err != nil { 34 | @@ -42,10 +48,12 @@ func NewCLevelDB(name string, dir string) (*CLevelDB, error) { 35 | woSync := levigo.NewWriteOptions() 36 | woSync.SetSync(true) 37 | database := &CLevelDB{ 38 | - db: db, 39 | - ro: ro, 40 | - wo: wo, 41 | - woSync: woSync, 42 | + db: db, 43 | + ro: ro, 44 | + wo: wo, 45 | + woSync: woSync, 46 | + cache: cache, 47 | + filterPolicy: filter, 48 | } 49 | return database, nil 50 | } 51 | @@ -113,6 +121,8 @@ func (db *CLevelDB) Close() { 52 | db.ro.Close() 53 | db.wo.Close() 54 | db.woSync.Close() 55 | + db.cache.Close() 56 | + db.filterPolicy.Close() 57 | } 58 | 59 | // Implements DB. 60 | -------------------------------------------------------------------------------- /patches/tm_goleveldb_bloom_filter.patch: -------------------------------------------------------------------------------- 1 | diff --git a/vendor/github.com/tendermint/tendermint/libs/db/go_level_db.go b/vendor/github.com/tendermint/tendermint/libs/db/go_level_db.go 2 | index 79ee5ccb..8d81628c 100644 3 | --- a/vendor/github.com/tendermint/tendermint/libs/db/go_level_db.go 4 | +++ b/vendor/github.com/tendermint/tendermint/libs/db/go_level_db.go 5 | @@ -7,6 +7,7 @@ import ( 6 | 7 | "github.com/syndtr/goleveldb/leveldb" 8 | "github.com/syndtr/goleveldb/leveldb/errors" 9 | + "github.com/syndtr/goleveldb/leveldb/filter" 10 | "github.com/syndtr/goleveldb/leveldb/iterator" 11 | "github.com/syndtr/goleveldb/leveldb/opt" 12 | ) 13 | @@ -31,6 +32,16 @@ func NewGoLevelDB(name string, dir string) (*GoLevelDB, error) { 14 | 15 | func NewGoLevelDBWithOpts(name string, dir string, o *opt.Options) (*GoLevelDB, error) { 16 | dbPath := filepath.Join(dir, name+".db") 17 | + 18 | + bloomFilter := filter.NewBloomFilter(10) 19 | + if o == nil { 20 | + o = &opt.Options{ 21 | + Filter: bloomFilter, 22 | + } 23 | + } else { 24 | + o.Filter = bloomFilter 25 | + } 26 | + 27 | db, err := leveldb.OpenFile(dbPath, o) 28 | if err != nil { 29 | return nil, err 30 | -------------------------------------------------------------------------------- /protos/data/data.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "./;ndid_abci_state_v9"; 4 | 5 | package ndid_abci_state_v9; 6 | 7 | import "google/protobuf/wrappers.proto"; 8 | 9 | message KeyVersions { 10 | repeated int64 versions = 1; 11 | } 12 | 13 | message NodeDetail { 14 | NodeKey signing_public_key = 1; 15 | NodeKey signing_master_public_key = 2; 16 | NodeKey encryption_public_key = 3; 17 | string node_name = 4; 18 | string role = 5; 19 | double max_ial = 6; 20 | double max_aal = 7; 21 | repeated MQ mq = 8; 22 | bool active = 9; 23 | bool is_idp_agent = 10; 24 | string proxy_node_id = 11; 25 | string proxy_config = 12; 26 | bool use_whitelist = 13; 27 | repeated string whitelist = 14; 28 | repeated string supported_request_message_data_url_type_list = 15; 29 | repeated string supported_feature_list = 16; 30 | } 31 | 32 | message NodeKey { 33 | string public_key = 1; 34 | string algorithm = 2; 35 | int64 version = 3; 36 | int64 creation_block_height = 4; 37 | string creation_chain_id = 5; 38 | bool active = 6; 39 | } 40 | 41 | message MQ { 42 | string ip = 1; 43 | int64 port = 2; 44 | } 45 | 46 | message IdPList { 47 | repeated string node_id = 1; 48 | } 49 | 50 | message NamespaceList { 51 | repeated Namespace namespaces = 1; 52 | } 53 | 54 | message Namespace { 55 | string namespace = 1; 56 | string description = 2; 57 | bool active = 3; 58 | int32 allowed_identifier_count_in_reference_group = 4; 59 | int32 allowed_active_identifier_count_in_reference_group = 5; 60 | } 61 | 62 | message ServiceDetailList { 63 | repeated ServiceDetail services = 1; 64 | } 65 | 66 | message ServiceDetail { 67 | string service_id = 1; 68 | string service_name = 2; 69 | string data_schema = 3; 70 | string data_schema_version = 4; 71 | bool active = 5; 72 | } 73 | 74 | message ApproveService { 75 | bool active = 1; 76 | } 77 | 78 | message TimeOutBlockRegisterIdentity { 79 | int64 time_out_block = 1; 80 | } 81 | 82 | message Proxy { 83 | string proxy_node_id = 1; 84 | string config = 2; 85 | } 86 | 87 | message BehindNodeList { 88 | repeated string nodes = 1; 89 | } 90 | 91 | message Request { 92 | string request_id = 1; 93 | int64 min_idp = 2; 94 | double min_aal = 3; 95 | double min_ial = 4; 96 | int64 request_timeout = 5; 97 | repeated string idp_id_list = 6; 98 | repeated DataRequest data_request_list = 7; 99 | string request_message_hash = 8; 100 | repeated Response response_list = 9; 101 | bool closed = 10; 102 | bool timed_out = 11; 103 | string purpose = 12; 104 | string owner = 13; 105 | int32 mode = 14; 106 | int64 use_count = 15; 107 | int64 creation_block_height = 16; 108 | string chain_id = 17; 109 | string request_type = 18; 110 | } 111 | 112 | message Message { 113 | string message_id = 1; 114 | string message = 2; 115 | string purpose = 3; 116 | string owner = 4; 117 | int64 creation_block_height = 5; 118 | string chain_id = 6; 119 | } 120 | 121 | message ASResponse { 122 | string as_id = 1; 123 | bool signed = 2; 124 | bool received_data = 3; 125 | int32 error_code = 4; 126 | } 127 | 128 | message DataRequest { 129 | string service_id = 1; 130 | repeated string as_id_list = 2; 131 | int64 min_as = 3; 132 | string request_params_hash = 4; 133 | repeated ASResponse response_list = 6; 134 | } 135 | 136 | message Response { 137 | double ial = 1; 138 | double aal = 2; 139 | string status = 3; 140 | string signature = 4; 141 | string idp_id = 5; 142 | string valid_ial = 6; 143 | string valid_signature = 7; 144 | int32 error_code = 8; 145 | } 146 | 147 | message ReportList { 148 | repeated Report reports = 1; 149 | } 150 | 151 | message Report { 152 | string method = 1; 153 | double price = 2; 154 | string data = 3; 155 | } 156 | 157 | message Accessor { 158 | string accessor_id = 1; 159 | string accessor_type = 2; 160 | string accessor_public_key = 3; 161 | bool active = 4; 162 | string owner = 5; 163 | int64 creation_block_height = 6; 164 | string creation_chain_id = 7; 165 | } 166 | 167 | message MsqDesList { 168 | repeated Node nodes = 1; 169 | } 170 | 171 | message Node { 172 | double ial = 1; 173 | string node_id = 2; 174 | bool active = 3; 175 | bool first = 4; 176 | int64 timeout_block = 5; 177 | } 178 | 179 | message ServiceList { 180 | repeated Service services = 1; 181 | } 182 | 183 | message Service { 184 | string service_id = 1; 185 | double min_ial = 2; 186 | double min_aal = 3; 187 | bool active = 4; 188 | bool suspended = 5; 189 | repeated string supported_namespace_list = 6; 190 | } 191 | 192 | message ServiceDesList { 193 | repeated ASNode node = 1; 194 | } 195 | 196 | message ASNode { 197 | string node_id = 1; 198 | double min_ial = 2; 199 | double min_aal = 3; 200 | string service_id = 4; 201 | repeated string supported_namespace_list = 5; 202 | bool active = 6; 203 | } 204 | 205 | message RPList { 206 | repeated string node_id = 1; 207 | } 208 | 209 | message ASList { 210 | repeated string node_id = 1; 211 | } 212 | 213 | message AllList { 214 | repeated string node_id = 1; 215 | } 216 | 217 | message AccessorInGroup { 218 | repeated string accessors = 1; 219 | } 220 | 221 | message Token { 222 | double amount = 1; 223 | } 224 | 225 | message TokenPrice { 226 | double price = 1; 227 | } 228 | 229 | message ReferenceGroup { 230 | repeated IdentityInRefGroup identities = 1; 231 | repeated IdPInRefGroup idps = 2; 232 | } 233 | 234 | message IdPInRefGroup { 235 | string node_id = 1; 236 | repeated int32 mode = 2; 237 | repeated Accessor accessors = 3; 238 | double ial = 4; 239 | bool active = 5; 240 | google.protobuf.BoolValue lial = 6; 241 | google.protobuf.BoolValue laal = 7; 242 | } 243 | 244 | message IdentityInRefGroup { 245 | string namespace = 1; 246 | string identifier_hash = 2; 247 | bool active = 3; 248 | } 249 | 250 | message SupportedIALList { 251 | repeated double ial_list = 1; 252 | } 253 | 254 | message SupportedAALList { 255 | repeated double aal_list = 1; 256 | } 257 | 258 | message AllowedModeList { 259 | repeated int32 mode = 1; 260 | } 261 | 262 | message AllowedMinIalForRegisterIdentityAtFirstIdp { 263 | double min_ial = 1; 264 | } 265 | 266 | message ErrorCode { 267 | int32 error_code = 1; 268 | string description = 2; 269 | } 270 | 271 | message ErrorCodeList { 272 | repeated ErrorCode error_code = 2; 273 | } 274 | 275 | message ServicePriceCeilingList { 276 | repeated ServicePriceCeilingByCurency price_ceiling_by_currency_list = 1; 277 | } 278 | 279 | message ServicePriceCeilingByCurency { 280 | string currency = 1; 281 | double price = 2; 282 | } 283 | 284 | message ServicePriceMinEffectiveDatetimeDelay { 285 | uint32 duration_second = 1; 286 | } 287 | 288 | message ServicePriceList { 289 | repeated ServicePrice service_price_list = 1; 290 | } 291 | 292 | message ServicePrice { 293 | repeated ServicePriceByCurrency price_by_currency_list = 1; 294 | int64 effective_datetime = 2; 295 | string more_info_url = 3; 296 | string detail = 4; 297 | int64 creation_block_height = 5; 298 | string creation_chain_id = 6; 299 | } 300 | 301 | message ServicePriceByCurrency { 302 | string currency = 1; 303 | double min_price = 2; 304 | double max_price = 3; 305 | } 306 | 307 | message RequestType { 308 | // string name = 1; 309 | } 310 | 311 | message SuppressedIdentityModificationNotificationNode { 312 | // string node_id = 1; 313 | } 314 | 315 | message NodeSupportedFeature { 316 | // string name = 1; 317 | } 318 | -------------------------------------------------------------------------------- /protos/gen_proto_go.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | protoc -I=./data --go_out=./data ./data/data.proto 4 | protoc -I=./tendermint --go_out=./tendermint ./tendermint/tendermint.proto 5 | protoc -I=./param --go_out=./param ./param/param.proto -------------------------------------------------------------------------------- /protos/param/param.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.31.0 4 | // protoc v4.24.0 5 | // source: param.proto 6 | 7 | package ndid_abci_param_v9 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type KeyValue struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` 29 | Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` 30 | } 31 | 32 | func (x *KeyValue) Reset() { 33 | *x = KeyValue{} 34 | if protoimpl.UnsafeEnabled { 35 | mi := &file_param_proto_msgTypes[0] 36 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 37 | ms.StoreMessageInfo(mi) 38 | } 39 | } 40 | 41 | func (x *KeyValue) String() string { 42 | return protoimpl.X.MessageStringOf(x) 43 | } 44 | 45 | func (*KeyValue) ProtoMessage() {} 46 | 47 | func (x *KeyValue) ProtoReflect() protoreflect.Message { 48 | mi := &file_param_proto_msgTypes[0] 49 | if protoimpl.UnsafeEnabled && x != nil { 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | if ms.LoadMessageInfo() == nil { 52 | ms.StoreMessageInfo(mi) 53 | } 54 | return ms 55 | } 56 | return mi.MessageOf(x) 57 | } 58 | 59 | // Deprecated: Use KeyValue.ProtoReflect.Descriptor instead. 60 | func (*KeyValue) Descriptor() ([]byte, []int) { 61 | return file_param_proto_rawDescGZIP(), []int{0} 62 | } 63 | 64 | func (x *KeyValue) GetKey() []byte { 65 | if x != nil { 66 | return x.Key 67 | } 68 | return nil 69 | } 70 | 71 | func (x *KeyValue) GetValue() []byte { 72 | if x != nil { 73 | return x.Value 74 | } 75 | return nil 76 | } 77 | 78 | type SetInitDataParam struct { 79 | state protoimpl.MessageState 80 | sizeCache protoimpl.SizeCache 81 | unknownFields protoimpl.UnknownFields 82 | 83 | KvList []*KeyValue `protobuf:"bytes,1,rep,name=kv_list,json=kvList,proto3" json:"kv_list,omitempty"` 84 | } 85 | 86 | func (x *SetInitDataParam) Reset() { 87 | *x = SetInitDataParam{} 88 | if protoimpl.UnsafeEnabled { 89 | mi := &file_param_proto_msgTypes[1] 90 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 91 | ms.StoreMessageInfo(mi) 92 | } 93 | } 94 | 95 | func (x *SetInitDataParam) String() string { 96 | return protoimpl.X.MessageStringOf(x) 97 | } 98 | 99 | func (*SetInitDataParam) ProtoMessage() {} 100 | 101 | func (x *SetInitDataParam) ProtoReflect() protoreflect.Message { 102 | mi := &file_param_proto_msgTypes[1] 103 | if protoimpl.UnsafeEnabled && x != nil { 104 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 105 | if ms.LoadMessageInfo() == nil { 106 | ms.StoreMessageInfo(mi) 107 | } 108 | return ms 109 | } 110 | return mi.MessageOf(x) 111 | } 112 | 113 | // Deprecated: Use SetInitDataParam.ProtoReflect.Descriptor instead. 114 | func (*SetInitDataParam) Descriptor() ([]byte, []int) { 115 | return file_param_proto_rawDescGZIP(), []int{1} 116 | } 117 | 118 | func (x *SetInitDataParam) GetKvList() []*KeyValue { 119 | if x != nil { 120 | return x.KvList 121 | } 122 | return nil 123 | } 124 | 125 | var File_param_proto protoreflect.FileDescriptor 126 | 127 | var file_param_proto_rawDesc = []byte{ 128 | 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x6e, 129 | 0x64, 0x69, 0x64, 0x5f, 0x61, 0x62, 0x63, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x76, 130 | 0x39, 0x22, 0x32, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 131 | 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 132 | 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 133 | 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x49, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x69, 0x74, 134 | 0x44, 0x61, 0x74, 0x61, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x35, 0x0a, 0x07, 0x6b, 0x76, 0x5f, 135 | 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6e, 0x64, 0x69, 136 | 0x64, 0x5f, 0x61, 0x62, 0x63, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x76, 0x39, 0x2e, 137 | 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6b, 0x76, 0x4c, 0x69, 0x73, 0x74, 138 | 0x42, 0x17, 0x5a, 0x15, 0x2e, 0x2f, 0x3b, 0x6e, 0x64, 0x69, 0x64, 0x5f, 0x61, 0x62, 0x63, 0x69, 139 | 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x76, 0x39, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 140 | 0x33, 141 | } 142 | 143 | var ( 144 | file_param_proto_rawDescOnce sync.Once 145 | file_param_proto_rawDescData = file_param_proto_rawDesc 146 | ) 147 | 148 | func file_param_proto_rawDescGZIP() []byte { 149 | file_param_proto_rawDescOnce.Do(func() { 150 | file_param_proto_rawDescData = protoimpl.X.CompressGZIP(file_param_proto_rawDescData) 151 | }) 152 | return file_param_proto_rawDescData 153 | } 154 | 155 | var file_param_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 156 | var file_param_proto_goTypes = []interface{}{ 157 | (*KeyValue)(nil), // 0: ndid_abci_param_v9.KeyValue 158 | (*SetInitDataParam)(nil), // 1: ndid_abci_param_v9.SetInitDataParam 159 | } 160 | var file_param_proto_depIdxs = []int32{ 161 | 0, // 0: ndid_abci_param_v9.SetInitDataParam.kv_list:type_name -> ndid_abci_param_v9.KeyValue 162 | 1, // [1:1] is the sub-list for method output_type 163 | 1, // [1:1] is the sub-list for method input_type 164 | 1, // [1:1] is the sub-list for extension type_name 165 | 1, // [1:1] is the sub-list for extension extendee 166 | 0, // [0:1] is the sub-list for field type_name 167 | } 168 | 169 | func init() { file_param_proto_init() } 170 | func file_param_proto_init() { 171 | if File_param_proto != nil { 172 | return 173 | } 174 | if !protoimpl.UnsafeEnabled { 175 | file_param_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 176 | switch v := v.(*KeyValue); i { 177 | case 0: 178 | return &v.state 179 | case 1: 180 | return &v.sizeCache 181 | case 2: 182 | return &v.unknownFields 183 | default: 184 | return nil 185 | } 186 | } 187 | file_param_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 188 | switch v := v.(*SetInitDataParam); i { 189 | case 0: 190 | return &v.state 191 | case 1: 192 | return &v.sizeCache 193 | case 2: 194 | return &v.unknownFields 195 | default: 196 | return nil 197 | } 198 | } 199 | } 200 | type x struct{} 201 | out := protoimpl.TypeBuilder{ 202 | File: protoimpl.DescBuilder{ 203 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 204 | RawDescriptor: file_param_proto_rawDesc, 205 | NumEnums: 0, 206 | NumMessages: 2, 207 | NumExtensions: 0, 208 | NumServices: 0, 209 | }, 210 | GoTypes: file_param_proto_goTypes, 211 | DependencyIndexes: file_param_proto_depIdxs, 212 | MessageInfos: file_param_proto_msgTypes, 213 | }.Build() 214 | File_param_proto = out.File 215 | file_param_proto_rawDesc = nil 216 | file_param_proto_goTypes = nil 217 | file_param_proto_depIdxs = nil 218 | } 219 | -------------------------------------------------------------------------------- /protos/param/param.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "./;ndid_abci_param_v9"; 4 | 5 | package ndid_abci_param_v9; 6 | 7 | message KeyValue { 8 | bytes key = 1; 9 | bytes value = 2; 10 | } 11 | 12 | message SetInitDataParam { 13 | repeated KeyValue kv_list = 1; 14 | } 15 | -------------------------------------------------------------------------------- /protos/tendermint/tendermint.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.31.0 4 | // protoc v4.24.0 5 | // source: tendermint.proto 6 | 7 | package ndid_tendermint_abci_interface_v9 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Tx struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` 29 | Params []byte `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"` 30 | Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"` 31 | Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` 32 | NodeId string `protobuf:"bytes,5,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` 33 | } 34 | 35 | func (x *Tx) Reset() { 36 | *x = Tx{} 37 | if protoimpl.UnsafeEnabled { 38 | mi := &file_tendermint_proto_msgTypes[0] 39 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 40 | ms.StoreMessageInfo(mi) 41 | } 42 | } 43 | 44 | func (x *Tx) String() string { 45 | return protoimpl.X.MessageStringOf(x) 46 | } 47 | 48 | func (*Tx) ProtoMessage() {} 49 | 50 | func (x *Tx) ProtoReflect() protoreflect.Message { 51 | mi := &file_tendermint_proto_msgTypes[0] 52 | if protoimpl.UnsafeEnabled && x != nil { 53 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 54 | if ms.LoadMessageInfo() == nil { 55 | ms.StoreMessageInfo(mi) 56 | } 57 | return ms 58 | } 59 | return mi.MessageOf(x) 60 | } 61 | 62 | // Deprecated: Use Tx.ProtoReflect.Descriptor instead. 63 | func (*Tx) Descriptor() ([]byte, []int) { 64 | return file_tendermint_proto_rawDescGZIP(), []int{0} 65 | } 66 | 67 | func (x *Tx) GetMethod() string { 68 | if x != nil { 69 | return x.Method 70 | } 71 | return "" 72 | } 73 | 74 | func (x *Tx) GetParams() []byte { 75 | if x != nil { 76 | return x.Params 77 | } 78 | return nil 79 | } 80 | 81 | func (x *Tx) GetNonce() []byte { 82 | if x != nil { 83 | return x.Nonce 84 | } 85 | return nil 86 | } 87 | 88 | func (x *Tx) GetSignature() []byte { 89 | if x != nil { 90 | return x.Signature 91 | } 92 | return nil 93 | } 94 | 95 | func (x *Tx) GetNodeId() string { 96 | if x != nil { 97 | return x.NodeId 98 | } 99 | return "" 100 | } 101 | 102 | type Query struct { 103 | state protoimpl.MessageState 104 | sizeCache protoimpl.SizeCache 105 | unknownFields protoimpl.UnknownFields 106 | 107 | Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` 108 | Params []byte `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"` 109 | } 110 | 111 | func (x *Query) Reset() { 112 | *x = Query{} 113 | if protoimpl.UnsafeEnabled { 114 | mi := &file_tendermint_proto_msgTypes[1] 115 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 116 | ms.StoreMessageInfo(mi) 117 | } 118 | } 119 | 120 | func (x *Query) String() string { 121 | return protoimpl.X.MessageStringOf(x) 122 | } 123 | 124 | func (*Query) ProtoMessage() {} 125 | 126 | func (x *Query) ProtoReflect() protoreflect.Message { 127 | mi := &file_tendermint_proto_msgTypes[1] 128 | if protoimpl.UnsafeEnabled && x != nil { 129 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 130 | if ms.LoadMessageInfo() == nil { 131 | ms.StoreMessageInfo(mi) 132 | } 133 | return ms 134 | } 135 | return mi.MessageOf(x) 136 | } 137 | 138 | // Deprecated: Use Query.ProtoReflect.Descriptor instead. 139 | func (*Query) Descriptor() ([]byte, []int) { 140 | return file_tendermint_proto_rawDescGZIP(), []int{1} 141 | } 142 | 143 | func (x *Query) GetMethod() string { 144 | if x != nil { 145 | return x.Method 146 | } 147 | return "" 148 | } 149 | 150 | func (x *Query) GetParams() []byte { 151 | if x != nil { 152 | return x.Params 153 | } 154 | return nil 155 | } 156 | 157 | var File_tendermint_proto protoreflect.FileDescriptor 158 | 159 | var file_tendermint_proto_rawDesc = []byte{ 160 | 0x0a, 0x10, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 161 | 0x74, 0x6f, 0x12, 0x21, 0x6e, 0x64, 0x69, 0x64, 0x5f, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x6d, 162 | 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x63, 0x69, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 163 | 0x63, 0x65, 0x5f, 0x76, 0x39, 0x22, 0x81, 0x01, 0x0a, 0x02, 0x54, 0x78, 0x12, 0x16, 0x0a, 0x06, 164 | 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 165 | 0x74, 0x68, 0x6f, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 166 | 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 167 | 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 168 | 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 169 | 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 170 | 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 171 | 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x05, 0x51, 0x75, 0x65, 172 | 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 173 | 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 174 | 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 175 | 0x6d, 0x73, 0x42, 0x26, 0x5a, 0x24, 0x2e, 0x2f, 0x3b, 0x6e, 0x64, 0x69, 0x64, 0x5f, 0x74, 0x65, 176 | 0x6e, 0x64, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x63, 0x69, 0x5f, 0x69, 0x6e, 177 | 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x76, 0x39, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 178 | 0x6f, 0x33, 179 | } 180 | 181 | var ( 182 | file_tendermint_proto_rawDescOnce sync.Once 183 | file_tendermint_proto_rawDescData = file_tendermint_proto_rawDesc 184 | ) 185 | 186 | func file_tendermint_proto_rawDescGZIP() []byte { 187 | file_tendermint_proto_rawDescOnce.Do(func() { 188 | file_tendermint_proto_rawDescData = protoimpl.X.CompressGZIP(file_tendermint_proto_rawDescData) 189 | }) 190 | return file_tendermint_proto_rawDescData 191 | } 192 | 193 | var file_tendermint_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 194 | var file_tendermint_proto_goTypes = []interface{}{ 195 | (*Tx)(nil), // 0: ndid_tendermint_abci_interface_v9.Tx 196 | (*Query)(nil), // 1: ndid_tendermint_abci_interface_v9.Query 197 | } 198 | var file_tendermint_proto_depIdxs = []int32{ 199 | 0, // [0:0] is the sub-list for method output_type 200 | 0, // [0:0] is the sub-list for method input_type 201 | 0, // [0:0] is the sub-list for extension type_name 202 | 0, // [0:0] is the sub-list for extension extendee 203 | 0, // [0:0] is the sub-list for field type_name 204 | } 205 | 206 | func init() { file_tendermint_proto_init() } 207 | func file_tendermint_proto_init() { 208 | if File_tendermint_proto != nil { 209 | return 210 | } 211 | if !protoimpl.UnsafeEnabled { 212 | file_tendermint_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 213 | switch v := v.(*Tx); i { 214 | case 0: 215 | return &v.state 216 | case 1: 217 | return &v.sizeCache 218 | case 2: 219 | return &v.unknownFields 220 | default: 221 | return nil 222 | } 223 | } 224 | file_tendermint_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 225 | switch v := v.(*Query); i { 226 | case 0: 227 | return &v.state 228 | case 1: 229 | return &v.sizeCache 230 | case 2: 231 | return &v.unknownFields 232 | default: 233 | return nil 234 | } 235 | } 236 | } 237 | type x struct{} 238 | out := protoimpl.TypeBuilder{ 239 | File: protoimpl.DescBuilder{ 240 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 241 | RawDescriptor: file_tendermint_proto_rawDesc, 242 | NumEnums: 0, 243 | NumMessages: 2, 244 | NumExtensions: 0, 245 | NumServices: 0, 246 | }, 247 | GoTypes: file_tendermint_proto_goTypes, 248 | DependencyIndexes: file_tendermint_proto_depIdxs, 249 | MessageInfos: file_tendermint_proto_msgTypes, 250 | }.Build() 251 | File_tendermint_proto = out.File 252 | file_tendermint_proto_rawDesc = nil 253 | file_tendermint_proto_goTypes = nil 254 | file_tendermint_proto_depIdxs = nil 255 | } 256 | -------------------------------------------------------------------------------- /protos/tendermint/tendermint.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "./;ndid_tendermint_abci_interface_v9"; 4 | 5 | package ndid_tendermint_abci_interface_v9; 6 | 7 | message Tx { 8 | string method = 1; 9 | bytes params = 2; 10 | bytes nonce = 3; 11 | bytes signature = 4; 12 | string node_id = 5; 13 | } 14 | 15 | message Query { 16 | string method = 1; 17 | bytes params = 2; 18 | } -------------------------------------------------------------------------------- /scripts/run_dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | trap killgroup SIGINT 4 | 5 | killgroup(){ 6 | echo killing... 7 | kill 0 8 | } 9 | 10 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 11 | REPO_DIR="$(dirname $BASE_DIR)" 12 | 13 | NODE1_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/IdP" 14 | NODE2_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/RP" 15 | NODE3_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/AS" 16 | NODE4_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/proxy" 17 | 18 | TMP_DIR="$REPO_DIR/tmp" 19 | 20 | NODE1_ABCI_DB_DIR="$TMP_DIR/idp_abci_db" 21 | NODE2_ABCI_DB_DIR="$TMP_DIR/rp_abci_db" 22 | NODE3_ABCI_DB_DIR="$TMP_DIR/as_abci_db" 23 | NODE4_ABCI_DB_DIR="$TMP_DIR/proxy_abci_db" 24 | 25 | reset_all_and_run_node_in_background() { 26 | go run ./abci --home $1 unsafe-reset-all && \ 27 | CGO_ENABLED=1 \ 28 | CGO_LDFLAGS="-lsnappy" \ 29 | ABCI_INITIAL_STATE_DIR_PATH=$ABCI_INITIAL_STATE_DIR_PATH \ 30 | ABCI_DB_DIR_PATH=$2 \ 31 | TENDERMINT_RETAIN_BLOCK_COUNT=$3 \ 32 | go run -tags "cleveldb" ./abci --home $1 node & 33 | } 34 | 35 | rm -rf $TMP_DIR 36 | 37 | reset_all_and_run_node_in_background $NODE1_TENDERMINT_HOME_DIR $NODE1_ABCI_DB_DIR 0 38 | 39 | # Wait a bit for the first node (seed node) to start 40 | sleep 2 41 | 42 | reset_all_and_run_node_in_background $NODE2_TENDERMINT_HOME_DIR $NODE2_ABCI_DB_DIR 0 43 | reset_all_and_run_node_in_background $NODE3_TENDERMINT_HOME_DIR $NODE3_ABCI_DB_DIR 0 44 | reset_all_and_run_node_in_background $NODE4_TENDERMINT_HOME_DIR $NODE4_ABCI_DB_DIR 0 45 | 46 | wait 47 | -------------------------------------------------------------------------------- /scripts/run_dev_as.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/AS" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/as_abci_db" 9 | 10 | rm -rf $ABCI_DB_DIR 11 | 12 | go run ./abci --home $TENDERMINT_HOME_DIR unsafe-reset-all && \ 13 | CGO_ENABLED=1 \ 14 | CGO_LDFLAGS="-lsnappy" \ 15 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 16 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 17 | -------------------------------------------------------------------------------- /scripts/run_dev_as_no_reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/AS" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/as_abci_db" 9 | 10 | CGO_ENABLED=1 \ 11 | CGO_LDFLAGS="-lsnappy" \ 12 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 13 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 14 | -------------------------------------------------------------------------------- /scripts/run_dev_idp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/IdP" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/idp_abci_db" 9 | 10 | rm -rf $ABCI_DB_DIR 11 | 12 | go run ./abci --home $TENDERMINT_HOME_DIR unsafe-reset-all && \ 13 | CGO_ENABLED=1 \ 14 | CGO_LDFLAGS="-lsnappy" \ 15 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 16 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 17 | -------------------------------------------------------------------------------- /scripts/run_dev_idp_no_reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/IdP" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/idp_abci_db" 9 | 10 | CGO_ENABLED=1 \ 11 | CGO_LDFLAGS="-lsnappy" \ 12 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 13 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 14 | -------------------------------------------------------------------------------- /scripts/run_dev_no_reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | trap killgroup SIGINT 4 | 5 | killgroup(){ 6 | echo killing... 7 | kill 0 8 | } 9 | 10 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 11 | REPO_DIR="$(dirname $BASE_DIR)" 12 | 13 | NODE1_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/IdP" 14 | NODE2_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/RP" 15 | NODE3_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/AS" 16 | NODE4_TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/proxy" 17 | 18 | TMP_DIR="$REPO_DIR/tmp" 19 | 20 | NODE1_ABCI_DB_DIR="$TMP_DIR/idp_abci_db" 21 | NODE2_ABCI_DB_DIR="$TMP_DIR/rp_abci_db" 22 | NODE3_ABCI_DB_DIR="$TMP_DIR/as_abci_db" 23 | NODE4_ABCI_DB_DIR="$TMP_DIR/proxy_abci_db" 24 | 25 | run_node_in_background() { 26 | CGO_ENABLED=1 \ 27 | CGO_LDFLAGS="-lsnappy" \ 28 | ABCI_DB_DIR_PATH=$2 \ 29 | TENDERMINT_RETAIN_BLOCK_COUNT=$3 \ 30 | go run -tags "cleveldb" ./abci --home $1 node & 31 | } 32 | 33 | run_node_in_background $NODE1_TENDERMINT_HOME_DIR $NODE1_ABCI_DB_DIR 0 34 | run_node_in_background $NODE2_TENDERMINT_HOME_DIR $NODE2_ABCI_DB_DIR 0 35 | run_node_in_background $NODE3_TENDERMINT_HOME_DIR $NODE3_ABCI_DB_DIR 0 36 | run_node_in_background $NODE4_TENDERMINT_HOME_DIR $NODE4_ABCI_DB_DIR 0 37 | 38 | wait 39 | -------------------------------------------------------------------------------- /scripts/run_dev_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/proxy" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/proxy_abci_db" 9 | 10 | rm -rf $ABCI_DB_DIR 11 | 12 | go run ./abci --home $TENDERMINT_HOME_DIR unsafe-reset-all && \ 13 | CGO_ENABLED=1 \ 14 | CGO_LDFLAGS="-lsnappy" \ 15 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 16 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node -------------------------------------------------------------------------------- /scripts/run_dev_proxy_no_reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/proxy" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/proxy_abci_db" 9 | 10 | CGO_ENABLED=1 \ 11 | CGO_LDFLAGS="-lsnappy" \ 12 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 13 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node -------------------------------------------------------------------------------- /scripts/run_dev_rp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/RP" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/rp_abci_db" 9 | 10 | rm -rf $ABCI_DB_DIR 11 | 12 | go run ./abci --home $TENDERMINT_HOME_DIR unsafe-reset-all && \ 13 | CGO_ENABLED=1 \ 14 | CGO_LDFLAGS="-lsnappy" \ 15 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 16 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 17 | -------------------------------------------------------------------------------- /scripts/run_dev_rp_no_reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASE_DIR="$(cd "$(dirname "$0")"; pwd)" 4 | REPO_DIR="$(dirname $BASE_DIR)" 5 | 6 | TENDERMINT_HOME_DIR="$REPO_DIR/config/tendermint/RP" 7 | 8 | ABCI_DB_DIR="$REPO_DIR/tmp/rp_abci_db" 9 | 10 | CGO_ENABLED=1 \ 11 | CGO_LDFLAGS="-lsnappy" \ 12 | ABCI_DB_DIR_PATH=$ABCI_DB_DIR \ 13 | go run -tags "cleveldb" ./abci --home $TENDERMINT_HOME_DIR node 14 | -------------------------------------------------------------------------------- /test/as/as.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, 2019 National Digital ID COMPANY LIMITED 3 | * 4 | * This file is part of NDID software. 5 | * 6 | * NDID is the free software: you can redistribute it and/or modify it under 7 | * the terms of the Affero GNU General Public License as published by the 8 | * Free Software Foundation, either version 3 of the License, or any later 9 | * version. 10 | * 11 | * NDID is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the Affero GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the Affero GNU General Public License 17 | * along with the NDID source code. If not, see https://www.gnu.org/licenses/agpl.txt. 18 | * 19 | * Please contact info@co.th for any further questions 20 | * 21 | */ 22 | 23 | package as 24 | 25 | import ( 26 | "encoding/json" 27 | "fmt" 28 | "testing" 29 | 30 | "github.com/ndidplatform/smart-contract/v9/abci/app/v1" 31 | "github.com/ndidplatform/smart-contract/v9/test/data" 32 | "github.com/ndidplatform/smart-contract/v9/test/utils" 33 | ) 34 | 35 | func RegisterServiceDestination(t *testing.T, nodeID, privK string, param app.RegisterServiceDestinationParam, expected string, expectResultFrom string) { 36 | privKey := utils.GetPrivateKeyFromString(privK) 37 | paramJSON, err := json.Marshal(param) 38 | if err != nil { 39 | fmt.Println("error:", err) 40 | } 41 | fnName := "RegisterServiceDestination" 42 | nonce, signature := utils.CreateSignatureAndNonce(fnName, paramJSON, privKey) 43 | result, _ := utils.CreateTxn([]byte(fnName), paramJSON, []byte(nonce), signature, []byte(nodeID)) 44 | resultObj, _ := result.(utils.ResponseTx) 45 | var actual string 46 | if expectResultFrom == "CheckTx" { 47 | actual = resultObj.Result.CheckTx.Log 48 | } else { 49 | actual = resultObj.Result.TxResult.Log 50 | } 51 | if actual != expected { 52 | t.Errorf("\n"+`CheckTx log: "%s"`, resultObj.Result.CheckTx.Log) 53 | t.Fatalf("FAIL: %s\nExpected: %#v\nActual: %#v", fnName, expected, actual) 54 | } 55 | t.Logf("PASS: %s", fnName) 56 | } 57 | 58 | func TestRegisterServiceDestination(t *testing.T, caseID int64, expected string, expectResultFrom string) { 59 | var nodeID string 60 | var privK string 61 | var param app.RegisterServiceDestinationParam 62 | switch caseID { 63 | case 1: 64 | param.ServiceID = data.ServiceID1 65 | param.MinAal = 1.1 66 | param.MinIal = 1.2 67 | param.SupportedNamespaceList = append(param.SupportedNamespaceList, data.UserNamespace1) 68 | nodeID = data.AS1 69 | privK = data.AsPrivK1 70 | case 2: 71 | param.ServiceID = data.ServiceID1 72 | param.MinAal = 1.1 73 | param.MinIal = 1.2 74 | param.SupportedNamespaceList = append(param.SupportedNamespaceList, data.UserNamespace1) 75 | nodeID = data.AS2 76 | privK = data.AsPrivK2 77 | } 78 | RegisterServiceDestination(t, nodeID, privK, param, expected, expectResultFrom) 79 | } 80 | 81 | func UpdateServiceDestination(t *testing.T, nodeID, privK string, param app.UpdateServiceDestinationParam, expected string, expectResultFrom string) { 82 | privKey := utils.GetPrivateKeyFromString(privK) 83 | paramJSON, err := json.Marshal(param) 84 | if err != nil { 85 | fmt.Println("error:", err) 86 | } 87 | fnName := "UpdateServiceDestination" 88 | nonce, signature := utils.CreateSignatureAndNonce(fnName, paramJSON, privKey) 89 | result, _ := utils.CreateTxn([]byte(fnName), paramJSON, []byte(nonce), signature, []byte(nodeID)) 90 | resultObj, _ := result.(utils.ResponseTx) 91 | var actual string 92 | if expectResultFrom == "CheckTx" { 93 | actual = resultObj.Result.CheckTx.Log 94 | } else { 95 | actual = resultObj.Result.TxResult.Log 96 | } 97 | if actual != expected { 98 | t.Errorf("\n"+`CheckTx log: "%s"`, resultObj.Result.CheckTx.Log) 99 | t.Fatalf("FAIL: %s\nExpected: %#v\nActual: %#v", fnName, expected, actual) 100 | } 101 | t.Logf("PASS: %s", fnName) 102 | } 103 | 104 | func TestUpdateServiceDestination(t *testing.T, caseID int64, expected string, expectResultFrom string) { 105 | var nodeID string 106 | var privK string 107 | var param app.UpdateServiceDestinationParam 108 | switch caseID { 109 | case 1: 110 | param.ServiceID = data.ServiceID1 111 | param.MinAal = 1.4 112 | param.MinIal = 1.5 113 | param.SupportedNamespaceList = append(param.SupportedNamespaceList, data.UserNamespace2) 114 | nodeID = data.AS1 115 | privK = data.AsPrivK1 116 | } 117 | UpdateServiceDestination(t, nodeID, privK, param, expected, expectResultFrom) 118 | } 119 | -------------------------------------------------------------------------------- /test/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/x509" 8 | "encoding/base64" 9 | "encoding/hex" 10 | "encoding/json" 11 | "encoding/pem" 12 | "fmt" 13 | "io" 14 | "log" 15 | mathRand "math/rand" 16 | "net/http" 17 | "net/url" 18 | "os" 19 | "strings" 20 | "time" 21 | 22 | abcitypes "github.com/cometbft/cometbft/abci/types" 23 | tmRand "github.com/cometbft/cometbft/libs/rand" 24 | "google.golang.org/protobuf/proto" 25 | 26 | protoTm "github.com/ndidplatform/smart-contract/v9/protos/tendermint" 27 | ) 28 | 29 | var tendermintAddr = GetEnv("TENDERMINT_ADDRESS", "http://localhost:45000") 30 | 31 | func GetPrivateKeyFromString(privK string) *rsa.PrivateKey { 32 | privK = strings.Replace(privK, "\t", "", -1) 33 | block, _ := pem.Decode([]byte(privK)) 34 | privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) 35 | if err != nil { 36 | fmt.Println(err.Error()) 37 | } 38 | return privateKey 39 | } 40 | 41 | func GeneratePublicKey(publicKey *rsa.PublicKey) ([]byte, error) { 42 | pubKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) 43 | if err != nil { 44 | return nil, err 45 | } 46 | privBlock := pem.Block{ 47 | Type: "PUBLIC KEY", 48 | Headers: nil, 49 | Bytes: pubKeyBytes, 50 | } 51 | publicPEM := pem.EncodeToMemory(&privBlock) 52 | return publicPEM, nil 53 | } 54 | 55 | func CreateSignatureAndNonce(fnName string, paramJSON []byte, privKey *rsa.PrivateKey) (nonce string, signature []byte) { 56 | status, err := Status() 57 | if err != nil { 58 | fmt.Println(err.Error()) 59 | return "", nil 60 | } 61 | 62 | currentChainID := status.Result.NodeInfo.Network 63 | 64 | nonce = base64.StdEncoding.EncodeToString([]byte(tmRand.Str(12))) 65 | tempPSSmessage := append([]byte(fnName), paramJSON...) 66 | tempPSSmessage = append(tempPSSmessage, []byte(currentChainID)...) 67 | tempPSSmessage = append(tempPSSmessage, []byte(nonce)...) 68 | PSSmessage := tempPSSmessage 69 | newhash := crypto.SHA256 70 | pssh := newhash.New() 71 | pssh.Write(PSSmessage) 72 | hashed := pssh.Sum(nil) 73 | signature, err = rsa.SignPKCS1v15(rand.Reader, privKey, newhash, hashed) 74 | if err != nil { 75 | fmt.Println(err.Error()) 76 | } 77 | return nonce, signature 78 | } 79 | 80 | func Status() (*ResponseStatus, error) { 81 | var URL *url.URL 82 | URL, err := url.Parse(tendermintAddr) 83 | if err != nil { 84 | panic(err) 85 | } 86 | URL.Path += "/status" 87 | encodedURL := URL.String() 88 | req, err := http.NewRequest("GET", encodedURL, nil) 89 | if err != nil { 90 | fmt.Println(err.Error()) 91 | return nil, err 92 | } 93 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 94 | client := &http.Client{ 95 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 96 | return http.ErrUseLastResponse 97 | }, 98 | } 99 | resp, err := client.Do(req) 100 | if err != nil { 101 | return nil, err 102 | } 103 | defer resp.Body.Close() 104 | var body *ResponseStatus 105 | err = json.NewDecoder(resp.Body).Decode(&body) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return body, nil 110 | } 111 | 112 | func CreateTxn(fnName []byte, param []byte, nonce []byte, signature []byte, nodeID []byte) (interface{}, error) { 113 | var tx protoTm.Tx 114 | tx.Method = string(fnName) 115 | tx.Params = param 116 | tx.Nonce = nonce 117 | tx.Signature = signature 118 | tx.NodeId = string(nodeID) 119 | txByte, err := proto.Marshal(&tx) 120 | if err != nil { 121 | log.Printf("err: %s", err.Error()) 122 | } 123 | txEncoded := hex.EncodeToString(txByte) 124 | var URL *url.URL 125 | URL, err = url.Parse(tendermintAddr) 126 | if err != nil { 127 | panic("boom") 128 | } 129 | URL.Path += "/broadcast_tx_commit" 130 | parameters := url.Values{} 131 | parameters.Add("tx", `0x`+txEncoded) 132 | URL.RawQuery = parameters.Encode() 133 | encodedURL := URL.String() 134 | req, err := http.NewRequest("GET", encodedURL, nil) 135 | if err != nil { 136 | fmt.Println(err.Error()) 137 | return nil, err 138 | } 139 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 140 | client := &http.Client{ 141 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 142 | return http.ErrUseLastResponse 143 | }, 144 | } 145 | resp, err := client.Do(req) 146 | if err != nil { 147 | return nil, err 148 | } 149 | defer resp.Body.Close() 150 | 151 | bodyBytes, err := io.ReadAll(resp.Body) 152 | if err != nil { 153 | log.Fatal(err) 154 | } 155 | // bodyString := string(bodyBytes) 156 | // fmt.Println(">>>", bodyString) 157 | 158 | var body ResponseTx 159 | 160 | err = json.Unmarshal(bodyBytes, &body) 161 | // err = json.NewDecoder(resp.Body).Decode(&body) 162 | if err != nil { 163 | panic(err) 164 | // return nil, err 165 | } 166 | return body, nil 167 | } 168 | 169 | func Query(fnName []byte, param []byte) (interface{}, error) { 170 | var data protoTm.Query 171 | data.Method = string(fnName) 172 | data.Params = param 173 | dataByte, err := proto.Marshal(&data) 174 | if err != nil { 175 | log.Printf("err: %s", err.Error()) 176 | } 177 | dataEncoded := hex.EncodeToString(dataByte) 178 | var URL *url.URL 179 | URL, err = url.Parse(tendermintAddr) 180 | if err != nil { 181 | panic("boom") 182 | } 183 | URL.Path += "/abci_query" 184 | parameters := url.Values{} 185 | parameters.Add("data", `0x`+dataEncoded) 186 | URL.RawQuery = parameters.Encode() 187 | encodedURL := URL.String() 188 | req, err := http.NewRequest("GET", encodedURL, nil) 189 | if err != nil { 190 | fmt.Println(err.Error()) 191 | return nil, err 192 | } 193 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 194 | client := &http.Client{ 195 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 196 | return http.ErrUseLastResponse 197 | }, 198 | } 199 | resp, err := client.Do(req) 200 | if err != nil { 201 | return nil, err 202 | } 203 | defer resp.Body.Close() 204 | 205 | bodyBytes, err := io.ReadAll(resp.Body) 206 | if err != nil { 207 | log.Fatal(err) 208 | } 209 | // bodyString := string(bodyBytes) 210 | // fmt.Println(">>>", bodyString) 211 | 212 | var body ResponseQuery 213 | err = json.Unmarshal(bodyBytes, &body) 214 | // err = json.NewDecoder(resp.Body).Decode(&body) 215 | if err != nil { 216 | panic(err) 217 | // return nil, err 218 | } 219 | return body, nil 220 | } 221 | 222 | func GetEnv(key, defaultValue string) string { 223 | value, exists := os.LookupEnv(key) 224 | if !exists { 225 | value = defaultValue 226 | } 227 | return value 228 | } 229 | 230 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 231 | 232 | func RandStringRunes(n int) string { 233 | mathRand.Seed(time.Now().UnixNano()) 234 | b := make([]rune, n) 235 | for i := range b { 236 | b[i] = letterRunes[mathRand.Intn(len(letterRunes))] 237 | } 238 | return string(b) 239 | } 240 | 241 | type ResponseTx struct { 242 | Jsonrpc string `json:"jsonrpc"` 243 | ID int `json:"id"` 244 | Result struct { 245 | CheckTx struct { 246 | Code int `json:"code"` 247 | Log string `json:"log"` 248 | } `json:"check_tx"` 249 | TxResult struct { 250 | Code int `json:"code"` 251 | Log string `json:"log"` 252 | Events []abcitypes.Event `json:"events"` 253 | } `json:"tx_result"` 254 | Hash string `json:"hash"` 255 | Height string `json:"height"` 256 | } `json:"result"` 257 | } 258 | 259 | type ResponseQuery struct { 260 | Jsonrpc string `json:"jsonrpc"` 261 | ID int `json:"id"` 262 | Result struct { 263 | Response struct { 264 | Log string `json:"log"` 265 | Value string `json:"value"` 266 | Height string `json:"height"` 267 | } `json:"response"` 268 | } `json:"result"` 269 | } 270 | 271 | type ResponseStatus struct { 272 | Jsonrpc string `json:"jsonrpc"` 273 | ID int `json:"id"` 274 | Result struct { 275 | NodeInfo struct { 276 | ProtocolVersion struct { 277 | P2P string `json:"p2p"` 278 | Block string `json:"block"` 279 | App string `json:"app"` 280 | } `json:"protocol_version"` 281 | ID string `json:"id"` 282 | ListenAddr string `json:"listen_addr"` 283 | Network string `json:"network"` 284 | Version string `json:"version"` 285 | Channels string `json:"channels"` 286 | Moniker string `json:"moniker"` 287 | Other struct { 288 | TxIndex string `json:"tx_index"` 289 | RPCAddress string `json:"rpc_address"` 290 | } `json:"other"` 291 | } `json:"node_info"` 292 | SyncInfo struct { 293 | LatestBlockHash string `json:"latest_block_hash"` 294 | LatestAppHash string `json:"latest_app_hash"` 295 | LatestBlockHeight string `json:"latest_block_height"` 296 | LatestBlockTime time.Time `json:"latest_block_time"` 297 | EarliestBlockHash string `json:"earliest_block_hash"` 298 | EarliestAppHash string `json:"earliest_app_hash"` 299 | EarliestBlockHeight string `json:"earliest_block_height"` 300 | EarliestBlockTime time.Time `json:"earliest_block_time"` 301 | CatchingUp bool `json:"catching_up"` 302 | } `json:"sync_info"` 303 | ValidatorInfo struct { 304 | Address string `json:"address"` 305 | PubKey struct { 306 | Type string `json:"type"` 307 | Value string `json:"value"` 308 | } `json:"pub_key"` 309 | VotingPower string `json:"voting_power"` 310 | } `json:"validator_info"` 311 | } `json:"result"` 312 | } 313 | --------------------------------------------------------------------------------