diff --git a/README.md b/README.md index 6aa65b90..4613081f 100644 --- a/README.md +++ b/README.md @@ -1,395 +1,160 @@ -# rubixgoplatform +# Rubix Blockchain Platform -The new Rubixgoplatform support command line options to run/configure the Rubix node. To run the application use the follwing format. +Rubix is a highly scalable, zero-free blockchain that overcomes the scale, cost, and privacy issues of traditional sequentially organized blockchains. It utilizes a novel Proof-of-Pledge (PoP) consensus mechanism, designed to address the drawbacks of Proof-of-Work (PoW) and Proof-of-Stake (PoS) systems. -``` -./rubixgoplatform +### Building from Source -Use the following commands +1. Clone the repository - -v : To get tool version + ``` + git clone https://github.com/rubixchain/rubixgoplatform.git + cd rubixgoplatform + ``` - -h : To get help +2. Based on the OS, run any one of the following commands to build `rubixgoplatform` binary: - run : To run the rubix core +- Linux (binary will be created in `linux` directory) - ping : Use the command to ping the peer -``` + ``` + make compile-linux + ``` -Run Command -: To run the Rubix node use this command. -``` -./rubixgoplatform run -p node1 -n 0 -s -testNet - -This following options are used to run the Rubix node - -n uint - Node number - -p string - Working directory path (default "./") - -s Start the core - -testNet - Run as test net - -testNetKey string - Test net key (default "testswarm.key") -``` -Ping Command -: To ping any peer in network use this command. -``` -./rubixgoplatform ping -peerID 12D3KooWKr8dEQiLXuKacxDCZiHePVEMpgjxk19C3QozuUVQcQHA -port +- MacOS (binary will be created in `mac` directory) -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -peerID string - Peerd ID - -port string - Server/Host port (default "20000") -``` -Add Bootstrap Command -: To add bootstrap to node use this command. -``` -./rubixgoplatform addbootstrap -peers /ip4/103.60.213.76/tcp/4001/p2p/QmR1VH6SsEN1wf4EmstxXtNMvR35KEetbBetiGWWKWavJ6 + ``` + make compile-mac + ``` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -peers string - Bootstrap peers, mutiple peers will be seprated by comma - -port string - Server/Host port (default "20000") -``` -Remove Bootstrap Command -: To remove bootstrap from node use this command. -``` -./rubixgoplatform removebootstrap -peers /ip4/103.60.213.76/tcp/4001/p2p/QmR1VH6SsEN1wf4EmstxXtNMvR35KEetbBetiGWWKWavJ6 +- Windows (binary will be created in `windows` directory) -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -peers string - Bootstrap peers, mutiple peers will be seprated by comma - -port string - Server/Host port (default "20000") -``` -Remove All Bootstrap Command -: To remove all bootstrap from node use this command. -``` -./rubixgoplatform removeallbootstrap + ``` + make compile-windows + ``` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") -``` -Get All Bootstrap Command -: To get all bootstrap from node use this command. -``` -./rubixgoplatform getallbootstrap +## Running a Rubix Node -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") -``` -Create DID Command -: To create DID use this command. -``` -./rubixgoplatform createdid +0. Build `rubixgoplaform` (Refer previous section) -This following options are used for this command - -port string - Server/Host port (default "20000") - -didType int - DID type (0-Basic Mode, 1-Standard Mode, 2-Wallet Mode, 3-Child Mode, 4-Light Mode) (default 0) - -didSecret string - DID secret (default "My DID Secret") - -privPWD string - Private key password (default "mypassword") - -quorumPWD string - Quroum key password (default "mypassword") - -imgFile string - Image file to create DID (Must be 256x256 PNG image) (default "image.png") - -didImgFile string - DID image file name (default "did.png") - -privImgFile string - DID private share image file name (default "pvtShare.png") - -pubImgFile string - DID public share image file name (default "pubShare.png") - -privKeyFile string - DID private key file name (default "pvtKey.pem") - -pubKeyFile string - DID public key file name (default "pubKey.pem") - -mnemonicKeyFile string - Mnemonic key file (default "mnemonic.txt") - -ChildPath int - BIP Child Path (default 0) - -fp forcepassword - This flag prompts to enter the password in terminal - - _Note: Use Light mode for PKI based authentication with backward compatiblity to PKI+NLSS based sign, and Basic mode for PKI+NLSS based authentication._ -``` -Get All DID Command -: To get all DID use this command. -``` -./rubixgoplatform getalldid +1. Install IPFS Kubo Client (version: `0.21.0`) and copy the IPFS binary to build directory. Refer the section based on your Operating System -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") -``` -To Register DID Command -: To register DID & PeerID map on the network use this command. -``` -./rubixgoplatform registerdid +
+ Windows Installation + +<<<<<<< HEAD + - In Powershell, run the following to install the IPFS kubo client: -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -did string - DID address (default "") -``` -To Add Quorum List -: To add quorum list use this command. -``` -./rubixgoplatform addquorum + ``` + wget https://dist.ipfs.tech/kubo/v0.21.0/kubo_v0.21.0_windows-amd64.zip -Outfile kubo_v0.21.0.zip + ``` + + - Extract `kubo_v0.21.0.zip` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -quorumList string - quorum list file name (default "quorumlist.json") -``` -To Get All Quorum List -: To get all quorum list use this command. -``` -./rubixgoplatform getallquorum + ``` + Expand-Archive -Path kubo_v0.28.0.zip + ``` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") -``` -To Remove All Quorum List -: To remove all quorum list use this command. -``` -./rubixgoplatform removeallquorum + - Copy the `ipfs` binary to build directory -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") -``` -To Setup Quorum -: To setup quorum use this command. This setup quorum by providn quorum private key password. -``` -./rubixgoplatform setupquorum + ``` + cp .\kubo_v0.28.0\kubo\ipfs.exe \windows\ + ``` +
-This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -quorumPWD string - Quroum key password (default "mypassword") - -fp forcepassword - Enter the Quroum key password in terminal -``` -To Setup Service Command -: To setup service on the node use this command. -``` -./rubixgoplatform setupservice +
+ Linux Installation + + - Run the following to install the IPFS kubo client: -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -srvName string - Service name (default "explorer_service") - -dbAddress string - Database address (default "localhost") - -dbName string - Explorer database name (default "ExplorerDB") - -dbPassword string - Database password (default "password") - -dbPort string - Database port number (default "1433") - -dbType string - DB Type, supported database are SQLServer, PostgressSQL, MySQL & Sqlite3 (default "SQLServer") - -dbUsername string - Database username (default "sa") -``` -To Generate Test RBT Command -: To generate test RBT on the node use this command. -``` -./rubixgoplatform generatetestrbt + ``` + wget https://dist.ipfs.tech/kubo/v0.21.0/kubo_v0.21.0_linux-amd64.tar.gz + ``` + + - Extract `kubo_v0.21.0_linux-amd64.tar.gz` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -did string - DID address (default "") - -numTokens int - Number tokens to be generated (default 1) - -fp - Force password to be entered on the terminal - -privPWD string - Private key password (default "mypassword") - -privImgFile string - DID private share image file name (default "pvtShare.png") - -privKeyFile string - DID private key file name (default "pvtKey.pem") -``` -To Transfer RBT Command -: To trasnfer RBT on the node use this command. -``` -./rubixgoplatform transferrbt + ``` + tar -xvzf kubo_v0.21.0_linux-amd64.tar.gz + ``` -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -senderAddr string - Sender address (default "") - -receiverAddr string - Receiver address (default "") - -rbtAmount float - RBT amount to trasnfered (default 0.0) - -transComment string - Transfer comment (default "Test tranasaction") - -transType int - Transaction type (default 2) - -fp - Force password to be entered on the terminal - -privPWD string - Private key password (default "mypassword") - -privImgFile string - DID private share image file name (default "pvtShare.png") - -privKeyFile string - DID private key file name (default "pvtKey.pem") -``` -To Get Account Info Command -: To get account information on the node use this command. -``` -./rubixgoplatform getaccountinfo + - Copy the `ipfs` binary to build directory -This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -did string - DID address (default "") -``` -To Dump Token Chain Command -: To dump token chain on the node use this command. -``` -./rubixgoplatform dumptokenchain + ``` + cp kubo/ipfs /linux/ + ``` +
-This following options are used for this command - -addr string - Server/Host Address (default "localhost") - -port string - Server/Host port (default "20000") - -token string - Token address (default "") -``` -To Migrate Existing Java Node to RubixGo -: To dump token chain on the node use this command. -``` -./rubixgoplatform migratenode +
+ MacOS Installation + + - Run the following to install the IPFS kubo client: -This following options are used for this command - -port string - Server/Host port (default "20000") - -fp - Force password to be entered on the terminal -``` -To Add explorer url -: To add explorer url where to send the transaction data. -``` -./rubixgoplatform addexplorer + ``` + wget https://dist.ipfs.tech/kubo/v0.21.0/kubo_v0.21.0_darwin-arm64.tar.gz + ``` + + - Extract `kubo_v0.21.0_darwin-arm64.tar.gz` -This following options are used for this command - -links string - URLs, mutiple URLs will be seprated by comma - -port string - Server/Host port (default "20000") -``` -To remove explorer url -: To remove explorer url where not to send the transaction data. -``` -./rubixgoplatform removeexplorer + ``` + tar -xvzf kubo_v0.21.0_darwin-arm64.tar.gz + ``` -This following options are used for this command - -links string - URLs, mutiple URLs will be seprated by comma - -port string - Server/Host port (default "20000") -``` -To get all explorer urls -: To get explorer urls where the transaction data is being sent. -``` -./rubixgoplatform getallexplorer + - Copy the `ipfs` binary to build directory -This following options are used for this command - -port string - Server/Host port (default "20000") -``` -To add the peer details manually -: To add the peer details by providing peerID, did and didType of the peer + ``` + cp kubo/ipfs /mac/ + ``` +
-``` -./rubixgoplatform addpeerdetails +2. Copy the `swarm.key` present in the root directory into the build directory and rename it to `testswarm.key`. -This following options are used for this command - -port string - Server/Host port (default "20000") - - -peerID string - Peerd ID - - -did string - DID address (default "") +3. Run the following from the build directory: - -didType int - DID type (0-Basic Mode, 1-Standard Mode, 2-Wallet Mode, 3-Child Mode, 4-Light Mode) (default 0) -``` + - Linux and Macos -To check details about the token states for which pledging has been done -: To check for what token states the pledging has been done, and which tokens are pledged + ``` + ./rubixgoplatform run --p node0 --n 0 --s --testNet --grpcPort 10500 + ``` -``` -./rubixgoplatform getpledgedtokendetails + - Windows -This following options are used for this command - -port string - Server/Host port (default "20000") -``` + ``` + .\rubixgoplatform.exe run --p node0 --n 0 --s --testNet --grpcPort 10500 + ``` -To check tokenstatehash status -: To check if a particular tokenstatehash is exhausted, i.e if it has been transferred further + The above command creates a `node0` name directory inside the build directory which hosts the configuration and DB files.The `rubixgodaemon` daemon runs on port `20000` and the gRPC server runs on `10500` + +## Rubix CLI + +Please refer [Rubix CLI](./command/README.md) docs for more details on the `rubixgoplatform` CLI +======= + -tokenstatehash string + TokenState Hash, for which the status needs to be checked +``` +Validate Token Chain Command +: To validate RBT and smart contract token chain ``` -./rubixgoplatform tokenstatehash +./rubixgoplatform validatetokenchain This following options are used for this command -port string Server/Host port (default "20000") - - -tokenstatehash string - TokenState Hash, for which the status needs to be checked -``` \ No newline at end of file + + -did string + DID address (default "") + + -sctValidation bool + (default false) provide in case of smart contract token chain validation + + -token string + token ID (default "") + + -allmyTokens bool + (default false) provide to validate all tokens from tokens table + + -blockCount int + number of blocks of the token chain to be validated (default 0) + + NOTE: Don't provide the flag -blockCount in case you want to validate all the blocks of the token chain + +``` +>>>>>>> 7593733ff89c2ef5aca349a68ce18bf77560fb3a diff --git a/block/block.go b/block/block.go index 2b246e27..d8fa11a4 100644 --- a/block/block.go +++ b/block/block.go @@ -25,23 +25,23 @@ import ( // } const ( - TCTokenTypeKey string = "1" - TCTransTypeKey string = "2" - TCTokenOwnerKey string = "3" - TCGenesisBlockKey string = "4" - TCTransInfoKey string = "5" - TCSmartContractKey string = "6" - TCQuorumSignatureKey string = "7" - TCPledgeDetailsKey string = "8" - TCBlockHashKey string = "98" - TCSignatureKey string = "99" - TCBlockContentKey string = "1" - TCBlockContentSigKey string = "2" - TCSmartContractDataKey string = "9" - TCTokenValueKey string = "10" - TCChildTokensKey string = "11" - TCSenderSignatureKey string = "12" - TCEpochKey string = "epoch" + TCTokenTypeKey string = "1" + TCTransTypeKey string = "2" + TCTokenOwnerKey string = "3" + TCGenesisBlockKey string = "4" + TCTransInfoKey string = "5" + TCSmartContractKey string = "6" + TCQuorumSignatureKey string = "7" + TCPledgeDetailsKey string = "8" + TCBlockHashKey string = "98" + TCSignatureKey string = "99" + TCBlockContentKey string = "1" + TCBlockContentSigKey string = "2" + TCSmartContractDataKey string = "9" + TCTokenValueKey string = "10" + TCChildTokensKey string = "11" + TCInitiatorSignatureKey string = "12" + TCEpochKey string = "epoch" ) const ( @@ -59,6 +59,22 @@ const ( TokenPinnedAsService string = "12" ) +const ( + Initiator_NLSS_share string = "nlss_share_signature" + Initiator_Private_sign string = "priv_signature" + Initiator_DID string = "initiator_did" + Initiator_Hash string = "hash" + Initiator_SignType string = "sign_type" +) + +const ( + CreditSig_Signature string = "signature" + CreditSig_PrivSignature string = "priv_signature" + CreditSig_DID string = "did" + CreditSig_Hash string = "hash" + CreditSig_SignType string = "sign_type" +) + type TokenChainBlock struct { TransactionType string `json:"transactionType"` TokenOwner string `json:"owner"` @@ -173,7 +189,7 @@ func CreateNewBlock(ctcb map[string]*Block, tcb *TokenChainBlock) *Block { ntcb[TCSmartContractDataKey] = tcb.SmartContractData } if tcb.InitiatorSignature != nil { - ntcb[TCSenderSignatureKey] = tcb.InitiatorSignature + ntcb[TCInitiatorSignatureKey] = tcb.InitiatorSignature } if floatPrecisionToMaxDecimalPlaces(tcb.TokenValue) > floatPrecisionToMaxDecimalPlaces(0) { @@ -725,3 +741,77 @@ func (b *Block) GetChildTokens() []string { func (b *Block) GetEpoch() int64 { return int64(util.GetIntFromMap(b.bm, TCEpochKey)) } + +// Fetch initiator signature details from the given block +func (b *Block) GetInitiatorSignature() *InitiatorSignature { + var initiator_sign InitiatorSignature + s, ok := b.bm[TCInitiatorSignatureKey] + if !ok || s == nil { + return nil + } + //fetch initiator did + did_ := util.GetFromMap(s, Initiator_DID) + initiator_sign.DID = did_.(string) + //fetch initiator sign type + sign_type_ := util.GetFromMap(s, Initiator_SignType) + initiator_sign.SignType = int(sign_type_.(uint64)) + //fetch initiator nlss share sign + nlss_share_ := util.GetFromMap(s, Initiator_NLSS_share) + initiator_sign.NLSS_share = nlss_share_.(string) + //fetch initiator private sign + priv_sign_ := util.GetFromMap(s, Initiator_Private_sign) + initiator_sign.Private_sign = priv_sign_.(string) + //fetch initiator hash / signed data + signed_data_ := util.GetFromMap(s, Initiator_Hash) + initiator_sign.Hash = signed_data_.(string) + + return &initiator_sign +} + +// Fetch quorums' signature details from the given block +func (b *Block) GetQuorumSignatureList() ([]CreditSignature, error) { + var quorum_sign_list []CreditSignature + s := b.bm[TCQuorumSignatureKey] + + qrmSignList_map, ok := s.([]interface{}) + if !ok { + fmt.Println("not of type []interface{}") + return nil, fmt.Errorf("failed to fetch quorums' signature information from block map") + } + for _, qrmSignList_ := range qrmSignList_map { + var quorum_sig CreditSignature + //fetch quorum did + qrm_did := util.GetFromMap(qrmSignList_, CreditSig_DID) + quorum_sig.DID = qrm_did.(string) + // //fetch quorum sign type + sign_type_ := util.GetFromMap(qrmSignList_, CreditSig_SignType) + quorum_sig.SignType = sign_type_.(string) + // //fetch quorum nlss share sign + nlss_share_ := util.GetFromMap(qrmSignList_, CreditSig_Signature) + quorum_sig.Signature = nlss_share_.(string) + // //fetch quorum private sign + priv_sign_ := util.GetFromMap(qrmSignList_, CreditSig_PrivSignature) + quorum_sig.PrivSignature = priv_sign_.(string) + quorum_sign_list = append(quorum_sign_list, quorum_sig) + } + + return quorum_sign_list, nil +} + +// calculate block hash from block data +func (b *Block) CalculateBlockHash() (string, error) { + var m map[string]interface{} + + err := cbor.Unmarshal(b.bb, &m) + if err != nil { + return "", err + } + bc, ok := m[TCBlockContentKey] + if !ok { + return "", fmt.Errorf("invalid block, block content missing") + } + hb := util.CalculateHash(bc.([]byte), "SHA3-256") + block_hash := util.HexToStr(hb) + + return block_hash, nil +} diff --git a/client/token.go b/client/token.go index 0c6a4b29..9a3579af 100644 --- a/client/token.go +++ b/client/token.go @@ -3,6 +3,8 @@ package client import ( "time" + "strconv" + "github.com/rubixchain/rubixgoplatform/core/model" "github.com/rubixchain/rubixgoplatform/setup" ) @@ -53,3 +55,18 @@ func (c *Client) GetPinnedInfo(TokenStateHash string) (*model.BasicResponse, err } return &br, nil } + +func (c *Client) ValidateTokenchain(user_did string, smartContractChainValidation bool, token string, blockCount int) (*model.BasicResponse, error) { + q := make(map[string]string) + q["did"] = user_did + q["token"] = token + q["blockcount"] = strconv.Itoa(blockCount) + q["SCChainValidation"] = strconv.FormatBool(smartContractChainValidation) + + var br model.BasicResponse + err := c.sendJSONRequest("GET", setup.APIValidateTokenChain, q, nil, &br) + if err != nil { + return nil, err + } + return &br, nil +} diff --git a/command/README.md b/command/README.md new file mode 100644 index 00000000..8e1f169d --- /dev/null +++ b/command/README.md @@ -0,0 +1,194 @@ +# Rubix CLI + +The `command` package builds a structured and extensible Command-Line Interface for Rubix Blockchain Platform. + +## Commands + +Rubix CLI has the following top-level commands: + +- [boostrap](#bootstrap-command) +- [chain-dump](#chain-dump-command) +- [config](#config-command) +- [did](#did-command) +- [explorer](#explorer-command) +- [node](#node-command) + - [node peer](#node-peer) +- [quorum](#quorum-command) +- [run](#run-command) +- [tx](#tx-commands) + - [tx rbt](#tx-rbt) + - [tx smart-contract](#tx-smart-contract) + - [tx nft](#tx-nft) + - [tx data-token](#tx-data-token) +- [upgrade](#upgrade-command) +- [pin-service](#pin-service-command) +- [validate-chain](#validate-chain-command) +- [version](#version-command) + +`addr` and `port` are Global Glags, which can be used in any command. Their default values are `localhost` and `20000` respectively. + +Run `rubixgoplatform -h` to know more + +### `bootstrap` Command + +It consists of subcommands that are associated with managing boostrap nodes: + +- `add`: Add IPFS bootstrap peers +- `list`: List all bootstrap peers from the configuration +- `remove`: Remove bootstrap peer(s) from the configuration +- `remove-all`: Removes all bootstrap peers from the configuration + +To know more about the flags, run `rubixgoplatform bootstrap [command] --help` + +### `chain-dump` Command + +It consists of subcommands that are associated with Token chain and SmartContract chain dumps. + +- `smart-contract`: Get the dump of Smart Contract chain +- `token`: Get the dump of Token chain +- `decode-token-chain`: Decodes token chain dump + +To know more about the flags, run `rubixgoplatform chain-dump [command] --help` + +### `config` Command + +It consists of subcommands that are associated with setting up DB and Services. + +- `setup-db`: Setup Database +- `setup-service`: Setup Service + +To know more about the flags, run `rubixgoplatform config [command] --help` + +### `did` Command + +It consists of subcommands that are associated with managing DIDs + +- `balance`: Get the account balance information of a DID +- `create`: Create a DID +- `list`: Fetch every DID present in the node +- `register`: Register DID + +To know more about the flags, run `rubixgoplatform did [command] --help` + +### `explorer` Command + +It consists of subcommands that are associated with explorer. + +- `add`: Add Explorer URLs +- `list`: List all Explorer URLs +- `remove`: Remove Explorer URLs + +To know more about the flags, run `rubixgoplatform explorer [command] --help` + +### `node` Command + +It consists of subcommands that are associated with Rubix node. + +- `lock-rbt-tokens`: Lock RBT tokens +- `migrate`: Migrate Node +- `peer`: Peer related subcommands +- `release-rbt-tokens`: Release all locked RBT tokens +- `shutdown`: shut down the node +- `token-state-pinned-info`: Check if a Token state is pinned + +To know more about the flags, run `rubixgoplatform node [command] --help` + +**`node peer` Commands** + +It consists of subcommands associated with peer info of a node + +- `add`: Add Peer details +- `local-id`: Get the local IPFS peer id +- `ping`: pings a peer +- `quorum-status`: check the status of quorum + +To know more about the flags, run `rubixgoplatform node peer [command] --help` + +### `quorum` Command + +It consists of subcommands that are associated with Quorums. + +- `add`: Add addresses present with quorumlist.json in the node +- `list`: List all Quorums +- `remove-all`: Remove all Quorums +- `setup`: Setup up DID as a Quorum +- `list-token-states`: List all pledge token states of a node +- `unpledge`: Unpledge all pledged tokens + +To know more about the flags, run `rubixgoplatform quorum [command] --help` + +### `run` Command + +This command is used to run a Rubix node. To know more about the flags, run `rubixgoplatform run [command] --help` + +### `tx` Commands + +It consists of subcommands that are associated with transactions related to RBT tokens, Smart Contracts and NFT. + +**`tx rbt` Commands** + +It consists of subcommands associated with RBT tokens + +- `generate-test-tokens`: Generate Test RBT tokens +- `transfer`: Transfer RBT tokens +- `self-transfer`: Self transfer RBT tokens + +To know more about the flags, run `rubixgoplatform tx rbt [command] --help` + +**`tx smart-contract` Commands** + +It consists of subcommands associated with Smart Contracts + +- `deploy`: Deploy a Smart Contract +- `execute`: Execute a Smart Contract +- `fetch`: Fetch a Smart Contract Token +- `generate`: Generate a Smart Contract Token +- `publish`: Publish a Smart Contract Token +- `subscribe`: Subscribe to a Smart Contract + +To know more about the flags, run `rubixgoplatform tx smart-contract [command] --help` + +**`tx nft` Commands** + +It consists of subcommands associated with NFTs + +- `create`: Create an NFT +- `list`: List NFTs by DID + +To know more about the flags, run `rubixgoplatform tx nft [command] --help` + + **`tx data-token` Commands** + +It consists of subcommands associated with Data tokens + +- `commit`: Commit a Data Token +- `create`: Create a Data Token + +To know more about the flags, run `rubixgoplatform tx data-token [command] --help` + +### `pin-service` Command + +It consists of subcommands associated with Token pinning and recovery + +- `pin`: Pins a token on a pinning service provider node +- `recover`: Recovers the pinned token from the pinning service provider node + +To know more about the flags, run `rubixgoplatform pin-service [command] --help` + +### `upgrade` Command + +It consists of subcommands associated with operations related to node version migrations + +- `unpledge-pow-tokens`: Unpledge any pledge tokens which were pledged as part of PoW based pledging + +To know more about the flags, run `rubixgoplatform upgrade [command] --help` + +### `validate-chain` Command + +This command validates token chain and smart contract chain. + +To know more about the flags, run `rubixgoplatform validate-chain --help` + +### `version` Command + +This command will output the Rubix binary version. diff --git a/command/addingpeerdetails.go b/command/addingpeerdetails.go deleted file mode 100644 index 8b09802d..00000000 --- a/command/addingpeerdetails.go +++ /dev/null @@ -1,64 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" - - "github.com/rubixchain/rubixgoplatform/core/wallet" -) - -func (cmd *Command) AddPeerDetails() { - var peerID string - var did string - var err error - if cmd.peerID == "" { - fmt.Print("Enter PeerID : ") - _, err = fmt.Scan(&peerID) - if err != nil { - cmd.log.Error("Failed to get PeerID") - return - } - } else { - peerID = cmd.peerID - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.peerID) - if !strings.HasPrefix(cmd.peerID, "12D3KooW") || len(cmd.peerID) != 52 || !is_alphanumeric { - cmd.log.Error("Invalid PeerID") - return - } - - if cmd.did == "" { - fmt.Print("Enter DID : ") - _, err = fmt.Scan(&did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } else { - did = cmd.did - } - is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - - // did_type = cmd.didType - if cmd.didType < 0 || cmd.didType > 4 { - cmd.log.Error("DID Type should be between 0 and 4") - return - } - - peer_detail := wallet.DIDPeerMap{ - PeerID: peerID, - DID: did, - DIDType: &cmd.didType, - } - msg, status := cmd.c.AddPeer(&peer_detail) - if !status { - cmd.log.Error("Failed to add peer in DB", "message", msg) - return - } - cmd.log.Info("Peer added successfully") -} diff --git a/command/bootstrap.go b/command/bootstrap.go index cc2286c6..8ebf0fae 100644 --- a/command/bootstrap.go +++ b/command/bootstrap.go @@ -1,64 +1,196 @@ package command import ( + "errors" "fmt" "strings" + + "github.com/spf13/cobra" ) -func (cmd *Command) addBootStrap() { - if len(cmd.peers) == 0 { - cmd.log.Error("Peers required for bootstrap. Use flag -peers to provide peers separated by a ','") - return - } - for _, peer := range cmd.peers { - if !strings.HasSuffix(peer, "/") { - cmd.log.Error(fmt.Sprintf("Invalid bootstrap peer : %s", peer)) - return - } - } - msg, status := cmd.c.AddBootStrap(cmd.peers) +const peersFlag string = "peers" - if !status { - cmd.log.Error("Add bootstrap command failed, " + msg) - } else { - cmd.log.Info("Add bootstrap command finished, " + msg) +func bootstrapCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "bootstrap", + Short: "Bootstrap related subcommands", + Long: "Bootstrap related subcommands", + Args: cobra.NoArgs, } + + cmd.AddCommand( + addBootStrap(cmdCfg), + removeBootStrap(cmdCfg), + removeAllBootStrap(cmdCfg), + getAllBootStrap(cmdCfg), + ) + + return cmd } -func (cmd *Command) removeBootStrap() { - if len(cmd.peers) == 0 { - cmd.log.Error("Peers required for bootstrap. Use flag -peers to provide peers separated by a ','") - return + +func customBootStrap(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "custom", + Short: "Some feat of Bootstrap", + Long: "Some feat of Bootstrap", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + peers, err := cmd.Flags().GetStringArray(peersFlag) + if err != nil { + return err + } + + if len(peers) == 0 { + errMsg := errors.New("peers are required for bootstrap") + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + for _, peer := range peers { + if !strings.HasSuffix(peer, "/") { + errMsg := fmt.Errorf("invalid bootstrap peer : %v", peer) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + } + msg, status := cmdCfg.c.AddBootStrap(peers) + if !status { + cmdCfg.log.Error("Add bootstrap command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Add bootstrap command finished, " + msg) + return nil + } + }, } - for _, peer := range cmd.peers { - if !strings.HasSuffix(peer, "/") { - cmd.log.Error(fmt.Sprintf("Invalid bootstrap peer : %s", peer)) - return - } + + cmd.Flags().StringSlice(peersFlag, []string{}, "Bootstrap peers, mutiple peers will be seprated by comma") + + return cmd +} + +func addBootStrap(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add IPFS bootstrap peers", + Long: "Add IPFS bootstrap peers", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + peers, err := cmd.Flags().GetStringArray(peersFlag) + if err != nil { + return err + } + + if len(peers) == 0 { + errMsg := errors.New("peers are required for bootstrap") + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + for _, peer := range peers { + if !strings.HasSuffix(peer, "/") { + errMsg := fmt.Errorf("invalid bootstrap peer : %v", peer) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + } + msg, status := cmdCfg.c.AddBootStrap(peers) + if !status { + cmdCfg.log.Error("Add bootstrap command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Add bootstrap command finished, " + msg) + return nil + } + }, } - msg, status := cmd.c.RemoveBootStrap(cmd.peers) - if !status { - cmd.log.Error("Remove bootstrap command failed, " + msg) - } else { - cmd.log.Info("Remove bootstrap command finished, " + msg) + + cmd.Flags().StringSlice(peersFlag, []string{}, "Bootstrap peers, mutiple peers will be seprated by comma") + + return cmd +} + +func removeBootStrap(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove", + Short: "Remove bootstrap peer(s) from the configuration", + Long: "Remove bootstrap peer(s) from the configuration", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + peers, err := cmd.Flags().GetStringArray(peersFlag) + if err != nil { + return err + } + + for _, peer := range peers { + if !strings.HasSuffix(peer, "/") { + errMsg := fmt.Errorf("invalid bootstrap peer : %s", peer) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + } + + if len(peers) == 0 { + errMsg := fmt.Errorf("peers required for bootstrap") + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + + msg, status := cmdCfg.c.RemoveBootStrap(peers) + if !status { + cmdCfg.log.Error("Remove bootstrap command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Remove bootstrap command finished, " + msg) + return nil + } + }, } + + cmd.Flags().StringSlice(peersFlag, []string{}, "Bootstrap peers, mutiple peers will be seprated by comma") + + return cmd } -func (cmd *Command) removeAllBootStrap() { - msg, status := cmd.c.RemoveAllBootStrap() - if !status { - cmd.log.Error("Remove all bootstrap command failed, " + msg) - } else { - cmd.log.Info("Remove all bootstrap command finished, " + msg) +func removeAllBootStrap(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove-all", + Short: "Removes all bootstrap peers from the configuration", + Long: "Removes all bootstrap peers from the configuration", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + msg, status := cmdCfg.c.RemoveAllBootStrap() + if !status { + cmdCfg.log.Error("Remove all bootstrap command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Remove all bootstrap command finished, " + msg) + return nil + } + }, } + + return cmd } -func (cmd *Command) getAllBootStrap() { - peers, msg, status := cmd.c.GetAllBootStrap() - if !status { - cmd.log.Error("Get all bootstrap command failed, " + msg) - } else { - cmd.log.Info("Get all bootstrap command finished, " + msg) - cmd.log.Info("Bootstrap peers", "peers", peers) +func getAllBootStrap(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all bootstrap peers from the configuration", + Long: "List all bootstrap peers from the configuration", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + peers, msg, status := cmdCfg.c.GetAllBootStrap() + if !status { + errMsg := fmt.Errorf("unable to retrieve all bootstrap peers, %v", msg) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } else { + cmdCfg.log.Info("Get all bootstrap command finished, " + msg) + cmdCfg.log.Info("Bootstrap peers", "peers", peers) + return nil + } + }, } + + return cmd } diff --git a/command/chain_dump.go b/command/chain_dump.go new file mode 100644 index 00000000..a8a67177 --- /dev/null +++ b/command/chain_dump.go @@ -0,0 +1,358 @@ +package command + +import ( + "fmt" + "os" + "regexp" + "strings" + "io/ioutil" + "encoding/json" + + "github.com/rubixchain/rubixgoplatform/block" + "github.com/rubixchain/rubixgoplatform/util" + "github.com/spf13/cobra" +) + +func chainDumpCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "chain-dump", + Short: "Token-chain and SmartContract-Chain dump related subcommands ", + Long: "Token-chain and SmartContract-Chain dump related subcommands ", + } + + cmd.AddCommand( + tokenChainDumpCmd(cmdCfg), + smartContractChainDumpCmd(cmdCfg), + decodeTokenChain(cmdCfg), + ) + + return cmd +} + +func tokenChainDumpCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "token", + Short: "Get the dump of Token chain", + Long: "Get the dump of Token chain", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.token == "" { + cmdCfg.log.Info("token id cannot be empty") + fmt.Print("Enter Token Id : ") + _, err := fmt.Scan(&cmdCfg.token) + if err != nil { + cmdCfg.log.Error("Failed to get Token ID") + return nil + } + } + isAlphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.token) + + if len(cmdCfg.token) != 46 || !strings.HasPrefix(cmdCfg.token, "Qm") || !isAlphanumeric { + cmdCfg.log.Error("Invalid token") + return nil + } + + blocks := make([]map[string]interface{}, 0) + blockID := "" + for { + ds, err := cmdCfg.c.DumpTokenChain(cmdCfg.token, blockID) + if err != nil { + cmdCfg.log.Error("Failed to dump token chain", "err", err) + return nil + } + if !ds.Status { + cmdCfg.log.Error("Failed to dump token chain", "msg", ds.Message) + return nil + } + for _, blk := range ds.Blocks { + b := block.InitBlock(blk, nil) + if b != nil { + blocks = append(blocks, b.GetBlockMap()) + } else { + cmdCfg.log.Error("Invalid block") + } + } + blockID = ds.NextBlockID + if ds.NextBlockID == "" { + break + } + } + str, err := tcMarshal("", blocks) + if err != nil { + cmdCfg.log.Error("Failed to dump token chain", "err", err) + return nil + } + f, err := os.Create("dump.json") + if err != nil { + cmdCfg.log.Error("Failed to dump token chain", "err", err) + return nil + } + f.WriteString(str) + f.Close() + cmdCfg.log.Info("Token chain dumped successfully!") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.token, "tokenHash", "", "Token Hash") + + return cmd +} + +func smartContractChainDumpCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "smart-contract", + Short: "Get the dump of Smart Contract chain", + Long: "Get the dump of Smart Contract chain", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + + blocks := make([]map[string]interface{}, 0) + blockID := "" + for { + ds, err := cmdCfg.c.DumpSmartContractTokenChain(cmdCfg.smartContractToken, blockID) + if err != nil { + cmdCfg.log.Error("Failed to dump smart contract token chain", "err", err) + return nil + } + if !ds.Status { + cmdCfg.log.Error("Failed to dump smart contract token chain", "msg", ds.Message) + return nil + } + for _, blk := range ds.Blocks { + b := block.InitBlock(blk, nil) + if b != nil { + blocks = append(blocks, b.GetBlockMap()) + } else { + cmdCfg.log.Error("Invalid block") + } + } + blockID = ds.NextBlockID + if ds.NextBlockID == "" { + break + } + } + str, err := tcMarshal("", blocks) + if err != nil { + cmdCfg.log.Error("Failed to dump smart contract token chain", "err", err) + return nil + } + f, err := os.Create("dump.json") + if err != nil { + cmdCfg.log.Error("Failed to dump smart contract token chain", "err", err) + return nil + } + f.WriteString(str) + f.Close() + cmdCfg.log.Info("smart contract Token chain dumped successfully!") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + + return cmd +} + +// decodeTokenChain decodes a JSON file, transforms its data, and writes the transformed data back to a file. +func decodeTokenChain(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "decode-token-chain", + Short: "Decode Token chain", + Long: "Decond Token chain", + RunE: func(cmd *cobra.Command, args []string) error { + // Open the input JSON file + file, err := os.Open("dump.json") + if err != nil { + errMsg := fmt.Errorf("error opening file: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + defer file.Close() + + // Read the JSON file + byteValue, err := ioutil.ReadAll(file) + if err != nil { + errMsg := fmt.Errorf("error reading file: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + + // Parse the JSON data + var data []interface{} + err = json.Unmarshal(byteValue, &data) + if err != nil { + errMsg := fmt.Errorf("error parsing JSON: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + + // Transform the JSON data + for i, item := range data { + flattenedItem := flattenKeys("", item) + mappedItem := applyKeyMapping(flattenedItem) + data[i] = mappedItem + } + + // Convert the transformed data back to JSON + output, err := json.MarshalIndent(data, "", " ") + if err != nil { + errMsg := fmt.Errorf("error marshaling JSON: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + + // Write the output to a file + err = ioutil.WriteFile("output.json", output, 0644) + if err != nil { + errMsg := fmt.Errorf("error writing file: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + + cmdCfg.log.Info("Transformation complete. Check output.json for results.") + return nil + }, + } + + return cmd + + +} + +func tcMarshal(str string, m interface{}) (string, error) { + var err error + switch mt := m.(type) { + case []map[string]interface{}: + str = str + "[" + c1 := false + for i := range mt { + if c1 { + str = str + "," + } + c1 = true + str, err = tcMarshal(str, mt[i]) + if err != nil { + return "", err + } + } + str = str + "]" + case map[string]interface{}: + str = str + "{" + c1 := false + for k, v := range mt { + if c1 { + str = str + "," + } + c1 = true + str = str + "\"" + k + "\":" + s, ok := v.(string) + if ok { + str = str + "\"" + s + "\"" + } else { + str, err = tcMarshal(str, v) + if err != nil { + return "", err + } + } + } + str = str + "}" + case map[string]string: + str = str + "{" + c1 := false + for k, v := range mt { + if c1 { + str = str + "," + } + c1 = true + str = str + "\"" + k + "\":" + str = str + "\"" + v + "\"" + } + + str = str + "}" + case map[interface{}]interface{}: + str = str + "{" + c1 := false + for k, v := range mt { + if c1 { + str = str + "," + } + c1 = true + str = str + "\"" + k.(string) + "\":" + str, err = tcMarshal(str, v) + if err != nil { + return "", err + } + } + + str = str + "}" + case []string: + str = str + "[" + c1 := false + for _, mf := range mt { + if c1 { + str = str + "," + } + c1 = true + str, err = tcMarshal(str, mf) + if err != nil { + return "", err + } + } + str = str + "]" + case []byte: + str = str + "\"" + util.HexToStr(mt) + "\"" + case string: + str = str + "\"" + mt + "\"" + case []interface{}: + str = str + "[" + c1 := false + for _, mf := range mt { + if c1 { + str = str + "," + } + c1 = true + s, ok := mf.(string) + if ok { + str = str + "\"" + s + "\"" + } else { + str, err = tcMarshal(str, mf) + if err != nil { + return "", err + } + } + } + str = str + "]" + case uint64: + str = str + fmt.Sprintf("%d", mt) + case int: + str = str + fmt.Sprintf("%d", mt) + case float64: + // TokenValue (key: "10") is a float value and needs to have a precision of 5 + // in the output dump file + str = str + fmt.Sprintf("%.5f", mt) + case interface{}: + str, err = tcMarshal(str, mt) + if err != nil { + return "", err + } + case nil: + str = str + "\"" + "\"" + default: + return "", fmt.Errorf("invalid type %T", mt) + } + return str, nil +} \ No newline at end of file diff --git a/command/command.go b/command/command.go index e46e9b6b..8909cbf4 100644 --- a/command/command.go +++ b/command/command.go @@ -1,14 +1,12 @@ package command import ( - "flag" "fmt" "io" "net" - "net/http" "os" "os/signal" - "runtime" + "path" "strings" "syscall" "time" @@ -17,281 +15,97 @@ import ( "github.com/rubixchain/rubixgoplatform/contract" "github.com/rubixchain/rubixgoplatform/core" "github.com/rubixchain/rubixgoplatform/core/config" - "github.com/rubixchain/rubixgoplatform/core/storage" - "github.com/rubixchain/rubixgoplatform/did" - _ "github.com/rubixchain/rubixgoplatform/docs" "github.com/rubixchain/rubixgoplatform/server" "github.com/rubixchain/rubixgoplatform/wrapper/apiconfig" srvcfg "github.com/rubixchain/rubixgoplatform/wrapper/config" - "github.com/rubixchain/rubixgoplatform/wrapper/ensweb" "github.com/rubixchain/rubixgoplatform/wrapper/logger" + "github.com/spf13/cobra" "golang.org/x/term" ) -const ( - ConfigFile string = "api_config.json" -) - -const ( - version string = "0.0.17" -) -const ( - VersionCmd string = "-v" - HelpCmd string = "-h" - RunCmd string = "run" - PingCmd string = "ping" - AddBootStrapCmd string = "addbootstrap" - RemoveBootStrapCmd string = "removebootstrap" - RemoveAllBootStrapCmd string = "removeallbootstrap" - GetAllBootStrapCmd string = "getallbootstrap" - CreateDIDCmd string = "createdid" - GetAllDIDCmd string = "getalldid" - AddQuorumCmd string = "addquorum" - GetAllQuorumCmd string = "getallquorum" - RemoveAllQuorumCmd string = "removeallquorum" - SetupQuorumCmd string = "setupquorum" - GenerateTestRBTCmd string = "generatetestrbt" - TransferRBTCmd string = "transferrbt" - GetAccountInfoCmd string = "getaccountinfo" - SetupServiceCmd string = "setupservice" - DumpTokenChainCmd string = "dumptokenchain" - RegsiterDIDCmd string = "registerdid" - SetupDIDCmd string = "setupdid" - ShutDownCmd string = "shutdown" - MirgateNodeCmd string = "migratenode" - LockTokensCmd string = "locktokens" - CreateDataTokenCmd string = "createdatatoken" - CommitDataTokenCmd string = "commitdatatoken" - SetupDBCmd string = "setupdb" - GetTxnDetailsCmd string = "gettxndetails" - CreateNFTCmd string = "createnft" - GetAllNFTCmd string = "getallnft" - UpdateConfig string = "updateconfig" - GenerateSmartContractToken string = "generatesct" - FetchSmartContract string = "fetchsct" - PublishContractCmd string = "publishsct" - SubscribeContractCmd string = "subscribesct" - DeploySmartContractCmd string = "deploysmartcontract" - ExecuteSmartcontractCmd string = "executesmartcontract" - DumpSmartContractTokenChainCmd string = "dumpsmartcontracttokenchain" - GetTokenBlock string = "gettokenblock" - GetSmartContractData string = "getsmartcontractdata" - GetPeerID string = "get-peer-id" - ReleaseAllLockedTokensCmd string = "releaseAllLockedTokens" - CheckQuorumStatusCmd string = "checkQuorumStatus" - AddExplorerCmd string = "addexplorer" - RemoveExplorerCmd string = "removeexplorer" - GetAllExplorerCmd string = "getallexplorer" - AddPeerDetailsCmd string = "addpeerdetails" - GetPledgedTokenDetailsCmd string = "getpledgedtokendetails" - CheckPinnedState string = "checkpinnedstate" - SelfTransferRBT string = "self-transfer-rbt" - RunUnpledge string = "run-unpledge" - UnpledgePOWPledgeTokens string = "unpledge-pow-pledge-tokens" - PinTokenCmd string = "pinToken" - RecoverTokensCmd string = "recoverToken" -) - -var commands = []string{VersionCmd, - HelpCmd, - RunCmd, - PingCmd, - AddBootStrapCmd, - RemoveBootStrapCmd, - RemoveAllBootStrapCmd, - GetAllBootStrapCmd, - CreateDIDCmd, - GetAllDIDCmd, - AddQuorumCmd, - GetAllQuorumCmd, - RemoveAllQuorumCmd, - SetupQuorumCmd, - GenerateTestRBTCmd, - TransferRBTCmd, - GetAccountInfoCmd, - SetupServiceCmd, - DumpTokenChainCmd, - RegsiterDIDCmd, - SetupDBCmd, - ShutDownCmd, - MirgateNodeCmd, - LockTokensCmd, - CreateDataTokenCmd, - CommitDataTokenCmd, - SetupDBCmd, - GetTxnDetailsCmd, - PublishContractCmd, - SubscribeContractCmd, - CreateNFTCmd, - GetAllNFTCmd, - DeploySmartContractCmd, - ExecuteSmartcontractCmd, - ShutDownCmd, - GenerateSmartContractToken, - FetchSmartContract, - PublishContractCmd, - SubscribeContractCmd, - DumpSmartContractTokenChainCmd, - GetTokenBlock, - GetSmartContractData, - GetPeerID, - AddPeerDetailsCmd, - SelfTransferRBT, - RunUnpledge, - UnpledgePOWPledgeTokens, - PinTokenCmd, - RecoverTokensCmd, -} - -var commandsHelp = []string{"To get tool version", - "To get help", - "To run the rubix core", - "This command will be used to ping the peer", - "This command will add bootstrap peers to the configuration", - "This command will remove bootstrap peers from the configuration", - "This command will remove all bootstrap peers from the configuration", - "This command will get all bootstrap peers from the configuration", - "This command will create DID", - "This command will get all DID address", - "This command will add quorurm list to node", - "This command will get all quorurm list from node", - "This command will delete all quorurm list from node", - "This command will setup node as quorurm", - "This command will generate test RBT token", - "This command will trasnfer RBT", - "This command will help to get account information", - "This command enable explorer service on the node", - "This command will dump the token chain into file", - "This command will register DID peer map across the network", - "This command will setup the DID with peer", - "This command will shutdown the rubix node", - "This command will migrate node to newer node", - "This command will lock the tokens on the arbitary node", - "This command will create data token token", - "This command will commit data token token", - "This command will setup the DB", - "This command will get transaction details", - "This command will publish a smart contract token", - "This command will subscribe to a smart contract token", - "This command will create NFT", - "This command will get all NFTs", - "This command will deploy the smart contract token", - "This command will execute the fetched smart contract", - "This command will shutdown the rubix node", - "This command will generate a smart contract token", - "This command will fetch a smart contract token", - "This command will publish a smart contract token", - "This command will subscribe to a smart contract token", - "This command will dump the smartcontract token chain", - "This command gets token block", - "This command gets the smartcontract data from latest block", - "This command will fetch the peer ID of the node", - "This command is to add the peer details manually", - "This command will initiate a self RBT transfer", - "This command will unpledge all the pledged tokens", - "This command will unpledge all PoW based pledge tokens and drop the unpledgequeue table", -} - -type Command struct { - cfg config.Config - c *client.Client - sc *contract.Contract - encKey string - start bool - node uint - runDir string - logFile string - logLevel string - cfgFile string - testNet bool - testNetKey string - addr string - port string - peerID string - peers []string - log logger.Logger - didRoot bool - didType int - didSecret string - forcePWD bool - privPWD string - quorumPWD string - imgFile string - didImgFile string - privImgFile string - pubImgFile string - privKeyFile string - pubKeyFile string - quorumList string - srvName string - storageType int - dbName string - dbType string - dbAddress string - dbPort string - dbUserName string - dbPassword string - senderAddr string - receiverAddr string - rbtAmount float64 - transComment string - transType int - numTokens int - enableAuth bool - did string - token string - arbitaryMode bool - tokenList string - batchID string - fileMode bool - file string - userID string - userInfo string - timeout time.Duration - txnID string - role string - date time.Time - grpcAddr string - grpcPort int - grpcSecure bool - deployerAddr string - binaryCodePath string - rawCodePath string - schemaFilePath string - smartContractToken string - newContractBlock string - publishType int - smartContractData string - executorAddr string - latest bool - quorumAddr string - links []string - mnemonicFile string - ChildPath int - TokenState string - pinningAddress string -} - -func showVersion() { - fmt.Printf("\n****************************************\n\n") - fmt.Printf("Rubix Core Version : %s\n", version) - fmt.Printf("\n****************************************\n\n") -} - -func showHelp() { - if runtime.GOOS == "windows" { - fmt.Printf("\nrubixgpplatform.exe \n") - } else { - fmt.Printf("\nrubixgoplatform \n") - } - fmt.Printf("\nUse the following commands\n\n") - for i := range commands { - fmt.Printf(" %20s : %s\n\n", commands[i], commandsHelp[i]) - } +type CommandConfig struct { + cfg config.Config + c *client.Client + sc *contract.Contract + encKey string + start bool + node uint + runDir string + logFile string + logLevel string + cfgFile string + testNet bool + testNetKey string + addr string + port string + peerID string + peers []string + log logger.Logger + didRoot bool + didType int + didSecret string + forcePWD bool + privPWD string + quorumPWD string + imgFile string + didImgFile string + privImgFile string + pubImgFile string + privKeyFile string + pubKeyFile string + quorumList string + srvName string + storageType int + dbName string + dbType string + dbAddress string + dbPort string + dbUserName string + dbPassword string + senderAddr string + receiverAddr string + rbtAmount float64 + transComment string + transType int + numTokens int + enableAuth bool + did string + token string + arbitaryMode bool + tokenList string + batchID string + fileMode bool + file string + userID string + userInfo string + timeout time.Duration + txnID string + role string + date time.Time + grpcAddr string + grpcPort int + grpcSecure bool + deployerAddr string + binaryCodePath string + rawCodePath string + schemaFilePath string + smartContractToken string + newContractBlock string + publishType int + smartContractData string + executorAddr string + latest bool + quorumAddr string + links []string + mnemonicFile string + ChildPath int + TokenState string + pinningAddress string + blockCount int + smartContractChainValidation bool } -// Get preferred outbound ip of this machine -func (cmd *Command) getURL(url string) string { +func (cmd *CommandConfig) getURL(url string) string { // No IP address present if strings.Contains(url, "://:") { conn, err := net.Dial("udp", "8.8.8.8:80") @@ -308,64 +122,7 @@ func (cmd *Command) getURL(url string) string { return url } -func (cmd *Command) runApp() { - core.InitConfig(cmd.runDir+cmd.cfgFile, cmd.encKey, uint16(cmd.node)) - err := apiconfig.LoadAPIConfig(cmd.runDir+cmd.cfgFile, cmd.encKey, &cmd.cfg) - - if err != nil { - cmd.log.Error("Configfile is either currupted or cipher is wrong", "err", err) - return - } - - // Override directory path - cmd.cfg.DirPath = cmd.runDir - sc := make(chan bool, 1) - c, err := core.NewCore(&cmd.cfg, cmd.runDir+cmd.cfgFile, cmd.encKey, cmd.log, cmd.testNet, cmd.testNetKey, cmd.arbitaryMode) - if err != nil { - cmd.log.Error("failed to create core") - return - } - addr := fmt.Sprintf(cmd.grpcAddr+":%d", cmd.grpcPort) - scfg := &server.Config{ - Config: srvcfg.Config{ - HostAddress: cmd.cfg.NodeAddress, - HostPort: cmd.cfg.NodePort, - Production: "false", - }, - GRPCAddr: addr, - GRPCSecure: cmd.grpcSecure, - } - scfg.EnableAuth = cmd.enableAuth - if cmd.enableAuth { - scfg.DBType = "Sqlite3" - scfg.DBAddress = cmd.cfg.DirPath + "rubix.db" - } - // scfg := &srvcfg.Config{ - // HostAddress: cmd.cfg.NodeAddress, - // HostPort: cmd.cfg.NodePort, - // } - s, err := server.NewServer(c, scfg, cmd.log, cmd.start, sc, cmd.timeout) - if err != nil { - cmd.log.Error("Failed to create server") - return - } - s.EnableSWagger(cmd.getURL(s.GetServerURL())) - cmd.log.Info("Core version : " + version) - cmd.log.Info("Starting server...") - go s.Start() - - ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGTERM) - signal.Notify(ch, syscall.SIGINT) - select { - case <-ch: - case <-sc: - } - s.Shutdown() - cmd.log.Info("Shutting down...") -} - -func (cmd *Command) validateOptions() bool { +func (cmd *CommandConfig) validateOptions() error { if cmd.runDir == "" { cmd.runDir = "./" } @@ -375,314 +132,227 @@ func (cmd *Command) validateOptions() bool { } } _, err := os.Stat(cmd.runDir) - if err == nil { - return true - } if os.IsNotExist(err) { err := os.MkdirAll(cmd.runDir, os.ModeDir|os.ModePerm) - if err == nil || os.IsExist(err) { - return true - } else { - return false + if err != nil || os.IsExist(err) { + return err } + } else { + return err } - return false + + return nil } -func Run(args []string) { - - cmd := &Command{} - var peers string - var timeout int - var links string - - flag.StringVar(&cmd.runDir, "p", "./", "Working directory path") - flag.StringVar(&cmd.logFile, "logFile", "", "Log file name") - flag.StringVar(&cmd.logLevel, "logLevel", "debug", "Log level") - flag.StringVar(&cmd.cfgFile, "c", ConfigFile, "Configuration file for the core") - flag.UintVar(&cmd.node, "n", 0, "Node number") - flag.StringVar(&cmd.encKey, "k", "TestKeyBasic#2022", "Config file encryption key") - flag.BoolVar(&cmd.start, "s", false, "Start the core") - flag.BoolVar(&cmd.testNet, "testNet", false, "Run as test net") - flag.StringVar(&cmd.testNetKey, "testNetKey", "testswarm.key", "Test net key") - flag.StringVar(&cmd.addr, "addr", "localhost", "Server/Host Address") - flag.StringVar(&cmd.port, "port", "20000", "Server/Host port") - flag.StringVar(&cmd.peerID, "peerID", "", "Peerd ID") - flag.StringVar(&peers, "peers", "", "Bootstrap peers, mutiple peers will be seprated by comma") - flag.BoolVar(&cmd.didRoot, "didRoot", false, "Root DID") - flag.IntVar(&cmd.didType, "didType", 0, "DID Creation type") - flag.IntVar(&cmd.ChildPath, "ChildPath", 0, "BIP child Path") - flag.StringVar(&cmd.didSecret, "didSecret", "My DID Secret", "DID creation secret") - flag.BoolVar(&cmd.forcePWD, "fp", false, "Force password entry") - flag.StringVar(&cmd.privPWD, "privPWD", "mypassword", "Private key password") - flag.StringVar(&cmd.quorumPWD, "quorumPWD", "mypassword", "Quorum key password") - flag.StringVar(&cmd.imgFile, "imgFile", did.ImgFileName, "DID creation image") - flag.StringVar(&cmd.didImgFile, "didImgFile", did.DIDImgFileName, "DID image") - flag.StringVar(&cmd.privImgFile, "privImgFile", did.PvtShareFileName, "DID public share image") - flag.StringVar(&cmd.pubImgFile, "pubImgFile", did.PubShareFileName, "DID public share image") - flag.StringVar(&cmd.mnemonicFile, "mnemonicKeyFile", did.MnemonicFileName, "Mnemonic key file") - flag.StringVar(&cmd.privKeyFile, "privKeyFile", did.PvtKeyFileName, "Private key file") - flag.StringVar(&cmd.pubKeyFile, "pubKeyFile", did.PubKeyFileName, "Public key file") - flag.StringVar(&cmd.quorumList, "quorumList", "quorumlist.json", "Quorum list") - flag.StringVar(&cmd.srvName, "srvName", "explorer_service", "Service name") - flag.IntVar(&cmd.storageType, "storageType", storage.StorageDBType, "Storage type") - flag.StringVar(&cmd.dbName, "dbName", "ServiceDB", "Service database name") - flag.StringVar(&cmd.dbType, "dbType", "SQLServer", "DB Type, supported database are SQLServer, PostgressSQL, MySQL & Sqlite3") - flag.StringVar(&cmd.dbAddress, "dbAddress", "localhost", "Database address") - flag.StringVar(&cmd.dbPort, "dbPort", "1433", "Database port number") - flag.StringVar(&cmd.dbUserName, "dbUsername", "sa", "Database username") - flag.StringVar(&cmd.dbPassword, "dbPassword", "password", "Database password") - flag.StringVar(&cmd.senderAddr, "senderAddr", "", "Sender address") - flag.StringVar(&cmd.receiverAddr, "receiverAddr", "", "Receiver address") - flag.Float64Var(&cmd.rbtAmount, "rbtAmount", 0.0, "RBT amount") - flag.StringVar(&cmd.transComment, "transComment", "", "Transaction comment") - flag.IntVar(&cmd.transType, "transType", 2, "Transaction type") - flag.IntVar(&cmd.numTokens, "numTokens", 1, "Number of tokens") - flag.StringVar(&cmd.did, "did", "", "DID") - flag.BoolVar(&cmd.enableAuth, "enableAuth", false, "Enable authentication") - flag.BoolVar(&cmd.arbitaryMode, "arbitaryMode", false, "Enable arbitary mode") - flag.StringVar(&cmd.tokenList, "tokenList", "tokens.txt", "Token lis") - flag.StringVar(&cmd.token, "token", "", "Token name") - flag.StringVar(&cmd.batchID, "bid", "batchID1", "Batch ID") - flag.BoolVar(&cmd.fileMode, "fmode", false, "File mode") - flag.StringVar(&cmd.file, "file", "file.txt", "File to be uploaded") - flag.StringVar(&cmd.userID, "uid", "testuser", "User ID for token creation") - flag.StringVar(&cmd.userInfo, "uinfo", "", "User info for token creation") - flag.IntVar(&timeout, "timeout", 0, "Timeout for the server") - flag.StringVar(&cmd.txnID, "txnID", "", "Transaction ID") - flag.StringVar(&cmd.role, "role", "", "Sender/Receiver") - flag.StringVar(&cmd.grpcAddr, "grpcAddr", "localhost", "GRPC server address") - flag.IntVar(&cmd.grpcPort, "grpcPort", 10500, "GRPC server port") - flag.BoolVar(&cmd.grpcSecure, "grpcSecure", false, "GRPC enable security") - flag.StringVar(&cmd.deployerAddr, "deployerAddr", "", "Smart contract Deployer Address") - flag.StringVar(&cmd.binaryCodePath, "binCode", "", "Binary code path") - flag.StringVar(&cmd.rawCodePath, "rawCode", "", "Raw code path") - flag.StringVar(&cmd.schemaFilePath, "schemaFile", "", "Schema file path") - flag.StringVar(&cmd.smartContractToken, "sct", "", "Smart contract token") - flag.StringVar(&cmd.newContractBlock, "sctBlockHash", "", "Contract block hash") - flag.IntVar(&cmd.publishType, "pubType", 0, "Smart contract event publishing type(Deploy & Execute)") - flag.StringVar(&cmd.smartContractData, "sctData", "data", "Smart contract execution info") - flag.StringVar(&cmd.executorAddr, "executorAddr", "", "Smart contract Executor Address") - flag.BoolVar(&cmd.latest, "latest", false, "flag to set latest") - flag.StringVar(&cmd.quorumAddr, "quorumAddr", "", "Quorum Node Address to check the status of the Quorum") - flag.StringVar(&links, "links", "", "Explorer url") - flag.StringVar(&cmd.TokenState, "tokenstatehash", "", "Give Token State Hash to check state") - flag.StringVar(&cmd.pinningAddress, "pinningAddress", "", "Pinning address") - - if len(os.Args) < 2 { - fmt.Println("Invalid Command") - showHelp() - return +func getpassword(msg string) (string, error) { + fmt.Print(msg) + bytePassword, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return "", err } + return string(bytePassword), nil +} - cmdName := os.Args[1] +var ( + commandCfg *CommandConfig = &CommandConfig{} + peers string + timeout int - os.Args = os.Args[1:] + ConfigFile string = "api_config.json" +) - flag.Parse() +var rootCmd = &cobra.Command{ + Use: "rubixgoplatform", + Short: "Rubix Blockchain Platform CLI", + Long: `Rubix Blockchain Platform CLI`, + SuggestionsMinimumDistance: 2, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if peers != "" { + peers = strings.ReplaceAll(peers, " ", "") + commandCfg.peers = strings.Split(peers, ",") + } - if peers != "" { - peers = strings.ReplaceAll(peers, " ", "") - cmd.peers = strings.Split(peers, ",") - } + commandCfg.timeout = time.Duration(timeout) * time.Minute - if links != "" { - links = strings.ReplaceAll(links, " ", "") - cmd.links = strings.Split(links, ",") - } + if err := commandCfg.validateOptions(); err != nil { + fmt.Printf("Validate options failed, error: %v\n", err) + os.Exit(1) + } - cmd.timeout = time.Duration(timeout) * time.Minute + if commandCfg.logFile == "" { + commandCfg.logFile = commandCfg.runDir + "log.txt" + } - if !cmd.validateOptions() { - fmt.Println("Validate options failed") - return - } + level := logger.Debug - if cmd.logFile == "" { - cmd.logFile = cmd.runDir + "log.txt" - } + fp, err := os.OpenFile(commandCfg.logFile, + os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } - level := logger.Debug + switch strings.ToLower(commandCfg.logLevel) { + case "error": + level = logger.Error + case "info": + level = logger.Info + case "debug": + level = logger.Debug + default: + level = logger.Debug + } - fp, err := os.OpenFile(cmd.logFile, - os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - panic(err) - } + logOptions := &logger.LoggerOptions{ + Name: "Main", + Level: level, + Color: []logger.ColorOption{logger.AutoColor, logger.ColorOff}, + Output: []io.Writer{logger.DefaultOutput, fp}, + } - switch strings.ToLower(cmd.logLevel) { - case "error": - level = logger.Error - case "info": - level = logger.Info - case "debug": - level = logger.Debug - default: - level = logger.Debug - } + commandCfg.log = logger.New(logOptions) - logOptions := &logger.LoggerOptions{ - Name: "Main", - Level: level, - Color: []logger.ColorOption{logger.AutoColor, logger.ColorOff}, - Output: []io.Writer{logger.DefaultOutput, fp}, - } + // Get addr and port + commandCfg.addr, err = cmd.Root().PersistentFlags().GetString("addr") + if err != nil { + return err + } + commandCfg.port, err = cmd.Root().PersistentFlags().GetString("port") + if err != nil { + return err + } - cmd.log = logger.New(logOptions) + commandCfg.c, err = client.NewClient(&srvcfg.Config{ServerAddress: commandCfg.addr, ServerPort: commandCfg.port}, commandCfg.log, commandCfg.timeout) + if err != nil { + commandCfg.log.Error("Failed to create client") + return err + } - cmd.c, err = client.NewClient(&srvcfg.Config{ServerAddress: cmd.addr, ServerPort: cmd.port}, cmd.log, cmd.timeout) - if err != nil { - cmd.log.Error("Failed to create client") - return - } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + cmd.Help() + } - switch cmdName { - case VersionCmd: - showVersion() - case HelpCmd: - showHelp() - case RunCmd: - cmd.runApp() - case PingCmd: - cmd.ping() - case AddBootStrapCmd: - cmd.addBootStrap() - case RemoveBootStrapCmd: - cmd.removeBootStrap() - case RemoveAllBootStrapCmd: - cmd.removeAllBootStrap() - case GetAllBootStrapCmd: - cmd.getAllBootStrap() - case CreateDIDCmd: - cmd.CreateDID() - case GetAllDIDCmd: - cmd.GetAllDID() - case AddQuorumCmd: - cmd.AddQuorurm() - case GetAllQuorumCmd: - cmd.GetAllQuorum() - case RemoveAllQuorumCmd: - cmd.RemoveAllQuorum() - case SetupQuorumCmd: - cmd.SetupQuorum() - case SetupServiceCmd: - cmd.SetupService() - case GenerateTestRBTCmd: - cmd.GenerateTestRBT() - case TransferRBTCmd: - cmd.TransferRBT() - case GetAccountInfoCmd: - cmd.GetAccountInfo() - case DumpTokenChainCmd: - cmd.dumpTokenChain() - case RegsiterDIDCmd: - cmd.RegsiterDIDCmd() - case SetupDIDCmd: - cmd.SetupDIDCmd() - case ShutDownCmd: - cmd.ShutDownCmd() - case MirgateNodeCmd: - cmd.MigrateNodeCmd() - case CreateDataTokenCmd: - cmd.createDataToken() - case CommitDataTokenCmd: - cmd.commitDataToken() - case SetupDBCmd: - cmd.setupDB() - case GetTxnDetailsCmd: - cmd.getTxnDetails() - case PublishContractCmd: - cmd.PublishContract() - case SubscribeContractCmd: - cmd.SubscribeContract() - case CreateNFTCmd: - cmd.createNFT() - case GetAllNFTCmd: - cmd.getAllNFTs() - case DeploySmartContractCmd: - cmd.deploySmartcontract() - case GenerateSmartContractToken: - cmd.generateSmartContractToken() - case FetchSmartContract: - cmd.fetchSmartContract() - case DumpSmartContractTokenChainCmd: - cmd.dumpSmartContractTokenChain() - case GetTokenBlock: - cmd.getTokenBlock() - case GetSmartContractData: - cmd.getSmartContractData() - case ExecuteSmartcontractCmd: - cmd.executeSmartcontract() - case GetPeerID: - cmd.peerIDCmd() - case ReleaseAllLockedTokensCmd: - cmd.releaseAllLockedTokens() - case CheckQuorumStatusCmd: - cmd.checkQuorumStatus() - case AddExplorerCmd: - cmd.addExplorer() - case RemoveExplorerCmd: - cmd.removeExplorer() - case GetAllExplorerCmd: - cmd.getAllExplorer() - case AddPeerDetailsCmd: - cmd.AddPeerDetails() - case GetPledgedTokenDetailsCmd: - cmd.GetPledgedTokenDetails() - case CheckPinnedState: - cmd.CheckPinnedState() - case SelfTransferRBT: - cmd.SelfTransferRBT() - case RunUnpledge: - cmd.RunUnpledge() - case UnpledgePOWPledgeTokens: - cmd.UnpledgePOWBasedPledgedTokens() - case PinTokenCmd: - cmd.PinRBT() - case RecoverTokensCmd: - cmd.RecoverTokens() - default: - cmd.log.Error("Invalid command") - } + return nil + }, } -func (cmd *Command) basicClient(method string, path string, model interface{}) (ensweb.Client, *http.Request, error) { - cfg := srvcfg.Config{ - ServerAddress: cmd.addr, - ServerPort: cmd.port, - } - c, err := ensweb.NewClient(&cfg, cmd.log) - if err != nil { - return c, nil, fmt.Errorf("failed to get new client, " + err.Error()) +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) } - r, err := c.JSONRequest(method, path, model) - if err != nil { - return c, nil, fmt.Errorf("failed to create http request, " + err.Error()) - } - return c, r, nil } -func (cmd *Command) multiformClient(method string, path string, field map[string]string, files map[string]string) (ensweb.Client, *http.Request, error) { - cfg := srvcfg.Config{ - ServerAddress: cmd.addr, - ServerPort: cmd.port, - } - c, err := ensweb.NewClient(&cfg, cmd.log) - if err != nil { - return c, nil, fmt.Errorf("failed to get new client, " + err.Error()) - } - r, err := c.MultiFormRequest(method, path, field, files) - if err != nil { - return c, nil, fmt.Errorf("failed to create http request, " + err.Error()) - } - return c, r, nil +func init() { + // Global Flags + rootCmd.PersistentFlags().StringVar(&commandCfg.addr, "addr", "localhost", "Node address") + rootCmd.PersistentFlags().StringVar(&commandCfg.port, "port", "20000", "Node port") + + // Removes the default `completion` command + rootCmd.CompletionOptions.DisableDefaultCmd = true + + rootCmd.AddCommand( + runApplication(commandCfg), + didCommandGroup(commandCfg), + bootstrapCommandGroup(commandCfg), + configCommandGroup(commandCfg), + nodeGroup(commandCfg), + explorerCommandGroup(commandCfg), + quorumCommandGroup(commandCfg), + txCommandGroup(commandCfg), + chainDumpCommandGroup(commandCfg), + upgradeGroup(commandCfg), + pinningServiceCommandGroup(commandCfg), + validateCommand(commandCfg), + versionCmd(), + ) + + // Disables the default help command. Not to be confused with the help flag (`--help` or `-h`) + rootCmd.SetHelpCommand(&cobra.Command{Hidden: true}) } -func getpassword(msg string) (string, error) { - fmt.Print(msg) - bytePassword, err := term.ReadPassword(int(syscall.Stdin)) - if err != nil { - return "", err +func runApplication(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "run", + Short: "Run Rubix Core", + Long: "Run Rubix Core", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + if err := os.MkdirAll(cmdCfg.runDir, os.ModePerm); err != nil { + fmt.Println("Error creating directories:", err) + return err + } + + core.InitConfig(path.Join(cmdCfg.runDir, cmdCfg.cfgFile), cmdCfg.encKey, uint16(cmdCfg.node)) + err := apiconfig.LoadAPIConfig(path.Join(cmdCfg.runDir, cmdCfg.cfgFile), cmdCfg.encKey, &cmdCfg.cfg) + if err != nil { + cmdCfg.log.Error("Configfile is either currupted or cipher is wrong", "err", err) + return err + } + + // Override directory path + cmdCfg.cfg.DirPath = cmdCfg.runDir + sc := make(chan bool, 1) + c, err := core.NewCore(&cmdCfg.cfg, path.Join(cmdCfg.runDir, cmdCfg.cfgFile), cmdCfg.encKey, cmdCfg.log, cmdCfg.testNet, cmdCfg.testNetKey, cmdCfg.arbitaryMode) + if err != nil { + cmdCfg.log.Error("failed to create core") + return err + } + + addr := fmt.Sprintf(cmdCfg.grpcAddr+":%d", cmdCfg.grpcPort) + scfg := &server.Config{ + Config: srvcfg.Config{ + HostAddress: cmdCfg.cfg.NodeAddress, + HostPort: cmdCfg.cfg.NodePort, + Production: "false", + }, + GRPCAddr: addr, + GRPCSecure: cmdCfg.grpcSecure, + } + scfg.EnableAuth = cmdCfg.enableAuth + if cmdCfg.enableAuth { + scfg.DBType = "Sqlite3" + scfg.DBAddress = path.Join(cmdCfg.cfg.DirPath, "rubix.db") + } + // scfg := &srvcfg.Config{ + // HostAddress: cmd.cfg.NodeAddress, + // HostPort: cmd.cfg.NodePort, + // } + s, err := server.NewServer(c, scfg, cmdCfg.log, cmdCfg.start, sc, cmdCfg.timeout) + if err != nil { + cmdCfg.log.Error("Failed to create server") + return err + } + s.EnableSWagger(cmdCfg.getURL(s.GetServerURL())) + cmdCfg.log.Info("Core version : " + version) + cmdCfg.log.Info("Starting server...") + go s.Start() + + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGTERM) + signal.Notify(ch, syscall.SIGINT) + select { + case <-ch: + case <-sc: + } + s.Shutdown() + cmdCfg.log.Info("Shutting down...") + return nil + }, } - return string(bytePassword), nil + + cmd.Flags().StringVar(&cmdCfg.runDir, "p", "./", "working directory path") + cmd.Flags().UintVar(&cmdCfg.node, "n", 0, "node number") + cmd.Flags().BoolVar(&cmdCfg.start, "s", false, "Start the core") + cmd.Flags().BoolVar(&cmdCfg.testNet, "testNet", false, "Run as test net") + cmd.Flags().StringVar(&cmdCfg.testNetKey, "testNetKey", "testswarm.key", "Test net key") + cmd.Flags().StringVar(&cmdCfg.cfgFile, "c", ConfigFile, "Configuration file for the core") + cmd.Flags().StringVar(&cmdCfg.encKey, "k", "TestKeyBasic#2022", "Config file encryption key") + cmd.Flags().BoolVar(&cmdCfg.arbitaryMode, "arbitaryMode", false, "Enable arbitary mode") + cmd.Flags().IntVar(&cmdCfg.grpcPort, "grpcPort", 10500, "GRPC server port") + cmd.Flags().BoolVar(&cmdCfg.grpcSecure, "grpcSecure", false, "GRPC enable security") + + return cmd } diff --git a/command/config.go b/command/config.go index 6825aba1..5c5d0d0a 100644 --- a/command/config.go +++ b/command/config.go @@ -1,21 +1,98 @@ package command -import "github.com/rubixchain/rubixgoplatform/core/config" - -func (cmd *Command) setupDB() { - sc := &config.StorageConfig{ - StorageType: cmd.storageType, - DBName: cmd.dbName, - DBAddress: cmd.dbAddress, - DBUserName: cmd.dbUserName, - DBPassword: cmd.dbPassword, - DBPort: cmd.dbPort, - DBType: cmd.dbType, +import ( + "github.com/rubixchain/rubixgoplatform/core/config" + "github.com/spf13/cobra" + "github.com/rubixchain/rubixgoplatform/core/storage" +) + +func configCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "config", + Short: "Config related subcommands (DB, service)", + Long: "Config related subcommands (DB, service)", + Args: cobra.NoArgs, } - msg, ok := cmd.c.SetupDB(sc) - if !ok { - cmd.log.Error("Failed to setup DB", "msg", msg) - return + + cmd.AddCommand( + setupDB(cmdCfg), + setupService(cmdCfg), + ) + + return cmd +} + +func setupDB(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "setup-db", + Short: "Setup Database", + Long: "Setup Database", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + sc := &config.StorageConfig{ + StorageType: cmdCfg.storageType, + DBName: cmdCfg.dbName, + DBAddress: cmdCfg.dbAddress, + DBUserName: cmdCfg.dbUserName, + DBPassword: cmdCfg.dbPassword, + DBPort: cmdCfg.dbPort, + DBType: cmdCfg.dbType, + } + msg, ok := cmdCfg.c.SetupDB(sc) + if !ok { + cmdCfg.log.Error("Failed to setup DB", "msg", msg) + return nil + } + cmdCfg.log.Info("DB setup done successfully") + return nil + }, } - cmd.log.Info("DB setup done successfully") + + cmd.Flags().IntVar(&cmdCfg.storageType, "storageType", storage.StorageDBType, "Storage type") + cmd.Flags().StringVar(&cmdCfg.dbName, "dbName", "ServiceDB", "Service database name") + cmd.Flags().StringVar(&cmdCfg.dbType, "dbType", "SQLServer", "DB Type, supported database are SQLServer, PostgressSQL, MySQL & Sqlite3") + cmd.Flags().StringVar(&cmdCfg.dbAddress, "dbAddress", "localhost", "Database address") + cmd.Flags().StringVar(&cmdCfg.dbPort, "dbPort", "1433", "Database port number") + cmd.Flags().StringVar(&cmdCfg.dbUserName, "dbUsername", "sa", "Database username") + cmd.Flags().StringVar(&cmdCfg.dbPassword, "dbPassword", "password", "Database password") + + return cmd } + +func setupService(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "setup-service", + Short: "Setup Service", + Long: "Setup Service", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + scfg := config.ServiceConfig{ + ServiceName: cmdCfg.srvName, + DBName: cmdCfg.dbName, + DBType: cmdCfg.dbType, + DBAddress: cmdCfg.dbAddress, + DBPort: cmdCfg.dbPort, + DBUserName: cmdCfg.dbUserName, + DBPassword: cmdCfg.dbPassword, + } + msg, status := cmdCfg.c.SetupService(&scfg) + if !status { + cmdCfg.log.Error("Failed to setup service", "message", msg) + return nil + } + + cmdCfg.log.Info("Service setup successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.srvName, "srvName", "explorer_service", "Service name") + cmd.Flags().StringVar(&cmdCfg.dbName, "dbName", "ServiceDB", "Service database name") + cmd.Flags().StringVar(&cmdCfg.dbType, "dbType", "SQLServer", "DB Type, supported database are SQLServer, PostgressSQL, MySQL & Sqlite3") + cmd.Flags().StringVar(&cmdCfg.dbAddress, "dbAddress", "localhost", "Database address") + cmd.Flags().StringVar(&cmdCfg.dbPort, "dbPort", "1433", "Database port number") + cmd.Flags().StringVar(&cmdCfg.dbUserName, "dbUsername", "sa", "Database username") + cmd.Flags().StringVar(&cmdCfg.dbPassword, "dbPassword", "password", "Database password") + + return cmd +} \ No newline at end of file diff --git a/command/data_token.go b/command/data_token.go index 117f13f7..19aa7dc9 100644 --- a/command/data_token.go +++ b/command/data_token.go @@ -11,100 +11,132 @@ import ( "github.com/rubixchain/rubixgoplatform/client" "github.com/rubixchain/rubixgoplatform/core" "github.com/rubixchain/rubixgoplatform/util" + "github.com/spf13/cobra" ) -func (cmd *Command) createDataToken() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - dt := client.DataTokenReq{ - DID: cmd.did, - UserID: cmd.userID, - UserInfo: cmd.userInfo, - } +func createDataToken(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Create a Data Token", + Long: "Create a Data Token", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + dt := client.DataTokenReq{ + DID: cmdCfg.did, + UserID: cmdCfg.userID, + UserInfo: cmdCfg.userInfo, + } - if cmd.fileMode { - dt.Files = make([]string, 0) - dt.Files = append(dt.Files, cmd.file) - } else { - fd, err := ioutil.ReadFile(cmd.file) - if err != nil { - cmd.log.Error("Failed to read file", "err", err) - return - } - hb := util.CalculateHash(fd, "SHA3-256") - fi := make(map[string]map[string]string) - fn := path.Base(cmd.file) - info := make(map[string]string) - info[core.DTFileHashField] = util.HexToStr(hb) - fi[fn] = info - jb, err := json.Marshal(fi) - if err != nil { - cmd.log.Error("Failed to marshal json input", "err", err) - return - } - dt.FileInfo = string(jb) - } - br, err := cmd.c.CreateDataToken(&dt) - if err != nil { - cmd.log.Error("Failed to create data token", "err", err) - return + if cmdCfg.fileMode { + dt.Files = make([]string, 0) + dt.Files = append(dt.Files, cmdCfg.file) + } else { + fd, err := ioutil.ReadFile(cmdCfg.file) + if err != nil { + cmdCfg.log.Error("Failed to read file", "err", err) + return nil + } + hb := util.CalculateHash(fd, "SHA3-256") + fi := make(map[string]map[string]string) + fn := path.Base(cmdCfg.file) + info := make(map[string]string) + info[core.DTFileHashField] = util.HexToStr(hb) + fi[fn] = info + jb, err := json.Marshal(fi) + if err != nil { + cmdCfg.log.Error("Failed to marshal json input", "err", err) + return nil + } + dt.FileInfo = string(jb) + } + br, err := cmdCfg.c.CreateDataToken(&dt) + if err != nil { + cmdCfg.log.Error("Failed to create data token", "err", err) + return nil + } + if !br.Status { + cmdCfg.log.Error("Failed to create data token", "msg", br.Message) + return nil + } + msg, status := signatureResponse(cmdCfg, br) + if !status { + cmdCfg.log.Error("Failed to create data token, " + msg) + return nil + } + cmdCfg.log.Info(fmt.Sprintf("Data Token : %s", msg)) + cmdCfg.log.Info("Data token created successfully") + return nil + }, } - if !br.Status { - cmd.log.Error("Failed to create data token", "msg", br.Message) - return - } - msg, status := cmd.SignatureResponse(br) - if !status { - cmd.log.Error("Failed to create data token, " + msg) - return - } - cmd.log.Info(fmt.Sprintf("Data Token : %s", msg)) - cmd.log.Info("Data token created successfully") + + cmd.Flags().BoolVar(&cmdCfg.fileMode, "fmode", false, "File mode") + cmd.Flags().StringVar(&cmdCfg.file, "file", "file.txt", "File to be uploaded") + cmd.Flags().StringVar(&cmdCfg.userID, "uid", "testuser", "User ID for token creation") + cmd.Flags().StringVar(&cmdCfg.userInfo, "uinfo", "", "User info for token creation") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd } -func (cmd *Command) commitDataToken() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - br, err := cmd.c.CommitDataToken(cmd.did, cmd.batchID) - if err != nil { - cmd.log.Error("Failed to commit data token", "err", err) - return - } +func commitDataToken(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "commit", + Short: "Commit a Data Token", + Long: "Commit a Data Token", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + + br, err := cmdCfg.c.CommitDataToken(cmdCfg.did, cmdCfg.batchID) + if err != nil { + cmdCfg.log.Error("Failed to commit data token", "err", err) + return nil + } - if !br.Status { - cmd.log.Error("Failed to commit data token", "msg", br.Message) - return - } + if !br.Status { + cmdCfg.log.Error("Failed to commit data token", "msg", br.Message) + return nil + } - msg, status := cmd.SignatureResponse(br) + msg, status := signatureResponse(cmdCfg, br) - if !status { - cmd.log.Error("Failed to commit data token, " + msg) - return + if !status { + cmdCfg.log.Error("Failed to commit data token, " + msg) + return nil + } + + cmdCfg.log.Info("Data tokens committed successfully") + return nil + }, } - cmd.log.Info("Data tokens committed successfully") + + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + cmd.Flags().StringVar(&cmdCfg.batchID, "bid", "batchID1", "Batch ID") + + return cmd } diff --git a/command/decodeTokenChain.go b/command/decodeTokenChain.go new file mode 100644 index 00000000..36dab662 --- /dev/null +++ b/command/decodeTokenChain.go @@ -0,0 +1,119 @@ +package command + +import ( + "strconv" +) + +// Define a map for key translation +var keyMapping = map[string]string{ + "1": "TCTokenTypeKey", + "2": "TCTransTypeKey", + "3": "TCTokenOwnerKey", + "4": "TCGenesisBlockKey", + "5": "TCTransInfoKey", + "6": "TCSmartContractKey", + "7": "TCQuorumSignatureKey", + "8": "TCPledgeDetailsKey", + "9": "TCSmartContractDataKey", + "10": "TCTokenValueKey", + "11": "TCChildTokensKey", + "12": "TCSenderSignatureKey", + "98": "TCBlockHashKey", + "99": "TCSignatureKey", + "epoch": "TCEpoch", + // Keys under "4" + "4-1": "GBTypeKey", + "4-2": "GBInfoKey", + + "4-2-1": "GITokenLevelKey", + "4-2-2": "GITokenNumberKey", + "4-2-3": "GIMigratedBlkIDKey", + "4-2-4": "GIPreviousIDKey", + "4-2-5": "GIParentIDKey", + "4-2-6": "GIGrandParentIDKey", + "4-2-7": "GICommitedTokensKey", + "4-2-8": "GISmartContractValueKey", + + "5-1": "TISenderDIDKey", + "5-2": "TIReceiverDIDKey", + "5-3": "TICommentKey", + "5-4": "TITIDKey", + "5-5": "TIBlockKey", + "5-6": "TITokensKey", + "5-7": "TIRefIDKey", + "5-8": "TIDeployerDIDKey", + "5-9": "TIExecutorDIDKey", + "5-10": "TICommitedTokensKey", + "5-6-1": "TTTokenTypeKey", + "5-6-2": "TTPledgedTokenKey", + "5-6-3": "TTPledgedDIDKey", + "5-6-4": "TTBlockNumberKey", + "5-6-5": "TTPreviousBlockIDKey", + "5-6-6": "TTUnpledgedIDKey", + "5-6-7": "TTCommitedDIDKey", + "5-10-1": "TTTokenTypeKey", + "5-10-4": "TTBlockNumberKey", + "5-10-5": "TTPreviousBlockIDKey", + "5-10-6": "TTUnpledgedIDKey", + "5-10-7": "TTCommitedDIDKey", +} + +// flattenKeys processes the input recursively, flattening numeric keys and retaining non-numeric keys. +func flattenKeys(parentKey string, value interface{}) interface{} { + switch v := value.(type) { + case map[string]interface{}: + flattenedMap := make(map[string]interface{}) + for k, nestedValue := range v { + var newKey string + if isInteger(k) { + if parentKey != "" { + newKey = parentKey + "-" + k + } else { + newKey = k + } + flattenedMap[newKey] = flattenKeys(newKey, nestedValue) + } else { + newKey = k + flattenedMap[newKey] = flattenKeys(parentKey, nestedValue) + } + } + return flattenedMap + case []interface{}: + for i, item := range v { + v[i] = flattenKeys(parentKey, item) + } + return v + default: + return value + } +} + +// applyKeyMapping recursively applies the key mapping to the flattened JSON structure. +func applyKeyMapping(value interface{}) interface{} { + switch v := value.(type) { + case map[string]interface{}: + mappedMap := make(map[string]interface{}) + for k, nestedValue := range v { + mappedKey, exists := keyMapping[k] + if exists { + mappedMap[mappedKey] = applyKeyMapping(nestedValue) + } else { + mappedMap[k] = applyKeyMapping(nestedValue) + } + } + return mappedMap + case []interface{}: + for i, item := range v { + v[i] = applyKeyMapping(item) + } + return v + default: + return value + } +} + +// isInteger checks if the given string is an integer. +func isInteger(s string) bool { + _, err := strconv.Atoi(s) + return err == nil +} diff --git a/command/diagnostic.go b/command/diagnostic.go deleted file mode 100644 index 150f4db6..00000000 --- a/command/diagnostic.go +++ /dev/null @@ -1,291 +0,0 @@ -package command - -import ( - "fmt" - "os" - "regexp" - "strings" - - "github.com/rubixchain/rubixgoplatform/block" - "github.com/rubixchain/rubixgoplatform/util" -) - -func tcMarshal(str string, m interface{}) (string, error) { - var err error - switch mt := m.(type) { - case []map[string]interface{}: - str = str + "[" - c1 := false - for i := range mt { - if c1 { - str = str + "," - } - c1 = true - str, err = tcMarshal(str, mt[i]) - if err != nil { - return "", err - } - } - str = str + "]" - case map[string]interface{}: - str = str + "{" - c1 := false - for k, v := range mt { - if c1 { - str = str + "," - } - c1 = true - str = str + "\"" + k + "\":" - s, ok := v.(string) - if ok { - str = str + "\"" + s + "\"" - } else { - str, err = tcMarshal(str, v) - if err != nil { - return "", err - } - } - } - str = str + "}" - case map[string]string: - str = str + "{" - c1 := false - for k, v := range mt { - if c1 { - str = str + "," - } - c1 = true - str = str + "\"" + k + "\":" - str = str + "\"" + v + "\"" - } - - str = str + "}" - case map[interface{}]interface{}: - str = str + "{" - c1 := false - for k, v := range mt { - if c1 { - str = str + "," - } - c1 = true - str = str + "\"" + k.(string) + "\":" - str, err = tcMarshal(str, v) - if err != nil { - return "", err - } - } - - str = str + "}" - case []string: - str = str + "[" - c1 := false - for _, mf := range mt { - if c1 { - str = str + "," - } - c1 = true - str, err = tcMarshal(str, mf) - if err != nil { - return "", err - } - } - str = str + "]" - case []byte: - str = str + "\"" + util.HexToStr(mt) + "\"" - case string: - str = str + "\"" + mt + "\"" - case []interface{}: - str = str + "[" - c1 := false - for _, mf := range mt { - if c1 { - str = str + "," - } - c1 = true - s, ok := mf.(string) - if ok { - str = str + "\"" + s + "\"" - } else { - str, err = tcMarshal(str, mf) - if err != nil { - return "", err - } - } - } - str = str + "]" - case uint64: - str = str + fmt.Sprintf("%d", mt) - case int: - str = str + fmt.Sprintf("%d", mt) - case float64: - // TokenValue (key: "10") is a float value and needs to have a precision of 5 - // in the output dump file - str = str + fmt.Sprintf("%.5f", mt) - case interface{}: - str, err = tcMarshal(str, mt) - if err != nil { - return "", err - } - case nil: - str = str + "\"" + "\"" - default: - return "", fmt.Errorf("invalid type %T", mt) - } - return str, nil -} - -func (cmd *Command) dumpTokenChain() { - if cmd.token == "" { - cmd.log.Info("token id cannot be empty") - fmt.Print("Enter Token Id : ") - _, err := fmt.Scan(&cmd.token) - if err != nil { - cmd.log.Error("Failed to get Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.token) - - if len(cmd.token) != 46 || !strings.HasPrefix(cmd.token, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid token") - return - } - - blocks := make([]map[string]interface{}, 0) - blockID := "" - for { - ds, err := cmd.c.DumpTokenChain(cmd.token, blockID) - if err != nil { - cmd.log.Error("Failed to dump token chain", "err", err) - return - } - if !ds.Status { - cmd.log.Error("Failed to dump token chain", "msg", ds.Message) - return - } - for _, blk := range ds.Blocks { - b := block.InitBlock(blk, nil) - if b != nil { - blocks = append(blocks, b.GetBlockMap()) - } else { - cmd.log.Error("Invalid block") - } - } - blockID = ds.NextBlockID - if ds.NextBlockID == "" { - break - } - } - str, err := tcMarshal("", blocks) - if err != nil { - cmd.log.Error("Failed to dump token chain", "err", err) - return - } - f, err := os.Create("dump.json") - if err != nil { - cmd.log.Error("Failed to dump token chain", "err", err) - return - } - f.WriteString(str) - f.Close() - cmd.log.Info("Token chain dumped successfully!") -} - -func (cmd *Command) dumpSmartContractTokenChain() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - blocks := make([]map[string]interface{}, 0) - blockID := "" - for { - ds, err := cmd.c.DumpSmartContractTokenChain(cmd.smartContractToken, blockID) - if err != nil { - cmd.log.Error("Failed to dump smart contract token chain", "err", err) - return - } - if !ds.Status { - cmd.log.Error("Failed to dump smart contract token chain", "msg", ds.Message) - return - } - for _, blk := range ds.Blocks { - b := block.InitBlock(blk, nil) - if b != nil { - blocks = append(blocks, b.GetBlockMap()) - } else { - cmd.log.Error("Invalid block") - } - } - blockID = ds.NextBlockID - if ds.NextBlockID == "" { - break - } - } - str, err := tcMarshal("", blocks) - if err != nil { - cmd.log.Error("Failed to dump smart contract token chain", "err", err) - return - } - f, err := os.Create("dump.json") - if err != nil { - cmd.log.Error("Failed to dump smart contract token chain", "err", err) - return - } - f.WriteString(str) - f.Close() - cmd.log.Info("smart contract Token chain dumped successfully!") -} - -func (cmd *Command) getTokenBlock() { - -} - -func (cmd *Command) getSmartContractData() { - // if latest flag not set then return all data - // format willbe json object - /* - { - block_no - block_hash - smartcontract_hash - } - */ - -} - -func (cmd *Command) removeTokenChainBlock() { - response, err := cmd.c.RemoveTokenChainBlock(cmd.token, cmd.latest) - if err != nil { - cmd.log.Error("Failed to remove token chain", "err", err) - return - } - if !response.Status { - cmd.log.Error("Failed to remove token chain", "msg", response.Message) - return - } - cmd.log.Info("Token chain removed successfully!") -} - -func (cmd *Command) releaseAllLockedTokens() { - resp, err := cmd.c.ReleaseAllLockedTokens() - if err != nil { - cmd.log.Error("Failed to release the locked tokens", "err", err) - return - } - if !resp.Status { - cmd.log.Error("Failed to release the locked tokens", "msg", resp.Message) - return - } - cmd.log.Info("Locked Tokens released successfully Or No Locked Tokens found to be released") -} diff --git a/command/did.go b/command/did.go index f424ef25..5e2a17d2 100644 --- a/command/did.go +++ b/command/did.go @@ -15,242 +15,323 @@ import ( "github.com/rubixchain/rubixgoplatform/did" "github.com/rubixchain/rubixgoplatform/nlss" "github.com/rubixchain/rubixgoplatform/util" + "github.com/spf13/cobra" ) -func (cmd *Command) CreateDID() { - if cmd.forcePWD { - pwd, err := getpassword("Set private key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - npwd, err := getpassword("Re-enter private key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - if pwd != npwd { - cmd.log.Error("Password mismatch") - return - } - cmd.privPWD = pwd - } - if cmd.forcePWD { - pwd, err := getpassword("Set quorum key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - npwd, err := getpassword("Re-enter quorum key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - if pwd != npwd { - cmd.log.Error("Password mismatch") - return - } - cmd.quorumPWD = pwd - } - if cmd.didType < 0 || cmd.didType > 4 { - cmd.log.Error("DID Type should be between 0 and 4") - return +func didCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "did", + Short: "DID related subcommands", + Long: "DID related subcommands", + Args: cobra.NoArgs, } - if cmd.didType == did.LiteDIDMode { - if cmd.privKeyFile == "" || cmd.pubKeyFile == "" { - cmd.log.Error("private key & public key file names required") - return - } - } else if cmd.didType == did.WalletDIDMode { - f, err := os.Open(cmd.imgFile) - if err != nil { - cmd.log.Error("failed to open image", "err", err) - return - } - defer f.Close() - img, _, err := image.Decode(f) - if err != nil { - cmd.log.Error("failed to decode image", "err", err) - return - } - bounds := img.Bounds() - w, h := bounds.Max.X, bounds.Max.Y - if w != 256 || h != 256 { - cmd.log.Error("invalid image size", "err", err) - return - } - pixels := make([]byte, 0) - for y := 0; y < h; y++ { - for x := 0; x < w; x++ { - r, g, b, _ := img.At(x, y).RGBA() - pixels = append(pixels, byte(r>>8)) - pixels = append(pixels, byte(g>>8)) - pixels = append(pixels, byte(b>>8)) + cmd.AddCommand( + createDID(cmdCfg), + listDIDs(cmdCfg), + registerDID(cmdCfg), + accountInfoCmd(cmdCfg), + ) + + return cmd +} + +func createDID(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Create a DID", + Long: "Create a DID", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + if cmdCfg.forcePWD { + pwd, err := getpassword("Set private key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + npwd, err := getpassword("Re-enter private key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + if pwd != npwd { + cmdCfg.log.Error("Password mismatch") + return nil + } + cmdCfg.privPWD = pwd } - } - outPixels := make([]byte, 0) - message := cmd.didSecret + util.GetMACAddress() - dataHash := util.CalculateHash([]byte(message), "SHA3-256") - offset := 0 - for y := 0; y < h; y++ { - for x := 0; x < 24; x++ { - for i := 0; i < 32; i++ { - outPixels = append(outPixels, dataHash[i]^pixels[offset+i]) + if cmdCfg.forcePWD { + pwd, err := getpassword("Set quorum key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + npwd, err := getpassword("Re-enter quorum key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + if pwd != npwd { + cmdCfg.log.Error("Password mismatch") + return nil } - offset = offset + 32 - dataHash = util.CalculateHash(dataHash, "SHA3-256") + cmdCfg.quorumPWD = pwd } - } - - err = util.CreatePNGImage(outPixels, w, h, cmd.didImgFile) - if err != nil { - cmd.log.Error("failed to create image", "err", err) - return - } - pvtShare := make([]byte, 0) - pubShare := make([]byte, 0) - numBytes := len(outPixels) - for i := 0; i < numBytes; i = i + 1024 { - pvS, pbS := nlss.Gen2Shares(outPixels[i : i+1024]) - pvtShare = append(pvtShare, pvS...) - pubShare = append(pubShare, pbS...) - } - err = util.CreatePNGImage(pvtShare, w*4, h*2, cmd.privImgFile) - if err != nil { - cmd.log.Error("failed to create image", "err", err) - return - } - err = util.CreatePNGImage(pubShare, w*4, h*2, cmd.pubImgFile) - if err != nil { - cmd.log.Error("failed to create image", "err", err) - return - } - } - if cmd.didType != did.BasicDIDMode && cmd.didType != did.LiteDIDMode { - if cmd.privKeyFile == "" || cmd.pubKeyFile == "" { - cmd.log.Error("private key & public key file names required") - return - } - pvtKey, pubKey, err := crypto.GenerateKeyPair(&crypto.CryptoConfig{Alg: crypto.ECDSAP256, Pwd: cmd.privPWD}) - if err != nil { - cmd.log.Error("failed to create keypair", "err", err) - return - } - err = util.FileWrite(cmd.privKeyFile, pvtKey) - if err != nil { - cmd.log.Error("failed to write private key file", "err", err) - return - } - err = util.FileWrite(cmd.pubKeyFile, pubKey) - if err != nil { - cmd.log.Error("failed to write public key file", "err", err) - return - } - } - cfg := did.DIDCreate{ - Type: cmd.didType, - Secret: cmd.didSecret, - RootDID: cmd.didRoot, - PrivPWD: cmd.privPWD, - QuorumPWD: cmd.quorumPWD, - ImgFile: cmd.imgFile, - DIDImgFileName: cmd.didImgFile, - PubImgFile: cmd.pubImgFile, - PubKeyFile: cmd.pubKeyFile, - MnemonicFile: cmd.mnemonicFile, - ChildPath: cmd.ChildPath, - } - msg, status := cmd.c.CreateDID(&cfg) - if !status { - cmd.log.Error("Failed to create DID", "message", msg) - return + if cmdCfg.didType == did.LiteDIDMode { + if cmdCfg.privKeyFile == "" || cmdCfg.pubKeyFile == "" { + cmdCfg.log.Error("private key & public key file names required") + return nil + } + } else if cmdCfg.didType == did.WalletDIDMode { + f, err := os.Open(cmdCfg.imgFile) + if err != nil { + cmdCfg.log.Error("failed to open image", "err", err) + return nil + } + defer f.Close() + img, _, err := image.Decode(f) + if err != nil { + cmdCfg.log.Error("failed to decode image", "err", err) + return nil + } + bounds := img.Bounds() + w, h := bounds.Max.X, bounds.Max.Y + + if w != 256 || h != 256 { + cmdCfg.log.Error("invalid image size", "err", err) + return nil + } + pixels := make([]byte, 0) + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + r, g, b, _ := img.At(x, y).RGBA() + pixels = append(pixels, byte(r>>8)) + pixels = append(pixels, byte(g>>8)) + pixels = append(pixels, byte(b>>8)) + } + } + outPixels := make([]byte, 0) + message := cmdCfg.didSecret + util.GetMACAddress() + dataHash := util.CalculateHash([]byte(message), "SHA3-256") + offset := 0 + for y := 0; y < h; y++ { + for x := 0; x < 24; x++ { + for i := 0; i < 32; i++ { + outPixels = append(outPixels, dataHash[i]^pixels[offset+i]) + } + offset = offset + 32 + dataHash = util.CalculateHash(dataHash, "SHA3-256") + } + } + + err = util.CreatePNGImage(outPixels, w, h, cmdCfg.didImgFile) + if err != nil { + cmdCfg.log.Error("failed to create image", "err", err) + return nil + } + pvtShare := make([]byte, 0) + pubShare := make([]byte, 0) + numBytes := len(outPixels) + for i := 0; i < numBytes; i = i + 1024 { + pvS, pbS := nlss.Gen2Shares(outPixels[i : i+1024]) + pvtShare = append(pvtShare, pvS...) + pubShare = append(pubShare, pbS...) + } + err = util.CreatePNGImage(pvtShare, w*4, h*2, cmdCfg.privImgFile) + if err != nil { + cmdCfg.log.Error("failed to create image", "err", err) + return nil + } + err = util.CreatePNGImage(pubShare, w*4, h*2, cmdCfg.pubImgFile) + if err != nil { + cmdCfg.log.Error("failed to create image", "err", err) + return nil + } + } + if cmdCfg.didType != did.BasicDIDMode && cmdCfg.didType != did.LiteDIDMode { + if cmdCfg.privKeyFile == "" || cmdCfg.pubKeyFile == "" { + cmdCfg.log.Error("private key & public key file names required") + return nil + } + pvtKey, pubKey, err := crypto.GenerateKeyPair(&crypto.CryptoConfig{Alg: crypto.ECDSAP256, Pwd: cmdCfg.privPWD}) + if err != nil { + cmdCfg.log.Error("failed to create keypair", "err", err) + return nil + } + err = util.FileWrite(cmdCfg.privKeyFile, pvtKey) + if err != nil { + cmdCfg.log.Error("failed to write private key file", "err", err) + return nil + } + err = util.FileWrite(cmdCfg.pubKeyFile, pubKey) + if err != nil { + cmdCfg.log.Error("failed to write public key file", "err", err) + return nil + } + } + cfg := did.DIDCreate{ + Type: cmdCfg.didType, + Secret: cmdCfg.didSecret, + RootDID: cmdCfg.didRoot, + PrivPWD: cmdCfg.privPWD, + QuorumPWD: cmdCfg.quorumPWD, + ImgFile: cmdCfg.imgFile, + DIDImgFileName: cmdCfg.didImgFile, + PubImgFile: cmdCfg.pubImgFile, + PubKeyFile: cmdCfg.pubKeyFile, + MnemonicFile: cmdCfg.mnemonicFile, + ChildPath: cmdCfg.ChildPath, + } + msg, status := cmdCfg.c.CreateDID(&cfg) + if !status { + cmdCfg.log.Error("Failed to create DID", "message", msg) + return nil + } + cmdCfg.log.Info(fmt.Sprintf("DID %v created successfully", msg)) + return nil + }, } - cmd.log.Info(fmt.Sprintf("DID %v created successfully", msg)) + + cmd.Flags().BoolVar(&cmdCfg.forcePWD, "fp", false, "Force password entry") + cmd.Flags().StringVar(&cmdCfg.privPWD, "privPWD", "mypassword", "Private key password") + cmd.Flags().StringVar(&cmdCfg.quorumPWD, "quorumPWD", "mypassword", "Quorum key password") + cmd.Flags().IntVar(&cmdCfg.didType, "didType", 4, "DID Creation type") + cmd.Flags().StringVar(&cmdCfg.imgFile, "imgFile", did.ImgFileName, "DID creation image") + cmd.Flags().StringVar(&cmdCfg.privKeyFile, "privKeyFile", did.PvtKeyFileName, "Private key file") + cmd.Flags().StringVar(&cmdCfg.pubKeyFile, "pubKeyFile", did.PubKeyFileName, "Public key file") + cmd.Flags().StringVar(&cmdCfg.mnemonicFile, "mnemonicKeyFile", did.MnemonicFileName, "Mnemonic key file") + cmd.Flags().IntVar(&cmdCfg.ChildPath, "ChildPath", 0, "BIP child Path") + + return cmd } -func (cmd *Command) GetAllDID() { - response, err := cmd.c.GetAllDIDs() - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - if !response.Status { - cmd.log.Error("Failed to get DIDs", "message", response.Message) - return - } - for i := range response.AccountInfo { - fmt.Printf("Address : %s\n", response.AccountInfo[i].DID) +func listDIDs(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "Fetch every DID present in the node", + Long: "Fetch every DID present in the node", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + response, err := cmdCfg.c.GetAllDIDs() + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return err + } + if !response.Status { + cmdCfg.log.Error("Failed to get DIDs", "message", response.Message) + return err + } + for i := range response.AccountInfo { + fmt.Printf("Address : %s\n", response.AccountInfo[i].DID) + } + cmdCfg.log.Info("Got all DID successfully") + + return nil + }, } - cmd.log.Info("Got all DID successfully") + + return cmd } -func (cmd *Command) RegsiterDIDCmd() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - br, err := cmd.c.RegisterDID(cmd.did) +func registerDID(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "register", + Short: "Register DID", + Long: "Register DID", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } - if err != nil { - cmd.log.Error("Failed to register DID", "err", err) - return - } + br, err := cmdCfg.c.RegisterDID(cmdCfg.did) - if !br.Status { - cmd.log.Error("Failed to register DID", "msg", br.Message) - return - } + if err != nil { + errMsg := fmt.Errorf("failed to register DID, err: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } - msg, status := cmd.SignatureResponse(br) + if !br.Status { + errMsg := fmt.Errorf("failed to register DID, %v", br.Message) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } - if !status { - cmd.log.Error("Failed to register DID, " + msg) - return - } - cmd.log.Info("DID registered successfully") -} + msg, status := signatureResponse(cmdCfg, br) -func (cmd *Command) SetupDIDCmd() { - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - br, err := cmd.c.RegisterDID(cmd.did) + if !status { + errMsg := fmt.Errorf("failed to register DID, %v", msg) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + cmdCfg.log.Info("DID registered successfully") - if err != nil { - cmd.log.Error("Failed to register DID", "err", err) - return + return nil + }, } - if !br.Status { - cmd.log.Error("Failed to register DID", "msg", br.Message) - return - } + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") - msg, status := cmd.SignatureResponse(br) + return cmd +} + +func accountInfoCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "balance", + Short: "Get the account balance information of a DID", + Long: "Get the account balance information of a DID", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } - if !status { - cmd.log.Error("Failed to register DID, " + msg) - return + info, err := cmdCfg.c.GetAccountInfo(cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return nil + } + fmt.Printf("Response : %v\n", info) + if !info.Status { + cmdCfg.log.Error("Failed to get account info", "message", info.Message) + return nil + } else { + cmdCfg.log.Info("Successfully got the account balance information") + fmt.Printf("RBT : %10.5f, Locked RBT : %10.5f, Pledged RBT : %10.5f\n", info.AccountInfo[0].RBTAmount, info.AccountInfo[0].LockedRBT, info.AccountInfo[0].PledgedRBT) + return nil + } + }, } - cmd.log.Info("DID registered successfully") + + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd } -func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.Duration) (string, bool) { +func signatureResponse(cmdCfg *CommandConfig, br *model.BasicResponse, timeout ...time.Duration) (string, bool) { pwdSet := false - password := cmd.privPWD + password := cmdCfg.privPWD for { if !br.Status { return br.Message, false @@ -258,7 +339,7 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D if br.Result == nil { return br.Message, true } - cmd.log.Info("Got the request for the signature") + cmdCfg.log.Info("Got the request for the signature") jb, err := json.Marshal(br.Result) if err != nil { return "Invalid response, " + err.Error(), false @@ -268,7 +349,7 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D if err != nil { return "Invalid response, " + err.Error(), false } - if cmd.forcePWD && !pwdSet { + if cmdCfg.forcePWD && !pwdSet { password, err = getpassword("Enter private key password: ") if err != nil { return "Failed to get password", false @@ -285,7 +366,7 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D case did.BasicDIDMode: sresp.Password = password case did.StandardDIDMode: - privKey, err := ioutil.ReadFile(cmd.privKeyFile) + privKey, err := ioutil.ReadFile(cmdCfg.privKeyFile) if err != nil { return "Failed to open private key file, " + err.Error(), false } @@ -293,7 +374,7 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D if err != nil { return "Failed to decode private key file, " + err.Error(), false } - cmd.log.Info("Doing the private key signature") + cmdCfg.log.Info("Doing the private key signature") sig, err := crypto.Sign(key, sr.Hash) if err != nil { return "Failed to do signature, " + err.Error(), false @@ -302,11 +383,11 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D case did.WalletDIDMode: hash := sr.Hash if !sr.OnlyPrivKey { - byteImg, err := util.GetPNGImagePixels(cmd.privImgFile) + byteImg, err := util.GetPNGImagePixels(cmdCfg.privImgFile) if err != nil { return "Failed to read private share image file, " + err.Error(), false } - cmd.log.Info("Doing the private share signature") + cmdCfg.log.Info("Doing the private share signature") ps := util.ByteArraytoIntArray(byteImg) randPosObject := util.RandomPositions("signer", string(sr.Hash), 32, ps) @@ -323,7 +404,7 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D } sresp.Signature.Pixels = bs } - privKey, err := ioutil.ReadFile(cmd.privKeyFile) + privKey, err := ioutil.ReadFile(cmdCfg.privKeyFile) if err != nil { return "Failed to open private key file, " + err.Error(), false } @@ -331,46 +412,17 @@ func (cmd *Command) SignatureResponse(br *model.BasicResponse, timeout ...time.D if err != nil { return "Failed to decode private key file, " + err.Error(), false } - cmd.log.Info("Doing the private key signature") + cmdCfg.log.Info("Doing the private key signature") sig, err := crypto.Sign(key, hash) if err != nil { return "Failed to do signature, " + err.Error(), false } sresp.Signature.Signature = sig } - br, err = cmd.c.SignatureResponse(&sresp, timeout...) + br, err = cmdCfg.c.SignatureResponse(&sresp, timeout...) if err != nil { - cmd.log.Error("Failed to generate RBT", "err", err) + cmdCfg.log.Error("Failed to generate RBT", "err", err) return "Failed in signature response, " + err.Error(), false } } } - -func (cmd *Command) GetAccountInfo() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - info, err := cmd.c.GetAccountInfo(cmd.did) - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - fmt.Printf("Response : %v\n", info) - if !info.Status { - cmd.log.Error("Failed to get account info", "message", info.Message) - } else { - cmd.log.Info("Successfully got the account information") - fmt.Printf("RBT : %10.5f, Locked RBT : %10.5f, Pledged RBT : %10.5f, Pinned RBT : %10.5f\n", info.AccountInfo[0].RBTAmount, info.AccountInfo[0].LockedRBT, info.AccountInfo[0].PledgedRBT, info.AccountInfo[0].PinnedRBT) - } -} diff --git a/command/explorer.go b/command/explorer.go index 11070427..fae32c7e 100644 --- a/command/explorer.go +++ b/command/explorer.go @@ -1,43 +1,113 @@ package command -import "fmt" +import ( + "fmt" -func (cmd *Command) addExplorer() { - if len(cmd.links) == 0 { - cmd.log.Error("provide explorer links required to add") - return - } - msg, status := cmd.c.AddExplorer(cmd.links) + "github.com/spf13/cobra" +) - if !status { - cmd.log.Error("Add Explorer command failed, " + msg) - } else { - cmd.log.Info("Add Explorer command finished, " + msg) +func explorerCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "explorer", + Short: "Explorer related commands", + Long: "Explorer related commands", } + + cmd.AddCommand( + addExplorer(cmdCfg), + removeExplorer(cmdCfg), + getAllExplorer(cmdCfg), + ) + + return cmd } -func (cmd *Command) removeExplorer() { - if len(cmd.links) == 0 { - cmd.log.Error("provide explorer links required to remove") - return - } - msg, status := cmd.c.RemoveExplorer(cmd.links) - if !status { - cmd.log.Error("Remove Explorer command failed, " + msg) - } else { - cmd.log.Info("Remove Explorer command finished, " + msg) +const linksFlag string = "links" + +func addExplorer(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add Explorer URLs", + Long: "Add Explorer URLs", + RunE: func(cmd *cobra.Command, args []string) error { + links, err := cmd.Flags().GetStringSlice(linksFlag) + if err != nil { + return err + } + + if len(links) == 0 { + cmdCfg.log.Error("links are required for Explorer") + return nil + } + msg, status := cmdCfg.c.AddExplorer(links) + + if !status { + cmdCfg.log.Error("Add Explorer command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Add Explorer command finished, " + msg) + return nil + } + }, } + + cmd.Flags().StringSlice(linksFlag, []string{}, "Explorer URLs") + + return cmd } -func (cmd *Command) getAllExplorer() { - links, msg, status := cmd.c.GetAllExplorer() - if !status { - cmd.log.Error("Get all Explorer command failed, " + msg) - } else { - cmd.log.Info("Get all Explorer command finished, " + msg) - cmd.log.Info("Explorer links", "links", links) - for i, q := range links { - fmt.Printf("URL %d: %s\n", i, q) - } +func removeExplorer(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove", + Short: "Remove Explorer URLs", + Long: "Remove Explorer URLs", + RunE: func(cmd *cobra.Command, args []string) error { + links, err := cmd.Flags().GetStringSlice(linksFlag) + if err != nil { + return err + } + + if len(links) == 0 { + cmdCfg.log.Error("links required for Explorer") + return nil + } + + msg, status := cmdCfg.c.RemoveExplorer(links) + if !status { + cmdCfg.log.Error("Remove Explorer command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Remove Explorer command finished, " + msg) + return nil + } + }, } + + cmd.Flags().StringSlice(linksFlag, []string{}, "Explorer URLs") + + return cmd } + +func getAllExplorer(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all Explorer URLs", + Long: "List all Explorer URLs", + RunE: func(cmd *cobra.Command, args []string) error { + links, msg, status := cmdCfg.c.GetAllExplorer() + if !status { + cmdCfg.log.Error("Get all Explorer command failed, " + msg) + return nil + } else { + cmdCfg.log.Info("Get all Explorer command finished, " + msg) + cmdCfg.log.Info("Explorer links", "links", links) + for i, q := range links { + fmt.Printf("URL %d: %s\n", i, q) + } + return nil + } + }, + } + + return cmd +} \ No newline at end of file diff --git a/command/migrate.go b/command/migrate.go deleted file mode 100644 index d36ace7e..00000000 --- a/command/migrate.go +++ /dev/null @@ -1,93 +0,0 @@ -package command - -import ( - "encoding/json" - "io/ioutil" - - "github.com/rubixchain/rubixgoplatform/core" -) - -func (cmd *Command) MigrateNodeCmd() { - if cmd.forcePWD { - pwd, err := getpassword("Set private key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - npwd, err := getpassword("Re-enter private key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - if pwd != npwd { - cmd.log.Error("Password mismatch") - return - } - cmd.privPWD = pwd - } - if cmd.forcePWD { - pwd, err := getpassword("Set quorum key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - npwd, err := getpassword("Re-enter quorum key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - if pwd != npwd { - cmd.log.Error("Password mismatch") - return - } - cmd.quorumPWD = pwd - } - if cmd.didType < 0 || cmd.didType > 4 { - cmd.log.Error("DID Type should be between 0 and 4") - return - } - r := core.MigrateRequest{ - DIDType: cmd.didType, - PrivPWD: cmd.privPWD, - QuorumPWD: cmd.quorumPWD, - } - br, err := cmd.c.MigrateNode(&r, cmd.timeout) - if err != nil { - cmd.log.Error("Failed to migrate node", "err", err) - return - } - if !br.Status { - cmd.log.Error("Failed to migrate node", "msg", br.Message) - return - } - msg, status := cmd.SignatureResponse(br, cmd.timeout) - if !status { - cmd.log.Error("Failed to migrate node, " + msg) - return - } - cmd.log.Info("Node migrated successfully, " + msg) -} - -func (cmd *Command) LockedTokensCmd() { - fb, err := ioutil.ReadFile(cmd.tokenList) - if err != nil { - cmd.log.Error("Failed to read token list", "err", err) - return - } - var ts []string - err = json.Unmarshal(fb, &ts) - if err != nil { - cmd.log.Error("Invalid token list", "err", err) - return - } - br, err := cmd.c.LockToknes(ts) - if err != nil { - cmd.log.Error("Failed to lock tokens", "err", err) - return - } - if !br.Status { - cmd.log.Error("Failed to lock tokens", "msg", br.Message) - return - } - cmd.log.Info("Tokens lokced sucessfully") -} diff --git a/command/nft.go b/command/nft.go index bc65a23e..3b063e4d 100644 --- a/command/nft.go +++ b/command/nft.go @@ -9,71 +9,116 @@ import ( "github.com/rubixchain/rubixgoplatform/client" "github.com/rubixchain/rubixgoplatform/core" "github.com/rubixchain/rubixgoplatform/util" + "github.com/spf13/cobra" ) -func (cmd *Command) createNFT() { - if cmd.did == "" { - cmd.log.Error("Failed to create NFT, DID is required to create NFT") - return +func nftCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "nft", + Short: "NFT related subcommands", + Long: "NFT related subcommands", } - nt := client.CreateNFTReq{ - NumTokens: cmd.numTokens, - DID: cmd.did, - UserID: cmd.userID, - UserInfo: cmd.userInfo, - } - if cmd.fileMode { - nt.Files = make([]string, 0) - nt.Files = append(nt.Files, cmd.file) - } else { - fd, err := ioutil.ReadFile(cmd.file) - if err != nil { - cmd.log.Error("Failed to read file", "err", err) - return - } - hb := util.CalculateHash(fd, "SHA3-256") - fi := make(map[string]map[string]string) - fn := path.Base(cmd.file) - info := make(map[string]string) - info[core.DTFileHashField] = util.HexToStr(hb) - fi[fn] = info - jb, err := json.Marshal(fi) - if err != nil { - cmd.log.Error("Failed to marshal json input", "err", err) - return - } - nt.FileInfo = string(jb) - } - br, err := cmd.c.CreateNFT(&nt) - if err != nil { - cmd.log.Error("Failed to create NFT", "err", err) - return - } - if !br.Status { - cmd.log.Error("Failed to create NFT", "msg", br.Message) - return - } - msg, status := cmd.SignatureResponse(br) - if !status { - cmd.log.Error("Failed to create NFT, " + msg) - return - } - cmd.log.Info(fmt.Sprintf("Data Token : %s", msg)) - cmd.log.Info("NFT created successfully") + + cmd.AddCommand( + createNFT(cmdCfg), + getAllNFTs(cmdCfg), + ) + + return cmd } -func (cmd *Command) getAllNFTs() { - if cmd.did == "" { - cmd.log.Error("Failed to get NFTs, DID is required to get NFTs") - return +func createNFT(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Create an NFT", + Long: "Create an NFT", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Error("Failed to create NFT, DID is required to create NFT") + return nil + } + nt := client.CreateNFTReq{ + NumTokens: cmdCfg.numTokens, + DID: cmdCfg.did, + UserID: cmdCfg.userID, + UserInfo: cmdCfg.userInfo, + } + if cmdCfg.fileMode { + nt.Files = make([]string, 0) + nt.Files = append(nt.Files, cmdCfg.file) + } else { + fd, err := ioutil.ReadFile(cmdCfg.file) + if err != nil { + cmdCfg.log.Error("Failed to read file", "err", err) + return nil + } + hb := util.CalculateHash(fd, "SHA3-256") + fi := make(map[string]map[string]string) + fn := path.Base(cmdCfg.file) + info := make(map[string]string) + info[core.DTFileHashField] = util.HexToStr(hb) + fi[fn] = info + jb, err := json.Marshal(fi) + if err != nil { + cmdCfg.log.Error("Failed to marshal json input", "err", err) + return nil + } + nt.FileInfo = string(jb) + } + br, err := cmdCfg.c.CreateNFT(&nt) + if err != nil { + cmdCfg.log.Error("Failed to create NFT", "err", err) + return nil + } + if !br.Status { + cmdCfg.log.Error("Failed to create NFT", "msg", br.Message) + return nil + } + msg, status := signatureResponse(cmdCfg, br) + if !status { + cmdCfg.log.Error("Failed to create NFT, " + msg) + return nil + } + cmdCfg.log.Info(fmt.Sprintf("Data Token : %s", msg)) + cmdCfg.log.Info("NFT created successfully") + return nil + }, } - tkns, err := cmd.c.GetAllNFTs(cmd.did) - if err != nil { - cmd.log.Error("Failed to get NFTs, " + err.Error()) - return - } - for _, tkn := range tkns.Tokens { - fmt.Printf("NFT : %s, Status : %d\n", tkn.Token, tkn.TokenStatus) + + cmd.Flags().BoolVar(&cmdCfg.fileMode, "fmode", false, "File mode") + cmd.Flags().StringVar(&cmdCfg.file, "file", "file.txt", "File to be uploaded") + cmd.Flags().StringVar(&cmdCfg.userID, "uid", "testuser", "User ID for token creation") + cmd.Flags().StringVar(&cmdCfg.userInfo, "uinfo", "", "User info for token creation") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + cmd.Flags().IntVar(&cmdCfg.numTokens, "numTokens", 1, "Number of tokens") + + return cmd +} + +func getAllNFTs(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List NFTs by DID", + Long: "List NFTs by DID", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Error("Failed to get NFTs, DID is required to get NFTs") + return nil + } + tkns, err := cmdCfg.c.GetAllNFTs(cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get NFTs, " + err.Error()) + return nil + } + for _, tkn := range tkns.Tokens { + fmt.Printf("NFT : %s, Status : %d\n", tkn.Token, tkn.TokenStatus) + } + cmdCfg.log.Info("Got all NFTs successfully") + return nil + }, } - cmd.log.Info("Got all NFTs successfully") + + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd } diff --git a/command/node.go b/command/node.go index e343eb34..f1c3f70f 100644 --- a/command/node.go +++ b/command/node.go @@ -1,27 +1,396 @@ package command import ( + "encoding/json" "fmt" + "io/ioutil" "os" + "regexp" + "strings" + + "github.com/rubixchain/rubixgoplatform/core" + "github.com/rubixchain/rubixgoplatform/core/wallet" + "github.com/spf13/cobra" ) -func (cmd *Command) ShutDownCmd() { - msg, status := cmd.c.Shutdown() - if !status { - cmd.log.Error("Failed to shutdown", "msg", msg) - return +func nodeGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "node", + Short: "Node related subcommands", + Long: "Node related subcommands", + } + + cmd.AddCommand( + migrateNodeCmd(cmdCfg), + lockRBTTokensCmd(cmdCfg), + releaseAllLockedRBTTokensCmd(cmdCfg), + checkPinnedStateCmd(cmdCfg), + peerGroup(cmdCfg), + shutDownCmd(cmdCfg), + ) + + return cmd +} + +func peerGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "peer", + Short: "peer related subcommands", + Long: "peer related subcommands", + } + + cmd.AddCommand( + ping(cmdCfg), + checkQuorumStatus(cmdCfg), + getLocalPeerIDCmd(cmdCfg), + addPeerDetailsCmd(cmdCfg), + ) + + return cmd +} + +func addPeerDetailsCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add Peer details", + Long: "Add Peer details", + RunE: func(cmd *cobra.Command, args []string) error { + var peerID string + var did string + var err error + if cmdCfg.peerID == "" { + fmt.Print("Enter PeerID : ") + _, err = fmt.Scan(&peerID) + if err != nil { + cmdCfg.log.Error("Failed to get PeerID") + return err + } + } else { + peerID = cmdCfg.peerID + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(peerID) + if !strings.HasPrefix(peerID, "12D3KooW") || len(peerID) != 52 || !is_alphanumeric { + cmdCfg.log.Error("Invalid PeerID") + return fmt.Errorf("invalid peerID: %v", peerID) + } + + if cmdCfg.did == "" { + fmt.Print("Enter DID : ") + _, err = fmt.Scan(&did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return err + } + } else { + did = cmdCfg.did + } + is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(did) + if !strings.HasPrefix(did, "bafybmi") || len(did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return fmt.Errorf("invalid did: %v", did) + } + + // did_type = cmdCfg.didType + if cmdCfg.didType < 0 || cmdCfg.didType > 4 { + cmdCfg.log.Error("DID Type should be between 0 and 4") + return err + } + + peerDetail := wallet.DIDPeerMap{ + PeerID: peerID, + DID: did, + DIDType: &cmdCfg.didType, + } + msg, status := cmdCfg.c.AddPeer(&peerDetail) + if !status { + cmdCfg.log.Error("failed to add peer in DB", "message", msg) + return fmt.Errorf("failed to add peer in DB, err: %v", msg) + } + cmdCfg.log.Info("Peer added successfully") + + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.peerID, "peerID", "", "Peer ID") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + cmd.Flags().IntVar(&cmdCfg.didType, "didType", 4, "DID Creation Type") + + return cmd +} + +func checkPinnedStateCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "token-state-pinned-info", + Short: "Check if a Token state is pinned", + Long: "Check if a Token state is pinned", + RunE: func(cmd *cobra.Command, _ []string) error { + info, err := cmdCfg.c.GetPinnedInfo(cmdCfg.TokenState) + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return err + } + fmt.Printf("Response : %v\n", info) + if !info.Status { + cmdCfg.log.Debug("Pin not available", "message", info.Message) + } else { + cmdCfg.log.Info("Token State is Pinned") + } + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.TokenState, "tokenstatehash", "", "Token State Hash") + + return cmd +} + +func getLocalPeerIDCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "local-id", + Short: "Get the local IPFS peer id", + Long: "Get the local IPFS peer id", + RunE: func(cmd *cobra.Command, _ []string) error { + msg, status := cmdCfg.c.PeerID() + if !status { + cmdCfg.log.Error("Failed to fetch peer ID of the node", "msg", msg) + return nil + } + _, err := fmt.Fprint(os.Stdout, msg, "\n") + if err != nil { + cmdCfg.log.Error(err.Error()) + return nil + } + return nil + }, + } + + return cmd +} + +func shutDownCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "shutdown", + Short: "shut down the node", + Long: "shut down the node", + RunE: func(cmd *cobra.Command, _ []string) error { + msg, status := cmdCfg.c.Shutdown() + if !status { + cmdCfg.log.Error("Failed to shutdown", "msg", msg) + return nil + } + cmdCfg.log.Info("Shutdown initiated successfully, " + msg) + return nil + }, } - cmd.log.Info("Shutdown initiated successfully, " + msg) + + return cmd } -func (cmd *Command) peerIDCmd() { - msg, status := cmd.c.PeerID() - if !status { - cmd.log.Error("Failed to fetch peer ID of the node", "msg", msg) - return +func ping(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "ping", + Short: "pings a peer", + Long: "pings a peer", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.peerID == "" { + cmdCfg.log.Error("PeerID cannot be empty. Please use flag peerId") + return nil + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.peerID) + if !strings.HasPrefix(cmdCfg.peerID, "12D3KooW") || len(cmdCfg.peerID) != 52 || !is_alphanumeric { + cmdCfg.log.Error("Invalid PeerID") + return nil + } + + msg, status := cmdCfg.c.Ping(cmdCfg.peerID) + if !status { + cmdCfg.log.Error("Ping failed", "message", msg) + return nil + } else { + cmdCfg.log.Info("Ping response received successfully", "message", msg) + return nil + } + }, } - _, err := fmt.Fprint(os.Stdout, msg, "\n") - if err != nil { - cmd.log.Error(err.Error()) + + cmd.Flags().StringVar(&cmdCfg.peerID, "peerID", "", "Peerd ID") + + return cmd +} + +func checkQuorumStatus(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "quorum-status", + Long: "check the status of quorum", + Short: "check the status of quorum", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.quorumAddr == "" { + cmdCfg.log.Info("Quorum Address cannot be empty") + fmt.Print("Enter Quorum Address : ") + _, err := fmt.Scan(&cmdCfg.quorumAddr) + if err != nil { + cmdCfg.log.Error("Failed to get Quorum Address") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.quorumAddr) + if !strings.HasPrefix(cmdCfg.quorumAddr, "bafybmi") || len(cmdCfg.quorumAddr) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID of the quorum") + return nil + } + + msg, _ := cmdCfg.c.CheckQuorumStatus(cmdCfg.quorumAddr) + //Verification with "status" pending ! + if strings.Contains(msg, "Quorum is setup") { + cmdCfg.log.Info("Quorum is setup in", cmdCfg.quorumAddr, "message", msg) + return nil + } else { + cmdCfg.log.Error("Quorum is not setup in ", cmdCfg.quorumAddr, " message ", msg) + return nil + } + }, } + + cmd.Flags().StringVar(&cmdCfg.quorumAddr, "quorumAddr", "", "Quorum Node Address to check the status of the Quorum") + + return cmd +} + +func migrateNodeCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "migrate", + Short: "Migrate Node", + Long: "Migrate Node", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.forcePWD { + pwd, err := getpassword("Set private key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + npwd, err := getpassword("Re-enter private key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + if pwd != npwd { + cmdCfg.log.Error("Password mismatch") + return nil + } + cmdCfg.privPWD = pwd + } + + if cmdCfg.forcePWD { + pwd, err := getpassword("Set quorum key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + npwd, err := getpassword("Re-enter quorum key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + if pwd != npwd { + cmdCfg.log.Error("Password mismatch") + return nil + } + cmdCfg.quorumPWD = pwd + } + if cmdCfg.didType < 0 || cmdCfg.didType > 4 { + cmdCfg.log.Error("DID Type should be between 0 and 4") + return nil + } + r := core.MigrateRequest{ + DIDType: cmdCfg.didType, + PrivPWD: cmdCfg.privPWD, + QuorumPWD: cmdCfg.quorumPWD, + } + br, err := cmdCfg.c.MigrateNode(&r, cmdCfg.timeout) + if err != nil { + cmdCfg.log.Error("Failed to migrate node", "err", err) + return nil + } + if !br.Status { + cmdCfg.log.Error("Failed to migrate node", "msg", br.Message) + return nil + } + msg, status := signatureResponse(cmdCfg, br, cmdCfg.timeout) + if !status { + cmdCfg.log.Error("Failed to migrate node, " + msg) + return nil + } + cmdCfg.log.Info("Node migrated successfully, " + msg) + return nil + }, + } + + cmd.Flags().BoolVar(&cmdCfg.forcePWD, "fp", false, "Force password entry") + cmd.Flags().StringVar(&cmdCfg.privPWD, "privPWD", "mypassword", "Private key password") + cmd.Flags().StringVar(&cmdCfg.quorumPWD, "quorumPWD", "mypassword", "Quorum key password") + cmd.Flags().IntVar(&cmdCfg.didType, "didType", 4, "DID Creation type") + cmd.Flags().DurationVar(&cmdCfg.timeout, "timeout", 0, "Timeout for the server") + + return cmd +} + +func lockRBTTokensCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "lock-rbt-tokens", + Short: "Lock RBT tokens", + Long: "Lock RBT tokens", + RunE: func(cmd *cobra.Command, args []string) error { + fb, err := ioutil.ReadFile(cmdCfg.tokenList) + if err != nil { + cmdCfg.log.Error("Failed to read token list", "err", err) + return nil + } + var ts []string + err = json.Unmarshal(fb, &ts) + if err != nil { + cmdCfg.log.Error("Invalid token list", "err", err) + return nil + } + br, err := cmdCfg.c.LockToknes(ts) + if err != nil { + cmdCfg.log.Error("Failed to lock tokens", "err", err) + return nil + } + if !br.Status { + cmdCfg.log.Error("Failed to lock tokens", "msg", br.Message) + return nil + } + cmdCfg.log.Info("Tokens locked sucessfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.tokenList, "tokenList", "tokens.txt", "Token list") + + return cmd +} + +func releaseAllLockedRBTTokensCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "release-rbt-tokens", + Short: "Release all locked RBT tokens", + Long: "Release all locked RBT tokens", + RunE: func(cmd *cobra.Command, args []string) error { + resp, err := cmdCfg.c.ReleaseAllLockedTokens() + if err != nil { + cmdCfg.log.Error("Failed to release the locked tokens", "err", err) + return nil + } + if !resp.Status { + cmdCfg.log.Error("Failed to release the locked tokens", "msg", resp.Message) + return nil + } + + cmdCfg.log.Info("Locked Tokens released successfully Or No Locked Tokens found to be released") + return nil + }, + } + + return cmd } diff --git a/command/ping.go b/command/ping.go deleted file mode 100644 index d64c3197..00000000 --- a/command/ping.go +++ /dev/null @@ -1,49 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" -) - -func (cmd *Command) ping() { - if cmd.peerID == "" { - cmd.log.Error("PeerID cannot be empty. Please use flag peerId") - return - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.peerID) - if !strings.HasPrefix(cmd.peerID, "12D3KooW") || len(cmd.peerID) != 52 || !is_alphanumeric { - cmd.log.Error("Invalid PeerID") - return - } - msg, status := cmd.c.Ping(cmd.peerID) - if !status { - cmd.log.Error("Ping failed", "message", msg) - } else { - cmd.log.Info("Ping response received successfully", "message", msg) - } -} - -func (cmd *Command) checkQuorumStatus() { - if cmd.quorumAddr == "" { - cmd.log.Info("Quorum Address cannot be empty") - fmt.Print("Enter Quorum Address : ") - _, err := fmt.Scan(&cmd.quorumAddr) - if err != nil { - cmd.log.Error("Failed to get Quorum Address") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.quorumAddr) - if !strings.HasPrefix(cmd.quorumAddr, "bafybmi") || len(cmd.quorumAddr) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID of the quorum") - return - } - msg, _ := cmd.c.CheckQuorumStatus(cmd.quorumAddr) - //Verification with "status" pending ! - if strings.Contains(msg, "Quorum is setup") { - cmd.log.Info("Quorum is setup in", cmd.quorumAddr, "message", msg) - } else { - cmd.log.Error("Quorum is not setup in ", cmd.quorumAddr, " message ", msg) - } -} diff --git a/command/quorum.go b/command/quorum.go new file mode 100644 index 00000000..e1788175 --- /dev/null +++ b/command/quorum.go @@ -0,0 +1,190 @@ +package command + +import ( + "errors" + "fmt" + "regexp" + "strings" + + "github.com/spf13/cobra" +) + +func quorumCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "quorum", + Short: "Quorum related subcommands", + Long: "Quorum related subcommands", + } + + cmd.AddCommand( + addQuorumCmd(cmdCfg), + listQuorumsCmd(cmdCfg), + removeAllQuorumCmd(cmdCfg), + setupQuorumCmd(cmdCfg), + runUnpledgeCmd(cmdCfg), + getPledgedTokenStateDetailsCmd(cmdCfg), + ) + + return cmd +} + +func getPledgedTokenStateDetailsCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list-token-states", + Short: "List all pledge token states of a node", + Long: "List all pledge token states of a node", + RunE: func(cmd *cobra.Command, _ []string) error { + info, err := cmdCfg.c.GetPledgedTokenDetails() + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return err + } + fmt.Printf("Response : %v\n", info) + if !info.Status { + cmdCfg.log.Error("Failed to get account info", "message", info.Message) + } else { + cmdCfg.log.Info("Successfully got the pledged token states info") + fmt.Println("DID ", "Pledged Token ", "Token State") + for _, i := range info.PledgedTokenStateDetails { + fmt.Println(i.DID, " ", i.TokensPledged, " ", i.TokenStateHash) + } + } + return nil + }, + } + + return cmd +} + +func runUnpledgeCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "unpledge", + Short: "Unpledge all pledged tokens", + Long: "Unpledge all pledged tokens", + RunE: func(cmd *cobra.Command, _ []string) error { + msg, status := cmdCfg.c.RunUnpledge() + cmdCfg.log.Info("Unpledging of pledged tokens has started") + if !status { + cmdCfg.log.Error(msg) + return errors.New(msg) + } + + cmdCfg.log.Info(msg) + return nil + }, + } + + return cmd +} + +func addQuorumCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: "Add addresses present with quorumlist.json in the node", + Long: "Add addresses present with quorumlist.json in the node", + RunE: func(cmd *cobra.Command, args []string) error { + msg, status := cmdCfg.c.AddQuorum(cmdCfg.quorumList) + if !status { + cmdCfg.log.Error("Failed to add quorum list to node", "msg", msg) + return nil + } + cmdCfg.log.Info("Quorum list added successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.quorumList, "quorumList", "quorumlist.json", "Quorum list") + + return cmd +} + +func listQuorumsCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all Quorums", + Long: "List all Quorums", + RunE: func(cmd *cobra.Command, args []string) error { + response, err := cmdCfg.c.GettAllQuorum() + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return nil + } + if !response.Status { + cmdCfg.log.Error("Failed to get quorum list from node", "msg", response.Message) + return nil + } + for _, q := range response.Result { + fmt.Printf("Address : %s\n", q) + } + cmdCfg.log.Info("Got all quorum list successfully") + return nil + }, + } + + return cmd +} + +func removeAllQuorumCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "remove-all", + Short: "Remove all Quorums", + Long: "Remove all Quorums", + RunE: func(cmd *cobra.Command, args []string) error { + msg, status := cmdCfg.c.RemoveAllQuorum() + if !status { + cmdCfg.log.Error("Failed to remove quorum list", "msg", msg) + return nil + } + cmdCfg.log.Info(msg) + return nil + }, + } + + return cmd +} + +func setupQuorumCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "setup", + Short: "Setup up DID as a Quorum", + Long: "Setup up DID as a Quorum", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("Quorum DID cannot be empty") + fmt.Print("Enter Quorum DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get Quorum DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + + if cmdCfg.forcePWD { + pwd, err := getpassword("Enter quorum key password: ") + if err != nil { + cmdCfg.log.Error("Failed to get password") + return nil + } + cmdCfg.quorumPWD = pwd + } + msg, status := cmdCfg.c.SetupQuorum(cmdCfg.did, cmdCfg.quorumPWD, cmdCfg.privPWD) + + if !status { + cmdCfg.log.Error("Failed to setup quorum", "msg", msg) + return nil + } + cmdCfg.log.Info("Quorum setup successfully") + return nil + }, + } + + cmd.Flags().BoolVar(&cmdCfg.forcePWD, "fp", false, "Force password entry") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd +} diff --git a/command/quorurm.go b/command/quorurm.go deleted file mode 100644 index af1dce3d..00000000 --- a/command/quorurm.go +++ /dev/null @@ -1,74 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" -) - -func (cmd *Command) AddQuorurm() { - msg, status := cmd.c.AddQuorum(cmd.quorumList) - if !status { - cmd.log.Error("Failed to add quorum list to node", "msg", msg) - return - } - cmd.log.Info("Quorum list added successfully") -} - -func (cmd *Command) GetAllQuorum() { - response, err := cmd.c.GettAllQuorum() - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - if !response.Status { - cmd.log.Error("Failed to get quorum list from node", "msg", response.Message) - return - } - for _, q := range response.Result { - fmt.Printf("Address : %s\n", q) - } - cmd.log.Info("Got all quorum list successfully") -} - -func (cmd *Command) RemoveAllQuorum() { - msg, status := cmd.c.RemoveAllQuorum() - if !status { - cmd.log.Error("Failed to remove quorum list", "msg", msg) - return - } - cmd.log.Info(msg) -} - -func (cmd *Command) SetupQuorum() { - if cmd.forcePWD { - pwd, err := getpassword("Enter quorum key password: ") - if err != nil { - cmd.log.Error("Failed to get password") - return - } - cmd.quorumPWD = pwd - } - - if cmd.did == "" { - cmd.log.Info("Quorum DID cannot be empty") - fmt.Print("Enter Quorum DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get Quorum DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - msg, status := cmd.c.SetupQuorum(cmd.did, cmd.quorumPWD, cmd.privPWD) - - if !status { - cmd.log.Error("Failed to setup quorum", "msg", msg) - return - } - cmd.log.Info("Quorum setup successfully") -} diff --git a/command/rbt_token.go b/command/rbt_token.go new file mode 100644 index 00000000..91a4b228 --- /dev/null +++ b/command/rbt_token.go @@ -0,0 +1,193 @@ +package command + +import ( + "fmt" + "regexp" + "strings" + + "github.com/rubixchain/rubixgoplatform/core/model" + "github.com/spf13/cobra" +) + +func transferRBTCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "transfer", + Short: "Transfer RBT tokens", + Long: "Transfer RBT tokens", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.senderAddr == "" { + cmdCfg.log.Info("Sender address cannot be empty") + fmt.Print("Enter Sender DID : ") + _, err := fmt.Scan(&cmdCfg.senderAddr) + if err != nil { + cmdCfg.log.Error("Failed to get Sender DID") + return nil + } + } + if cmdCfg.receiverAddr == "" { + cmdCfg.log.Info("Receiver address cannot be empty") + fmt.Print("Enter Receiver DID : ") + _, err := fmt.Scan(&cmdCfg.receiverAddr) + if err != nil { + cmdCfg.log.Error("Failed to get Receiver DID") + return nil + } + } + is_alphanumeric_sender := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.senderAddr) + is_alphanumeric_receiver := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.receiverAddr) + if !is_alphanumeric_sender || !is_alphanumeric_receiver { + cmdCfg.log.Error("Invalid sender or receiver address. Please provide valid DID") + return nil + } + if !strings.HasPrefix(cmdCfg.senderAddr, "bafybmi") || len(cmdCfg.senderAddr) != 59 || !strings.HasPrefix(cmdCfg.receiverAddr, "bafybmi") || len(cmdCfg.receiverAddr) != 59 { + cmdCfg.log.Error("Invalid sender or receiver DID") + return nil + } + if cmdCfg.rbtAmount < 0.00001 { + cmdCfg.log.Error("Invalid RBT amount. RBT amount should be atlease 0.00001") + return nil + } + if cmdCfg.transType < 1 || cmdCfg.transType > 2 { + cmdCfg.log.Error("Invalid trans type. TransType should be 1 or 2") + return nil + } + + rt := model.RBTTransferRequest{ + Receiver: cmdCfg.receiverAddr, + Sender: cmdCfg.senderAddr, + TokenCount: cmdCfg.rbtAmount, + Type: cmdCfg.transType, + Comment: cmdCfg.transComment, + } + + br, err := cmdCfg.c.TransferRBT(&rt) + if err != nil { + cmdCfg.log.Error("Failed RBT transfer", "err", err) + return nil + } + msg, status := signatureResponse(cmdCfg, br) + if !status { + cmdCfg.log.Error("Failed to trasnfer RBT", "msg", msg) + return nil + } + cmdCfg.log.Info(msg) + cmdCfg.log.Info("RBT transfered successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.senderAddr, "senderAddr", "", "Sender address") + cmd.Flags().StringVar(&cmdCfg.receiverAddr, "receiverAddr", "", "Receiver address") + cmd.Flags().Float64Var(&cmdCfg.rbtAmount, "rbtAmount", 0.0, "RBT amount") + cmd.Flags().StringVar(&cmdCfg.transComment, "transComment", "", "Transaction comment") + cmd.Flags().IntVar(&cmdCfg.transType, "transType", 2, "Transaction type") + + return cmd +} + +func selfTransferRBTCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "self-transfer", + Short: "Self transfer RBT tokens", + Long: "Self transfer RBT tokens", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.senderAddr == "" { + cmdCfg.log.Info("Sender address cannot be empty") + fmt.Print("Enter Sender DID : ") + _, err := fmt.Scan(&cmdCfg.senderAddr) + if err != nil { + cmdCfg.log.Error("Failed to get Sender DID") + return nil + } + } + is_alphanumeric_sender := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.senderAddr) + if !is_alphanumeric_sender { + cmdCfg.log.Error("Invalid sender or receiver address. Please provide valid DID") + return nil + } + if !strings.HasPrefix(cmdCfg.senderAddr, "bafybmi") || len(cmdCfg.senderAddr) != 59 { + cmdCfg.log.Error("Invalid sender or receiver DID") + return nil + } + if cmdCfg.transType < 1 || cmdCfg.transType > 2 { + cmdCfg.log.Error("Invalid trans type. TransType should be 1 or 2") + return nil + } + rt := model.RBTTransferRequest{ + Receiver: cmdCfg.senderAddr, + Sender: cmdCfg.senderAddr, + Type: cmdCfg.transType, + } + + br, err := cmdCfg.c.SelfTransferRBT(&rt) + if err != nil { + cmdCfg.log.Error("Failed Self RBT transfer", "err", err) + return nil + } + msg, status := signatureResponse(cmdCfg, br) + if !status { + cmdCfg.log.Error("Failed to self trasnfer RBT", "msg", msg) + return nil + } + cmdCfg.log.Info(msg) + cmdCfg.log.Info("Self RBT transfered successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.senderAddr, "senderAddr", "", "Sender address") + cmd.Flags().IntVar(&cmdCfg.transType, "transType", 2, "Transaction type") + + return cmd +} + +func generateTestRBTCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "generate-test-tokens", + Short: "Generate Test RBT tokens", + Long: "Generate Test RBT tokens", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + if cmdCfg.numTokens <= 0 { + cmdCfg.log.Error("Invalid RBT amount, tokens generated should be a whole number and greater than 0") + return nil + } + + br, err := cmdCfg.c.GenerateTestRBT(cmdCfg.numTokens, cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to generate RBT", "err", err) + return nil + } + if !br.Status { + cmdCfg.log.Error("Failed to generate RBT", "msg", br.Message) + return nil + } + + msg, status := signatureResponse(cmdCfg, br) + if !status { + cmdCfg.log.Error("Failed to generate test RBT, " + msg) + return nil + } + cmdCfg.log.Info("Test RBT generated successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + cmd.Flags().IntVar(&cmdCfg.numTokens, "numTokens", 1, "Number of tokens") + + return cmd +} diff --git a/command/recover.go b/command/recover.go index 9ab2b7df..ec0ce00f 100644 --- a/command/recover.go +++ b/command/recover.go @@ -1,24 +1,100 @@ package command import ( + "fmt" + "github.com/rubixchain/rubixgoplatform/core/model" + "github.com/spf13/cobra" ) -func (cmd *Command) RecoverTokens() { - rt := model.RBTRecoverRequest{ - PinningNode: cmd.pinningAddress, - Sender: cmd.senderAddr, - TokenCount: cmd.rbtAmount, +func pinningServiceCommandGroup(commandCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "pin-service", + Short: "Token pinning and recover related subcommands", + Long: "Token pinning and recover related subcommands", } - br, err := cmd.c.RecoverRBT(&rt) - if err != nil { - cmd.log.Error("Failed to Recover the Tokens", "err", err) - return + cmd.AddCommand( + recoverTokenCmd(commandCfg), + pinRBTCmd(commandCfg), + ) + + return cmd +} + +func recoverTokenCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "recover", + Long: "Recovers the pinned token from the pinning service provider node", + Short: "Recovers the pinned token from the pinning service provider node", + RunE: func(cmd *cobra.Command, args []string) error { + rt := model.RBTRecoverRequest{ + PinningNode: cmdCfg.pinningAddress, + Sender: cmdCfg.senderAddr, + TokenCount: cmdCfg.rbtAmount, + } + + br, err := cmdCfg.c.RecoverRBT(&rt) + if err != nil { + cmdCfg.log.Error("Failed to Recover the Tokens", "err", err) + return err + } + if !br.Status { + errMsg := fmt.Errorf("failed to recover RBT: " + br.Message) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } else { + cmdCfg.log.Info("Recovered RBT: " + br.Message) + return nil + } + }, } - if !br.Status { - cmd.log.Error("Failed to recover RBT: " + br.Message) - } else { - cmd.log.Info("Recovered RBT: " + br.Message) + + cmd.Flags().StringVar(&cmdCfg.pinningAddress, "pinningAddress", "", "Pinning address") + cmd.Flags().StringVar(&cmdCfg.senderAddr, "senderAddr", "", "Sender Address") + cmd.Flags().Float64Var(&cmdCfg.rbtAmount, "rbtAmount", 0.0, "RBT amount") + + return cmd +} + +func pinRBTCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "pin", + Long: "Pins a token on a pinning service provider node", + Short: "Pins a token on a pinning service provider node", + RunE: func(cmd *cobra.Command, args []string) error { + rt := model.RBTPinRequest{ + PinningNode: cmdCfg.pinningAddress, + Sender: cmdCfg.senderAddr, + TokenCount: cmdCfg.rbtAmount, + Type: cmdCfg.transType, + Comment: cmdCfg.transComment, + } + + br, err := cmdCfg.c.PinRBT(&rt) + if err != nil { + errMsg := fmt.Errorf("failed to pin the token, err: %v", err) + cmdCfg.log.Error(errMsg.Error()) + return err + } + + msg, status := signatureResponse(cmdCfg, br) + if !status { + errMsg := fmt.Errorf("failed to pin the token, msg: %v", msg) + cmdCfg.log.Error(errMsg.Error()) + return errMsg + } + cmdCfg.log.Info(msg) + cmdCfg.log.Info("RBT Pinned successfully") + return nil + }, } + + cmd.Flags().StringVar(&cmdCfg.pinningAddress, "pinningAddress", "", "Pinning address") + cmd.Flags().StringVar(&cmdCfg.senderAddr, "senderAddr", "", "Sender Address") + cmd.Flags().Float64Var(&cmdCfg.rbtAmount, "rbtAmount", 0.0, "RBT amount") + cmd.Flags().StringVar(&cmdCfg.transComment, "transComment", "", "Transaction comment") + cmd.Flags().IntVar(&cmdCfg.transType, "transType", 2, "Transaction type") + + return cmd } diff --git a/command/services.go b/command/services.go deleted file mode 100644 index cf162878..00000000 --- a/command/services.go +++ /dev/null @@ -1,23 +0,0 @@ -package command - -import ( - "github.com/rubixchain/rubixgoplatform/core/config" -) - -func (cmd *Command) SetupService() { - scfg := config.ServiceConfig{ - ServiceName: cmd.srvName, - DBName: cmd.dbName, - DBType: cmd.dbType, - DBAddress: cmd.dbAddress, - DBPort: cmd.dbPort, - DBUserName: cmd.dbUserName, - DBPassword: cmd.dbPassword, - } - msg, status := cmd.c.SetupService(&scfg) - if !status { - cmd.log.Error("Failed to setup service", "message", msg) - return - } - cmd.log.Info("Service setup successfully") -} diff --git a/command/smartContract.go b/command/smartContract.go deleted file mode 100644 index 61184f8e..00000000 --- a/command/smartContract.go +++ /dev/null @@ -1,282 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" - - "github.com/rubixchain/rubixgoplatform/client" - "github.com/rubixchain/rubixgoplatform/core" - "github.com/rubixchain/rubixgoplatform/core/model" -) - -func (cmd *Command) generateSmartContractToken() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - if cmd.binaryCodePath == "" { - cmd.log.Error("Please provide Binary code file") - return - } - if cmd.rawCodePath == "" { - cmd.log.Error("Please provide Raw code file") - return - } - if cmd.schemaFilePath == "" { - cmd.log.Error("Please provide Schema file") - return - } - smartContractTokenRequest := core.GenerateSmartContractRequest{ - BinaryCode: cmd.binaryCodePath, - RawCode: cmd.rawCodePath, - SchemaCode: cmd.schemaFilePath, - DID: cmd.did, - } - - request := client.SmartContractRequest{ - BinaryCode: smartContractTokenRequest.BinaryCode, - RawCode: smartContractTokenRequest.RawCode, - SchemaCode: smartContractTokenRequest.SchemaCode, - DID: smartContractTokenRequest.DID, - } - - basicResponse, err := cmd.c.GenerateSmartContractToken(&request) - if err != nil { - cmd.log.Error("Failed to generate smart contract token", "err", err) - return - } - if !basicResponse.Status { - cmd.log.Error("Failed to generate smart contract token", "err", err) - return - } - cmd.log.Info("Smart contract token generated successfully") - -} - -func (cmd *Command) fetchSmartContract() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - smartContractTokenRequest := core.FetchSmartContractRequest{ - SmartContractToken: cmd.smartContractToken, - } - - request := client.FetchSmartContractRequest{ - SmartContractToken: smartContractTokenRequest.SmartContractToken, - } - - basicResponse, err := cmd.c.FetchSmartContract(&request) - if err != nil { - cmd.log.Error("Failed to fetch smart contract token", "err", err) - return - } - if !basicResponse.Status { - cmd.log.Error("Failed to fetch smart contract token", "err", err) - return - } - cmd.log.Info("Smart contract token fetched successfully") -} -func (cmd *Command) PublishContract() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - if cmd.publishType < 1 || cmd.publishType > 2 { - cmd.log.Error("Invalid publish type") - return - } - basicResponse, err := cmd.c.PublishNewEvent(cmd.smartContractToken, cmd.did, cmd.publishType, cmd.newContractBlock) - - if err != nil { - cmd.log.Error("Failed to publish new event", "err", err) - return - } - if !basicResponse.Status { - cmd.log.Error("Failed to publish new event", "msg", basicResponse.Message) - return - } - message, status := cmd.SignatureResponse(basicResponse) - - if !status { - cmd.log.Error("Failed to publish new event, " + message) - return - } - cmd.log.Info("New event published successfully") -} -func (cmd *Command) SubscribeContract() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - - basicResponse, err := cmd.c.SubscribeContract(cmd.smartContractToken) - - if err != nil { - cmd.log.Error("Failed to subscribe contract", "err", err) - return - } - if !basicResponse.Status { - cmd.log.Error("Failed to subscribe contract", "msg", basicResponse.Message) - return - } - message, status := cmd.SignatureResponse(basicResponse) - - if !status { - cmd.log.Error("Failed to subscribe contract, " + message) - return - } - cmd.log.Info("New event subscribed successfully") -} - -func (cmd *Command) deploySmartcontract() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.deployerAddr) - if !strings.HasPrefix(cmd.deployerAddr, "bafybmi") || len(cmd.deployerAddr) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid deployer DID") - return - } - if cmd.rbtAmount < 0.00001 { - cmd.log.Error("Invalid RBT amount. Minimum RBT amount should be 0.00001") - return - } - if cmd.transType < 1 || cmd.transType > 2 { - cmd.log.Error("Invalid trans type") - return - } - deployRequest := model.DeploySmartContractRequest{ - SmartContractToken: cmd.smartContractToken, - DeployerAddress: cmd.deployerAddr, - RBTAmount: cmd.rbtAmount, - QuorumType: cmd.transType, - Comment: cmd.transComment, - } - response, err := cmd.c.DeploySmartContract(&deployRequest) - if err != nil { - cmd.log.Error("Failed to deploy Smart contract, Token ", cmd.smartContractToken, "err", err) - return - } - msg, status := cmd.SignatureResponse(response) - if !status { - cmd.log.Error("Failed to deploy Smart contract, Token ", cmd.smartContractToken, "msg", msg) - return - } - cmd.log.Info(msg) - cmd.log.Info("Smart Contract Deployed successfully") -} - -func (cmd *Command) executeSmartcontract() { - if cmd.smartContractToken == "" { - cmd.log.Info("smart contract token id cannot be empty") - fmt.Print("Enter SC Token Id : ") - _, err := fmt.Scan(&cmd.smartContractToken) - if err != nil { - cmd.log.Error("Failed to get SC Token ID") - return - } - } - - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.smartContractToken) - if len(cmd.smartContractToken) != 46 || !strings.HasPrefix(cmd.smartContractToken, "Qm") || !is_alphanumeric { - cmd.log.Error("Invalid smart contract token") - return - } - - is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.executorAddr) - if !strings.HasPrefix(cmd.executorAddr, "bafybmi") || len(cmd.executorAddr) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid executer DID") - return - } - if cmd.transType < 1 || cmd.transType > 2 { - cmd.log.Error("Invalid trans type") - return - } - if cmd.smartContractData == "" { - fmt.Print("Enter Data to be executed : ") - _, err := fmt.Scan(&cmd.smartContractData) - if err != nil { - cmd.log.Error("Failed to get data") - return - } - } - executorRequest := model.ExecuteSmartContractRequest{ - SmartContractToken: cmd.smartContractToken, - ExecutorAddress: cmd.executorAddr, - QuorumType: cmd.transType, - Comment: cmd.transComment, - SmartContractData: cmd.smartContractData, - } - response, err := cmd.c.ExecuteSmartContract(&executorRequest) - if err != nil { - cmd.log.Error("Failed to execute Smart contract, Token ", cmd.smartContractToken, "err", err) - return - } - msg, status := cmd.SignatureResponse(response) - if !status { - cmd.log.Error("Failed to execute Smart contract, Token ", cmd.smartContractToken, "msg", msg) - return - } - cmd.log.Info(msg) - cmd.log.Info("Smart Contract executed successfully") - -} diff --git a/command/smart_contract.go b/command/smart_contract.go new file mode 100644 index 00000000..77857b02 --- /dev/null +++ b/command/smart_contract.go @@ -0,0 +1,380 @@ +package command + +import ( + "fmt" + "regexp" + "strings" + + "github.com/rubixchain/rubixgoplatform/client" + "github.com/rubixchain/rubixgoplatform/core" + "github.com/rubixchain/rubixgoplatform/core/model" + "github.com/spf13/cobra" +) + +func generateSmartContractTokenCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "generate", + Short: "Generate a Smart Contract Token", + Long: "Generate a Smart Contract Token", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("DID cannot be empty") + fmt.Print("Enter DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get DID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + if cmdCfg.binaryCodePath == "" { + cmdCfg.log.Error("Please provide Binary code file") + return nil + } + if cmdCfg.rawCodePath == "" { + cmdCfg.log.Error("Please provide Raw code file") + return nil + } + if cmdCfg.schemaFilePath == "" { + cmdCfg.log.Error("Please provide Schema file") + return nil + } + + smartContractTokenRequest := core.GenerateSmartContractRequest{ + BinaryCode: cmdCfg.binaryCodePath, + RawCode: cmdCfg.rawCodePath, + SchemaCode: cmdCfg.schemaFilePath, + DID: cmdCfg.did, + } + + request := client.SmartContractRequest{ + BinaryCode: smartContractTokenRequest.BinaryCode, + RawCode: smartContractTokenRequest.RawCode, + SchemaCode: smartContractTokenRequest.SchemaCode, + DID: smartContractTokenRequest.DID, + } + + basicResponse, err := cmdCfg.c.GenerateSmartContractToken(&request) + if err != nil { + cmdCfg.log.Error("Failed to generate smart contract token", "err", err) + return nil + } + if !basicResponse.Status { + cmdCfg.log.Error("Failed to generate smart contract token", "err", err) + return nil + } + cmdCfg.log.Info("Smart contract token generated successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.binaryCodePath, "binCode", "", "WASM binary path") + cmd.Flags().StringVar(&cmdCfg.rawCodePath, "rawCode", "", "Smart Contract code path (usually lib.rs)") + cmd.Flags().StringVar(&cmdCfg.schemaFilePath, "schemaFile", "", "Schema file path") + + return cmd +} + +func fetchSmartContractCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "fetch", + Short: "Fetch a Smart Contract Token", + Long: "Fetch a Smart Contract Token", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + + smartContractTokenRequest := core.FetchSmartContractRequest{ + SmartContractToken: cmdCfg.smartContractToken, + } + + request := client.FetchSmartContractRequest{ + SmartContractToken: smartContractTokenRequest.SmartContractToken, + } + + basicResponse, err := cmdCfg.c.FetchSmartContract(&request) + if err != nil { + cmdCfg.log.Error("Failed to fetch smart contract token", "err", err) + return nil + } + if !basicResponse.Status { + cmdCfg.log.Error("Failed to fetch smart contract token", "err", err) + return nil + } + + cmdCfg.log.Info("Smart contract token fetched successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + + return cmd +} + +func publishContract(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "publish", + Short: "Publish a Smart Contract Token", + Long: "Publish a Smart Contract Token", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.did) + if !strings.HasPrefix(cmdCfg.did, "bafybmi") || len(cmdCfg.did) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid DID") + return nil + } + if cmdCfg.publishType < 1 || cmdCfg.publishType > 2 { + cmdCfg.log.Error("Invalid publish type") + return nil + } + + basicResponse, err := cmdCfg.c.PublishNewEvent( + cmdCfg.smartContractToken, + cmdCfg.did, + cmdCfg.publishType, + cmdCfg.newContractBlock, + ) + + if err != nil { + cmdCfg.log.Error("Failed to publish new event", "err", err) + return nil + } + if !basicResponse.Status { + cmdCfg.log.Error("Failed to publish new event", "msg", basicResponse.Message) + return nil + } + message, status := signatureResponse(cmdCfg, basicResponse) + + if !status { + cmdCfg.log.Error("Failed to publish new event, " + message) + return nil + } + + cmdCfg.log.Info("New event published successfully") + return nil + }, + } + + cmd.Flags().IntVar(&cmdCfg.publishType, "pubType", 0, "Smart contract event publishing type(Deploy & Execute)") + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + cmd.Flags().StringVar(&cmdCfg.newContractBlock, "sctBlockHash", "", "Contract block hash") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd +} + +func subscribeContract(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "subscribe", + Short: "Subscribe to a Smart Contract", + Long: "Subscribe to a Smart Contract", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + + basicResponse, err := cmdCfg.c.SubscribeContract(cmdCfg.smartContractToken) + + if err != nil { + cmdCfg.log.Error("Failed to subscribe contract", "err", err) + return nil + } + if !basicResponse.Status { + cmdCfg.log.Error("Failed to subscribe contract", "msg", basicResponse.Message) + return nil + } + message, status := signatureResponse(cmdCfg, basicResponse) + + if !status { + cmdCfg.log.Error("Failed to subscribe contract, " + message) + return nil + } + cmdCfg.log.Info("New event subscribed successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + + return cmd +} + +func deploySmartcontract(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a Smart Contract", + Long: "Deploy a Smart Contract", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.deployerAddr) + if !strings.HasPrefix(cmdCfg.deployerAddr, "bafybmi") || len(cmdCfg.deployerAddr) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid deployer DID") + return nil + } + if cmdCfg.rbtAmount < 0.00001 { + cmdCfg.log.Error("Invalid RBT amount. Minimum RBT amount should be 0.00001") + return nil + } + if cmdCfg.transType < 1 || cmdCfg.transType > 2 { + cmdCfg.log.Error("Invalid trans type") + return nil + } + + deployRequest := model.DeploySmartContractRequest{ + SmartContractToken: cmdCfg.smartContractToken, + DeployerAddress: cmdCfg.deployerAddr, + RBTAmount: cmdCfg.rbtAmount, + QuorumType: cmdCfg.transType, + Comment: cmdCfg.transComment, + } + response, err := cmdCfg.c.DeploySmartContract(&deployRequest) + if err != nil { + cmdCfg.log.Error("Failed to deploy Smart contract, Token ", cmdCfg.smartContractToken, "err", err) + return nil + } + msg, status := signatureResponse(cmdCfg, response) + if !status { + cmdCfg.log.Error("Failed to deploy Smart contract, Token ", cmdCfg.smartContractToken, "msg", msg) + return nil + } + cmdCfg.log.Info(msg) + cmdCfg.log.Info("Smart Contract Deployed successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.deployerAddr, "deployerAddr", "", "Smart contract Deployer Address") + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + cmd.Flags().Float64Var(&cmdCfg.rbtAmount, "rbtAmount", 0.0, "RBT amount") + cmd.Flags().StringVar(&cmdCfg.transComment, "transComment", "", "Transaction comment") + cmd.Flags().IntVar(&cmdCfg.transType, "transType", 2, "Transaction type") + + return cmd +} + +func executeSmartcontract(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "execute", + Short: "Execute a Smart Contract", + Long: "Execute a Smart Contract", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.smartContractToken == "" { + cmdCfg.log.Info("smart contract token id cannot be empty") + fmt.Print("Enter SC Token Id : ") + _, err := fmt.Scan(&cmdCfg.smartContractToken) + if err != nil { + cmdCfg.log.Error("Failed to get SC Token ID") + return nil + } + } + + is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.smartContractToken) + if len(cmdCfg.smartContractToken) != 46 || !strings.HasPrefix(cmdCfg.smartContractToken, "Qm") || !is_alphanumeric { + cmdCfg.log.Error("Invalid smart contract token") + return nil + } + + is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmdCfg.executorAddr) + if !strings.HasPrefix(cmdCfg.executorAddr, "bafybmi") || len(cmdCfg.executorAddr) != 59 || !is_alphanumeric { + cmdCfg.log.Error("Invalid executer DID") + return nil + } + if cmdCfg.transType < 1 || cmdCfg.transType > 2 { + cmdCfg.log.Error("Invalid trans type") + return nil + } + if cmdCfg.smartContractData == "" { + fmt.Print("Enter Data to be executed : ") + _, err := fmt.Scan(&cmdCfg.smartContractData) + if err != nil { + cmdCfg.log.Error("Failed to get data") + return nil + } + } + + executorRequest := model.ExecuteSmartContractRequest{ + SmartContractToken: cmdCfg.smartContractToken, + ExecutorAddress: cmdCfg.executorAddr, + QuorumType: cmdCfg.transType, + Comment: cmdCfg.transComment, + SmartContractData: cmdCfg.smartContractData, + } + response, err := cmdCfg.c.ExecuteSmartContract(&executorRequest) + if err != nil { + cmdCfg.log.Error("Failed to execute Smart contract, Token ", cmdCfg.smartContractToken, "err", err) + return nil + } + msg, status := signatureResponse(cmdCfg, response) + if !status { + cmdCfg.log.Error("Failed to execute Smart contract, Token ", cmdCfg.smartContractToken, "msg", msg) + return nil + } + cmdCfg.log.Info(msg) + cmdCfg.log.Info("Smart Contract executed successfully") + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.executorAddr, "executorAddr", "", "Smart contract Executor Address") + cmd.Flags().StringVar(&cmdCfg.smartContractToken, "sct", "", "Smart contract token hash") + cmd.Flags().Float64Var(&cmdCfg.rbtAmount, "rbtAmount", 0.0, "RBT amount") + cmd.Flags().StringVar(&cmdCfg.transComment, "transComment", "", "Transaction comment") + cmd.Flags().IntVar(&cmdCfg.transType, "transType", 2, "Transaction type") + + return cmd +} diff --git a/command/token.go b/command/token.go deleted file mode 100644 index 43ed856b..00000000 --- a/command/token.go +++ /dev/null @@ -1,48 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" -) - -func (cmd *Command) GenerateTestRBT() { - if cmd.did == "" { - cmd.log.Info("DID cannot be empty") - fmt.Print("Enter DID : ") - _, err := fmt.Scan(&cmd.did) - if err != nil { - cmd.log.Error("Failed to get DID") - return - } - } - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - if cmd.numTokens <= 0 { - cmd.log.Error("Invalid RBT amount, tokens generated should be a whole number and greater than 0") - return - } - - br, err := cmd.c.GenerateTestRBT(cmd.numTokens, cmd.did) - - if err != nil { - cmd.log.Error("Failed to generate RBT", "err", err) - return - } - - if !br.Status { - cmd.log.Error("Failed to generate RBT", "msg", br.Message) - return - } - - msg, status := cmd.SignatureResponse(br) - - if !status { - cmd.log.Error("Failed to generate test RBT, " + msg) - return - } - cmd.log.Info("Test RBT generated successfully") -} diff --git a/command/tokenstate.go b/command/tokenstate.go deleted file mode 100644 index d56a3e0b..00000000 --- a/command/tokenstate.go +++ /dev/null @@ -1,37 +0,0 @@ -package command - -import "fmt" - -func (cmd *Command) GetPledgedTokenDetails() { - info, err := cmd.c.GetPledgedTokenDetails() - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - fmt.Printf("Response : %v\n", info) - if !info.Status { - cmd.log.Error("Failed to get account info", "message", info.Message) - } else { - cmd.log.Info("Successfully got the pledged token states info") - fmt.Println("DID ", "Pledged Token ", "Token State") - for _, i := range info.PledgedTokenStateDetails { - fmt.Println(i.DID, " ", i.TokensPledged, " ", i.TokenStateHash) - } - } -} - -//command will take token hash, check for ipfs pinning, if no, ignore, if yes, get token detail, unpledge. - -func (cmd *Command) CheckPinnedState() { - info, err := cmd.c.GetPinnedInfo(cmd.TokenState) - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - fmt.Printf("Response : %v\n", info) - if !info.Status { - cmd.log.Debug("Pin not available", "message", info.Message) - } else { - cmd.log.Info("Token State is Pinned") - } -} diff --git a/command/transfer.go b/command/transfer.go deleted file mode 100644 index 5693c173..00000000 --- a/command/transfer.go +++ /dev/null @@ -1,112 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" - - "github.com/rubixchain/rubixgoplatform/core/model" -) - -func (cmd *Command) TransferRBT() { - if cmd.senderAddr == "" { - cmd.log.Info("Sender address cannot be empty") - fmt.Print("Enter Sender DID : ") - _, err := fmt.Scan(&cmd.senderAddr) - if err != nil { - cmd.log.Error("Failed to get Sender DID") - return - } - } - if cmd.receiverAddr == "" { - cmd.log.Info("Receiver address cannot be empty") - fmt.Print("Enter Receiver DID : ") - _, err := fmt.Scan(&cmd.receiverAddr) - if err != nil { - cmd.log.Error("Failed to get Receiver DID") - return - } - } - is_alphanumeric_sender := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - is_alphanumeric_receiver := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !is_alphanumeric_sender || !is_alphanumeric_receiver { - cmd.log.Error("Invalid sender or receiver address. Please provide valid DID") - return - } - if !strings.HasPrefix(cmd.senderAddr, "bafybmi") || len(cmd.senderAddr) != 59 || !strings.HasPrefix(cmd.receiverAddr, "bafybmi") || len(cmd.receiverAddr) != 59 { - cmd.log.Error("Invalid sender or receiver DID") - return - } - if cmd.rbtAmount < 0.00001 { - cmd.log.Error("Invalid RBT amount. RBT amount should be atlease 0.00001") - return - } - if cmd.transType < 1 || cmd.transType > 2 { - cmd.log.Error("Invalid trans type. TransType should be 1 or 2") - return - } - rt := model.RBTTransferRequest{ - Receiver: cmd.receiverAddr, - Sender: cmd.senderAddr, - TokenCount: cmd.rbtAmount, - Type: cmd.transType, - Comment: cmd.transComment, - } - - br, err := cmd.c.TransferRBT(&rt) - if err != nil { - cmd.log.Error("Failed RBT transfer", "err", err) - return - } - msg, status := cmd.SignatureResponse(br) - if !status { - cmd.log.Error("Failed to trasnfer RBT", "msg", msg) - return - } - cmd.log.Info(msg) - cmd.log.Info("RBT transfered successfully") -} - -func (cmd *Command) PinRBT() { - rt := model.RBTPinRequest{ - PinningNode: cmd.pinningAddress, - Sender: cmd.senderAddr, - TokenCount: cmd.rbtAmount, - Type: cmd.transType, - Comment: cmd.transComment, - } - - br, err := cmd.c.PinRBT(&rt) - if err != nil { - cmd.log.Error("Failed to Pin the Token", "err", err) - return - } - msg, status := cmd.SignatureResponse(br) - if !status { - cmd.log.Error("Failed to Pin RBT", "msg", msg) - return - } - cmd.log.Info(msg) - cmd.log.Info("RBT Pinned successfully") -} - -func (cmd *Command) SelfTransferRBT() { - rt := model.RBTTransferRequest{ - Sender: cmd.senderAddr, - Receiver: cmd.senderAddr, - Type: cmd.transType, - } - - br, err := cmd.c.TransferRBT(&rt) - if err != nil { - cmd.log.Error("Failed to self RBT transfer", "err", err) - return - } - msg, status := cmd.SignatureResponse(br) - if !status { - cmd.log.Error("Failed to self transfer RBT", "msg", msg) - return - } - cmd.log.Info(msg) - cmd.log.Info("Self RBT transfer successful") -} diff --git a/command/tx.go b/command/tx.go new file mode 100644 index 00000000..a398af44 --- /dev/null +++ b/command/tx.go @@ -0,0 +1,146 @@ +package command + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func txCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "transaction related subcommands (RBT, Smart Contract)", + Long: "transaction related subcommands (RBT, Smart Contract)", + } + + cmd.AddCommand( + getTxnDetails(cmdCfg), + txTokenCommandGroup(cmdCfg), + txSmartContractCommandGroup(cmdCfg), + txDataTokenCommandGroup(cmdCfg), + nftCommandGroup(cmdCfg), + ) + + return cmd +} + +func txTokenCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "rbt", + Short: "RBT related subcommands", + Long: "RBT related subcommands", + } + + cmd.AddCommand( + transferRBTCmd(cmdCfg), + generateTestRBTCmd(cmdCfg), + selfTransferRBTCmd(cmdCfg), + ) + + return cmd +} + +func txSmartContractCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "smart-contract", + Short: "Smart Contract related subcommands", + Long: "Smart Contract related subcommands", + } + + cmd.AddCommand( + generateSmartContractTokenCmd(cmdCfg), + fetchSmartContractCmd(cmdCfg), + publishContract(cmdCfg), + subscribeContract(cmdCfg), + deploySmartcontract(cmdCfg), + executeSmartcontract(cmdCfg), + ) + + return cmd +} + +// DEPRECATED +func txDataTokenCommandGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "data-token", + Short: "(DEPRECATED) Data Token related subcommands", + Long: "(DEPRECATED) Data Token related subcommands", + } + + cmd.AddCommand( + createDataToken(cmdCfg), + commitDataToken(cmdCfg), + ) + + return cmd +} + +func getTxnDetails(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "tx-details", + Short: "Get transaction details", + Long: "Get transaction details", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" || cmdCfg.txnID == "" || cmdCfg.transComment == "" { + cmdCfg.log.Error("Please provide did or transaction id or transaction comment to get transaction details") + return nil + } + + if cmdCfg.txnID != "" { + res, err := cmdCfg.c.GetTxnByID(cmdCfg.txnID) + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return nil + } + if !res.BasicResponse.Status { + cmdCfg.log.Error("Failed to get Txn details for TxnID", cmdCfg.txnID, " err", err) + return nil + } + for i := range res.TxnDetails { + td := res.TxnDetails[i] + fmt.Printf("%+v", td) + } + } + + if cmdCfg.did != "" { + res, err := cmdCfg.c.GetTxnByDID(cmdCfg.did, cmdCfg.role) + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return nil + } + if !res.BasicResponse.Status { + cmdCfg.log.Error("Failed to get Txn details for Did", cmdCfg.did, " err", err) + return nil + } + for i := range res.TxnDetails { + td := res.TxnDetails[i] + fmt.Printf("%+v", td) + } + } + + if cmdCfg.transComment != "" { + res, err := cmdCfg.c.GetTxnByComment(cmdCfg.transComment) + if err != nil { + cmdCfg.log.Error("Invalid response from the node", "err", err) + return nil + } + if !res.BasicResponse.Status { + cmdCfg.log.Error("Failed to get Txn details for comment", cmdCfg.transComment, " err", err) + return nil + } + for i := range res.TxnDetails { + td := res.TxnDetails[i] + fmt.Printf("%+v", td) + } + } + return nil + }, + } + + cmd.Flags().StringVar(&cmdCfg.txnID, "txnID", "", "Transaction ID") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + cmd.Flags().StringVar(&cmdCfg.role, "role", "", "Sender/Receiver") + cmd.Flags().StringVar(&cmdCfg.transComment, "transComment", "", "Transaction comment") + + return cmd +} diff --git a/command/txndetails.go b/command/txndetails.go deleted file mode 100644 index 9d0495ac..00000000 --- a/command/txndetails.go +++ /dev/null @@ -1,64 +0,0 @@ -package command - -import ( - "fmt" - "regexp" - "strings" -) - -func (cmd *Command) getTxnDetails() { - if cmd.did == "" && cmd.txnID == "" && cmd.transComment == "" { - cmd.log.Error("Please provide did or transaction id or transaction comment to get transaction details") - return - } - - if cmd.txnID != "" { - res, err := cmd.c.GetTxnByID(cmd.txnID) - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - if !res.BasicResponse.Status { - cmd.log.Error("Failed to get Txn details for TxnID", cmd.txnID, " err", err) - } - for i := range res.TxnDetails { - td := res.TxnDetails[i] - fmt.Printf("%+v", td) - } - } - - if cmd.did != "" { - is_alphanumeric := regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cmd.did) - if !strings.HasPrefix(cmd.did, "bafybmi") || len(cmd.did) != 59 || !is_alphanumeric { - cmd.log.Error("Invalid DID") - return - } - res, err := cmd.c.GetTxnByDID(cmd.did, cmd.role) - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - if !res.BasicResponse.Status { - cmd.log.Error("Failed to get Txn details for Did", cmd.did, " err", err) - } - for i := range res.TxnDetails { - td := res.TxnDetails[i] - fmt.Printf("%+v", td) - } - } - - if cmd.transComment != "" { - res, err := cmd.c.GetTxnByComment(cmd.transComment) - if err != nil { - cmd.log.Error("Invalid response from the node", "err", err) - return - } - if !res.BasicResponse.Status { - cmd.log.Error("Failed to get Txn details for comment", cmd.transComment, " err", err) - } - for i := range res.TxnDetails { - td := res.TxnDetails[i] - fmt.Printf("%+v", td) - } - } -} diff --git a/command/unpledge.go b/command/unpledge.go deleted file mode 100644 index f4e916fc..00000000 --- a/command/unpledge.go +++ /dev/null @@ -1,24 +0,0 @@ -package command - -func (cmd *Command) RunUnpledge() { - msg, status := cmd.c.RunUnpledge() - cmd.log.Info("Unpledging of pledged tokens has started") - if !status { - - cmd.log.Error(msg) - return - } - - cmd.log.Info(msg) -} - -func (cmd *Command) UnpledgePOWBasedPledgedTokens() { - cmd.log.Info("Unpledging of POW-based pledged tokens has started") - msg, status := cmd.c.UnpledgePOWBasedPledgedTokens() - if !status { - cmd.log.Error(msg) - return - } - - cmd.log.Info(msg) -} diff --git a/command/upgrade.go b/command/upgrade.go new file mode 100644 index 00000000..1c165223 --- /dev/null +++ b/command/upgrade.go @@ -0,0 +1,42 @@ +package command + +import ( + "errors" + + "github.com/spf13/cobra" +) + +func upgradeGroup(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade", + Short: "Upgrade related subcommands", + Long: "Upgrade related subcommands", + } + + cmd.AddCommand( + unpledgePOWBasedPledgedTokensCmd(cmdCfg), + ) + + return cmd +} + +func unpledgePOWBasedPledgedTokensCmd(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "unpledge-pow-tokens", + Long: "Unpledge any pledge tokens which were pledged as part of PoW based pledging", + Short: "Unpledge any pledge tokens which were pledged as part of PoW based pledging", + RunE: func(cmd *cobra.Command, args []string) error { + cmdCfg.log.Info("Unpledging of POW-based pledged tokens has started") + msg, status := cmdCfg.c.UnpledgePOWBasedPledgedTokens() + if !status { + cmdCfg.log.Error(msg) + return errors.New(msg) + } + + cmdCfg.log.Info(msg) + return nil + }, + } + + return cmd +} \ No newline at end of file diff --git a/command/validate.go b/command/validate.go new file mode 100644 index 00000000..6f04806f --- /dev/null +++ b/command/validate.go @@ -0,0 +1,47 @@ +package command + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func validateCommand(cmdCfg *CommandConfig) *cobra.Command { + cmd := &cobra.Command{ + Use: "validate-chain", + Short: "Validate Token or Smart Contract chain", + Long: "Validate Token or Smart Contract chain", + RunE: func(cmd *cobra.Command, args []string) error { + if cmdCfg.did == "" { + cmdCfg.log.Info("Tokenchain-validator did cannot be empty") + fmt.Print("Enter tokenchain-validator DID : ") + _, err := fmt.Scan(&cmdCfg.did) + if err != nil { + cmdCfg.log.Error("Failed to get tokenchain-validator DID") + return nil + } + } + + br, err := cmdCfg.c.ValidateTokenchain(cmdCfg.did, cmdCfg.smartContractChainValidation, cmdCfg.token, cmdCfg.blockCount) + if err != nil { + cmdCfg.log.Error("failed to validate token chain", "err", err) + return nil + } + + if !br.Status { + cmdCfg.log.Error("failed to validate token chain", "msg", br.Message) + return nil + } + + cmdCfg.log.Info("Tokenchain validated successfully", "msg", br.Message) + return nil + }, + } + + cmd.Flags().IntVar(&cmdCfg.blockCount, "blockCount", 0, "Number of blocks of the tokenchain to validate") + cmd.Flags().BoolVar(&cmdCfg.smartContractChainValidation, "sctValidation", false, "Validate smart contract token chain") + cmd.Flags().StringVar(&cmdCfg.token, "tokenHash", "", "Token Hash") + cmd.Flags().StringVar(&cmdCfg.did, "did", "", "DID") + + return cmd +} diff --git a/command/version.go b/command/version.go new file mode 100644 index 00000000..73966edb --- /dev/null +++ b/command/version.go @@ -0,0 +1,28 @@ +package command + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +const ( + version = "0.0.17" +) + +func versionCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "version", + Short: "Rubix version", + Long: "Rubix version", + RunE: func(cmd *cobra.Command, args []string) error { + _, err := fmt.Fprintln(cmd.OutOrStdout(), version) + if err != nil { + return fmt.Errorf("failed to fetch Rubix version, err: %v", err.Error()) + } + return nil + }, + } + + return cmd +} \ No newline at end of file diff --git a/core/core.go b/core/core.go index eb95a07d..e64831c1 100644 --- a/core/core.go +++ b/core/core.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net" "os" + "path" "sync" "time" @@ -54,6 +55,7 @@ const ( APISelfTransfer string = "/api/self-transfer" APIRecoverPinnedRBT string = "/api/recover-pinned-rbt" APIRequestSigningHash string = "/api/request-signing-hash" + APILockInvalidToken string = "/api/lock-invalid-token" ) const ( @@ -155,14 +157,14 @@ func NewCore(cfg *config.Config, cfgFile string, encKey string, log logger.Logge update := false if cfg.CfgData.StorageConfig.StorageType == 0 { cfg.CfgData.StorageConfig.StorageType = storage.StorageDBType - cfg.CfgData.StorageConfig.DBAddress = cfg.DirPath + RubixRootDir + DefaultMainNetDB + cfg.CfgData.StorageConfig.DBAddress = path.Join(cfg.DirPath, RubixRootDir, DefaultMainNetDB) cfg.CfgData.StorageConfig.DBType = "Sqlite3" update = true } if cfg.CfgData.TestStorageConfig.StorageType == 0 { cfg.CfgData.TestStorageConfig.StorageType = storage.StorageDBType - cfg.CfgData.TestStorageConfig.DBAddress = cfg.DirPath + RubixRootDir + DefaultTestNetDB + cfg.CfgData.TestStorageConfig.DBAddress = path.Join(cfg.DirPath, RubixRootDir, DefaultTestNetDB) cfg.CfgData.TestStorageConfig.DBType = "Sqlite3" update = true } @@ -182,9 +184,9 @@ func NewCore(cfg *config.Config, cfgFile string, encKey string, log logger.Logge arbitaryMode: am, secret: util.GetRandBytes(32), } - c.didDir = c.cfg.DirPath + RubixRootDir + c.didDir = path.Join(c.cfg.DirPath, RubixRootDir) if c.testNet { - c.didDir = c.cfg.DirPath + RubixRootDir + TestNetDIDDir + c.didDir = path.Join(c.cfg.DirPath, RubixRootDir, TestNetDIDDir) } if _, err := os.Stat(c.didDir); os.IsNotExist(err) { @@ -207,23 +209,23 @@ func NewCore(cfg *config.Config, cfgFile string, encKey string, log logger.Logge if update { c.updateConfig() } - if _, err := os.Stat(cfg.DirPath + RubixRootDir + MainNetDir); os.IsNotExist(err) { - err := os.MkdirAll(cfg.DirPath+RubixRootDir+MainNetDir, os.ModeDir|os.ModePerm) + if _, err := os.Stat(path.Join(cfg.DirPath, RubixRootDir, MainNetDir)); os.IsNotExist(err) { + err := os.MkdirAll(path.Join(cfg.DirPath, RubixRootDir, MainNetDir), os.ModeDir|os.ModePerm) if err != nil { c.log.Error("Failed to create main net directory", "err", err) return nil, err } } - tcDir := cfg.DirPath + RubixRootDir + MainNetDir + "/" + tcDir := path.Join(cfg.DirPath, RubixRootDir, MainNetDir) if testNet { - if _, err := os.Stat(cfg.DirPath + RubixRootDir + TestNetDir); os.IsNotExist(err) { - err := os.MkdirAll(cfg.DirPath+RubixRootDir+TestNetDir, os.ModeDir|os.ModePerm) + if _, err := os.Stat(path.Join(cfg.DirPath, RubixRootDir, TestNetDir)); os.IsNotExist(err) { + err := os.MkdirAll(path.Join(cfg.DirPath, RubixRootDir, TestNetDir), os.ModeDir|os.ModePerm) if err != nil { c.log.Error("Failed to create test net directory", "err", err) return nil, err } } - tcDir = cfg.DirPath + RubixRootDir + TestNetDir + "/" + tcDir = path.Join(cfg.DirPath, RubixRootDir, TestNetDir) } sc := cfg.CfgData.StorageConfig @@ -405,20 +407,20 @@ func (c *Core) StopCore() { } func (c *Core) CreateTempFolder() (string, error) { - folderName := c.cfg.DirPath + "temp/" + uuid.New().String() + folderName := path.Join(c.cfg.DirPath, "temp", uuid.New().String()) err := os.MkdirAll(folderName, os.ModeDir|os.ModePerm) return folderName, err } func (c *Core) CreateSCTempFolder() (string, error) { - folderName := c.cfg.DirPath + "SmartContract/" + uuid.New().String() + folderName := path.Join(c.cfg.DirPath, "SmartContract", uuid.New().String()) err := os.MkdirAll(folderName, os.ModeDir|os.ModePerm) return folderName, err } func (c *Core) RenameSCFolder(tempFolderPath string, smartContractName string) (string, error) { - scFolderName := c.cfg.DirPath + "SmartContract/" + smartContractName + scFolderName := path.Join(c.cfg.DirPath, "SmartContract", smartContractName) err := os.Rename(tempFolderPath, scFolderName) if err != nil { c.log.Error("Unable to rename ", tempFolderPath, " to ", scFolderName, "error ", err) @@ -606,20 +608,21 @@ func (c *Core) SetupForienDIDQuorum(didStr string, self_did string) (did.DIDCryp } func (c *Core) FetchDID(did string) error { - _, err := os.Stat(c.didDir + did) + didPath := path.Join(c.didDir, did) + _, err := os.Stat(didPath) if err != nil { - err = os.MkdirAll(c.didDir+did, os.ModeDir|os.ModePerm) + err = os.MkdirAll(didPath, os.ModeDir|os.ModePerm) if err != nil { c.log.Error("failed to create directory", "err", err) return err } - err = c.ipfs.Get(did, c.didDir+did+"/") + err = c.ipfs.Get(did, didPath) if err == nil { - _, e := os.Stat(c.didDir + did + "/" + didm.MasterDIDFileName) + _, e := os.Stat(path.Join(didPath, didm.MasterDIDFileName)) // Fetch the master DID also if e == nil { var rb []byte - rb, err = ioutil.ReadFile(c.didDir + did + "/" + didm.MasterDIDFileName) + rb, err = ioutil.ReadFile(path.Join(didPath, didm.MasterDIDFileName)) if err == nil { return c.FetchDID(string(rb)) } diff --git a/core/ipfs.go b/core/ipfs.go index aae3b421..9448f90a 100644 --- a/core/ipfs.go +++ b/core/ipfs.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "os/exec" + "path" "runtime" "strings" "time" @@ -188,9 +189,10 @@ func (c *Core) runIPFS() { // RunIPFS will run the IPFS daemon func (c *Core) RunIPFS() error { - os.Setenv("IPFS_PATH", c.cfg.DirPath+".ipfs") + ipfsConfigBasePath := path.Join(c.cfg.DirPath, ".ipfs") + os.Setenv("IPFS_PATH", ipfsConfigBasePath) os.Setenv("LIBP2P_FORCE_PNET", "1") - err := c.initIPFS(c.cfg.DirPath + ".ipfs") + err := c.initIPFS(ipfsConfigBasePath) if err != nil { c.log.Error("failed to initialize IPFS", "err", err) return err diff --git a/core/ping.go b/core/ping.go index eebfb071..b948d811 100644 --- a/core/ping.go +++ b/core/ping.go @@ -9,6 +9,7 @@ import ( "github.com/rubixchain/rubixgoplatform/core/ipfsport" "github.com/rubixchain/rubixgoplatform/core/model" "github.com/rubixchain/rubixgoplatform/core/wallet" + "github.com/rubixchain/rubixgoplatform/token" "github.com/rubixchain/rubixgoplatform/wrapper/ensweb" ) @@ -31,6 +32,7 @@ type GetPeerInfoResponse struct { func (c *Core) PingSetup() { c.l.AddRoute(APIPingPath, "GET", c.PingRecevied) c.l.AddRoute(APIGetPeerInfoPath, "GET", c.GetPeerInfoResponse) + c.l.AddRoute(APILockInvalidToken, "POST", c.LockInvalidTokenResponse) } // CheckQuorumStatusSetup will setup the ping route @@ -235,3 +237,104 @@ func (c *Core) GetPeerInfo(p *ipfsport.Peer, peerDID string) (GetPeerInfoRespons err := p.SendJSONRequest("GET", APIGetPeerInfoPath, q, nil, &response, false) return response, err } + +// LockInvalidTokenResponse is the handler for LockInvalidToken request +func (c *Core) LockInvalidTokenResponse(req *ensweb.Request) *ensweb.Result { //PingRecevied + resp := &model.BasicResponse{ + Status: false, + } + + did := c.l.GetQuerry(req, "did") + //exctract token Id and token type from the map - m + var m map[string]string + err := c.l.ParseJSON(req, &m) + if err != nil { + c.log.Error("Failed to parse json request", "err", err) + resp.Message = "Failed to parse json request" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + //exctract token Id + tokenId, ok := m["token"] + if !ok { + c.log.Error("Missing old did value") + resp.Message = "Missing old did value" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + //exctract token type + token_type_str, ok := m["token_type"] + if !ok { + c.log.Error("Missing new did value") + resp.Message = "Missing new did value" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + token_type, err := strconv.Atoi(token_type_str) + if err != nil { + resp.Message = "failed to retrieve token type" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + if token_type == token.SmartContractTokenType { + token_info, err := c.w.GetSmartContractToken(tokenId) + if err != nil { + resp.Message = "failed to retrieve token details. inValid token" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + sctoken := wallet.SmartContract{} + for i := range token_info { + if token_info[i].Deployer == did { + sctoken = token_info[i] + break + } + } + if sctoken.ContractStatus != wallet.TokenIsDeployed { + c.log.Error("Smart contract is not in deployed state, can not lock") + resp.Message = "Smart contract is not in deployed state, can't lock" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + err = c.w.LockSmartContract(&sctoken) + if err != nil { + resp.Message = "failed to lock invalid smart contract" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + resp.Message = "Smart contract token locked successfully" + + } else { //token transferred or pledged/unpledged types + token_info, err := c.w.ReadToken(tokenId) + if err != nil { + resp.Message = "failed to retrieve token details. inValid token" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + if token_info.DID != did || token_info.TokenStatus != wallet.TokenIsFree { + c.log.Error("Not token owner, can not lock token") + resp.Message = "Not token owner, can't lock token" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + err = c.w.LockToken(token_info) + if err != nil { + resp.Message = "failed to lock invalid token" + return c.l.RenderJSON(req, &resp, http.StatusOK) + } + resp.Message = "Token locked successfully" + } + + resp.Status = true + return c.l.RenderJSON(req, &resp, http.StatusOK) + +} + +func (c *Core) LockInvalidToken(tokenId string, tokenType int, user_did string) (*model.BasicResponse, error) { + var resp model.BasicResponse + p, err := c.pm.OpenPeerConn(c.peerID, user_did, c.getCoreAppName(c.peerID)) + if err != nil { + resp.Message = "Self-peer Connection Error" + resp.Status = false + return &resp, err + } + m := make(map[string]string) + m["token"] = tokenId + m["token_type"] = strconv.Itoa(tokenType) + err = p.SendJSONRequest("POST", APILockInvalidToken, nil, &m, &resp, true) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/core/smart_contract.go b/core/smart_contract.go index 5cf16151..064850f9 100644 --- a/core/smart_contract.go +++ b/core/smart_contract.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "net/http" "os" + "path" "path/filepath" "github.com/rubixchain/rubixgoplatform/core/model" @@ -370,7 +371,7 @@ func (c *Core) ContractCallBack(peerID string, topic string, data []byte) { c.log.Info("Smart contract " + fetchSC.SmartContractToken + " files fetching succesful") } smartContractToken := newEvent.SmartContractToken - scFolderPath := c.cfg.DirPath + "SmartContract/" + smartContractToken + scFolderPath := path.Join(c.cfg.DirPath, "SmartContract/", smartContractToken) if _, err := os.Stat(scFolderPath); os.IsNotExist(err) { fetchSC.SmartContractToken = smartContractToken fetchSC.SmartContractTokenPath, err = c.CreateSCTempFolder() diff --git a/core/smartcontract_tokenchain_validation.go b/core/smartcontract_tokenchain_validation.go new file mode 100644 index 00000000..54028fb5 --- /dev/null +++ b/core/smartcontract_tokenchain_validation.go @@ -0,0 +1,306 @@ +package core + +import ( + "fmt" + + "github.com/rubixchain/rubixgoplatform/block" + "github.com/rubixchain/rubixgoplatform/core/model" + "github.com/rubixchain/rubixgoplatform/core/wallet" + "github.com/rubixchain/rubixgoplatform/did" + "github.com/rubixchain/rubixgoplatform/util" +) + +func (c *Core) SmartContractTokenChainValidation(user_did string, tokenId string, blockCount int) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + ok := c.w.IsDIDExist(user_did) + if !ok { + response.Message = "Invalid did" + return response, fmt.Errorf("invalid did: %v", user_did) + } + + if tokenId == "" { //if provided the boolean flag 'allmyToken', all the tokens' chain from tokens table will be validated + c.log.Info("Validating all smart contracts from your smart contract table") + tokens_list, err := c.w.GetSmartContractTokenByDeployer(user_did) + if err != nil { + response.Message = "failed to fetch all smart contract tokens" + return response, err + } + //Validate smart contract tokenchain for each smart contrtact in the smart contract table + for _, token_info := range tokens_list { + //Get token type + type_string := SmartContractString + token_type := c.TokenType(type_string) + + response, err = c.ValidateSmartContractTokenChain(user_did, token_info, token_type, blockCount) + if err != nil || !response.Status { + c.log.Error("token chain validation failed for token:", token_info.SmartContractHash, "\nError :", err, "\nmsg:", response.Message) + if token_info.ContractStatus == wallet.TokenIsFree { + //if token chain validation failed and the validator is the current owner of the token, + //then lock the token + response, err = c.LockInvalidToken(token_info.SmartContractHash, token_type, user_did) + if err != nil { + c.log.Error(response.Message, token_info.SmartContractHash) + return response, err + } + c.log.Info(response.Message, token_info.SmartContractHash) + } + } + } + + } else { + //Fetch token information + token_info, err := c.w.GetSmartContractToken(tokenId) + if err != nil { + response.Message = "Failed to get smart contract token, smart contract does not exist" + return response, err + } + //Get token type + type_string := SmartContractString + token_type := c.TokenType(type_string) + //Validate tokenchain for the provided token + response, err = c.ValidateSmartContractTokenChain(user_did, token_info[0], token_type, blockCount) + if err != nil || !response.Status { + c.log.Error("token chain validation failed for token:", tokenId, "Error :", err, "msg:", response.Message) + if token_info[0].ContractStatus == wallet.TokenIsDeployed { + response, err1 := c.LockInvalidToken(tokenId, token_type, user_did) + if err1 != nil { + c.log.Error(response.Message, tokenId) + return response, err1 + } + c.log.Info(response.Message, tokenId) + return response, err + } + return response, err + } + } + return response, nil +} + +// Validates tokenchain for the given token upto the specified block height +func (c *Core) ValidateSmartContractTokenChain(user_did string, token_info wallet.SmartContract, token_type int, blockCount int) (*model.BasicResponse, error) { + c.log.Info("validating smart copntract tokenchain", token_info.SmartContractHash) + response := &model.BasicResponse{ + Status: false, + } + + validated_block_count := 0 + blockId := "" + + var blocks [][]byte + var prevBlockId string + var nextBlockID string + var err error + + //This for loop ensures that we fetch all the blocks in the token chain + //starting from genesis block to latest block + for { + //GetAllTokenBlocks returns next 100 blocks and nextBlockID of the 100th block, + //starting from the given block Id, in the direction: genesis to latest block + blocks, nextBlockID, err = c.w.GetAllTokenBlocks(token_info.SmartContractHash, token_type, blockId) + if err != nil { + response.Message = "Failed to get token chain block" + return response, err + } + //the nextBlockID of the latest block is empty string + blockId = nextBlockID + if nextBlockID == "" { + break + } + } + + c.log.Info("token chain length", len(blocks)) + for i := len(blocks) - 1; i >= 0; i-- { + b := block.InitBlock(blocks[i], nil) + //validated_block_count keeps count of the number of blocks validated, including failed blocks + validated_block_count++ + + if b != nil { + //calculate block height + block_height, err := b.GetBlockNumber(token_info.SmartContractHash) + if err != nil { + response.Message = "failed to fetch BlockNumber" + return response, fmt.Errorf("invalid token chain block") + } + + c.log.Info("validating at block height:", block_height) + + //fetch transaction type to validate the block accordingly + txn_type := b.GetTransType() + switch txn_type { + case block.TokenDeployedType: + prevBlockId := "" + //validate smart contract deployed block + response, err = c.Validate_SC_Block(b, token_info.SmartContractHash, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenExecutedType: + //calculate previous block Id + prevBlock := block.InitBlock(blocks[i-1], nil) + prevBlockId, err = prevBlock.GetBlockID(token_info.SmartContractHash) + if err != nil { + c.log.Error("invalid previous block") + continue + } + //validate smart contract executed block + response, err = c.Validate_SC_Block(b, token_info.SmartContractHash, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + default: + prevBlockId := "" + //validate smart contract deployed block + response, err = c.Validate_SC_Block(b, token_info.SmartContractHash, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + } + + } else { + c.log.Error("Invalid block") + } + + c.log.Info("validated_block_count", validated_block_count) + // //If blockCount is provided, then we will stop validating when we reach the blockCount + // //If blockCount is not provided,i.e., is 0, then it will never be equal to validated_block_count + // //and thus will be continued till genesis block + if validated_block_count == blockCount { + break + } + } + + //Get latest block in the token chain + latestBlock := c.w.GetLatestTokenBlock(token_info.SmartContractHash, token_type) + + //Verify if the token is pinned only by the current owner aka receiver in the latest block + response, err = c.CurrentOwnerPinCheck(latestBlock, token_info.SmartContractHash, user_did) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + + //verify if the current token state is pinned by the quorums in the latest block + response, err = c.CurrentQuorumStatePinCheck(latestBlock, token_info.SmartContractHash, token_type, user_did) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + + c.log.Info("token chain validated successfully") + response.Message = "token chain validated successfully" + response.Status = true + return response, nil +} + +// validate block of type: TokenTransferredType = "02" / TokenDeployedType = "09" / TokenExecutedType = "10" +func (c *Core) Validate_SC_Block(b *block.Block, tokenId string, calculated_prevBlockId string, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{} + + //Validate block hash + response, err := c.ValidateBlockHash(b, tokenId, calculated_prevBlockId) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + //Validate sender signature + response, err = c.ValidateTxnInitiator(b) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + //validate quorums signature + response, err = c.ValidateQuorums(b, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + response.Status = true + if b.GetTransType() == block.TokenDeployedType { //smart contract deployed mode + response.Message = "smart contract deployed block validated successfully" + c.log.Debug("successfully validated smart contract deployed block") + // return response, nil + } else { //smart contract executed mode + response.Message = "smart contract executed block validated successfully" + c.log.Debug("successfully validated smart contract executed block") + // return response, nil + } + return response, nil +} + +// Deployer/Executor signature verification in a (non-genesis)block +func (c *Core) ValidateTxnInitiator(b *block.Block) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + var initiator string + txn_type := b.GetTransType() + if txn_type == block.TokenDeployedType { + initiator = b.GetDeployerDID() + } else if txn_type == block.TokenExecutedType { + initiator = b.GetExecutorDID() + } else { + c.log.Info("Failed to identify transaction type, transaction initiated with old executable") + response.Message = "Failed to identify transaction type" + return response, nil + } + + initiator_sign := b.GetInitiatorSignature() + //check if it is a block addded to chain before adding initiator signature to block structure + if initiator_sign == nil { + c.log.Info("old block, initiator signature not found") + response.Message = "old block, initiator signature not found" + return response, nil + } else if initiator_sign.DID != initiator { + c.log.Info("invalid initiator, initiator did does not match") + response.Message = "invalid initiator, initiator did does not match" + return response, fmt.Errorf("invalid initiator, initiator did does not match") + } + + var initiator_didType int + //sign type = 0, means it is a BIP signature and the did was created in light mode + //sign type = 1, means it is an NLSS-based signature and the did was created using NLSS scheme + //and thus the did could be initialised in basic mode to fetch the public key + if initiator_sign.SignType == 0 { + initiator_didType = did.LiteDIDMode + } else { + initiator_didType = did.BasicDIDMode + } + + //Initialise initiator did + didCrypto, err := c.InitialiseDID(initiator, initiator_didType) + if err != nil { + c.log.Error("failed to initialise initiator did:", initiator) + response.Message = "failed to initialise initiator did" + return response, err + } + + //initiator signature verification + if initiator_didType == did.LiteDIDMode { + response.Status, err = didCrypto.PvtVerify([]byte(initiator_sign.Hash), util.StrToHex(initiator_sign.Private_sign)) + if err != nil { + c.log.Error("failed to verify initiator:", initiator, "err", err) + response.Message = "invalid initiator" + return response, err + } + } else { + response.Status, err = didCrypto.NlssVerify(initiator_sign.Hash, util.StrToHex(initiator_sign.NLSS_share), util.StrToHex(initiator_sign.Private_sign)) + if err != nil { + c.log.Error("failed to verify initiator:", initiator, "err", err) + response.Message = "invalid initiator" + return response, err + } + } + + response.Message = "initiator validated successfully" + c.log.Debug("initiator (deployer/executor) validated successfully") + return response, nil +} diff --git a/core/token_chain_validation.go b/core/token_chain_validation.go new file mode 100644 index 00000000..c9bce4de --- /dev/null +++ b/core/token_chain_validation.go @@ -0,0 +1,741 @@ +package core + +import ( + "fmt" + "sync" + + "github.com/rubixchain/rubixgoplatform/block" + "github.com/rubixchain/rubixgoplatform/core/model" + "github.com/rubixchain/rubixgoplatform/core/wallet" + "github.com/rubixchain/rubixgoplatform/did" + "github.com/rubixchain/rubixgoplatform/rac" + "github.com/rubixchain/rubixgoplatform/token" + "github.com/rubixchain/rubixgoplatform/util" +) + +func (c *Core) TokenChainValidation(user_did string, tokenId string, blockCount int) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + ok := c.w.IsDIDExist(user_did) + if !ok { + response.Message = "Invalid did" + return response, fmt.Errorf("invalid did: %v", user_did) + } + + if tokenId == "" { //if provided the boolean flag 'allmyToken', all the tokens' chain from tokens table will be validated + c.log.Info("Validating all tokens from your tokens table") + tokens_list, err := c.w.GetAllTokens(user_did) + if err != nil { + response.Message = "failed to fetch all tokens" + return response, err + } + for _, tkn := range tokens_list { + //Fetch token information + token_info, err := c.w.ReadToken(tkn.TokenID) + if err != nil { + response.Message = "Failed to get token chain block, token does not exist" + return response, err + } + //Get token type + type_string := RBTString + if token_info.TokenValue < 1.0 { + type_string = PartString + } + token_type := c.TokenType(type_string) + //Validate tokenchain for each token in the tokens table + response, err = c.ValidateTokenChain(user_did, token_info, token_type, blockCount) + if err != nil || !response.Status { + c.log.Error("token chain validation failed for token:", tkn.TokenID, "\nError :", err, "\nmsg:", response.Message) + if token_info.TokenStatus == wallet.TokenIsFree { + //if token chain validation failed and the validator is the current owner of the token, + //then lock the token + response, err = c.LockInvalidToken(tkn.TokenID, token_type, user_did) + if err != nil { + c.log.Error(response.Message, tkn.TokenID) + return response, err + } + c.log.Info(response.Message, tkn.TokenID) + } else { + c.log.Error("token is not free, token state is", token_info.TokenStatus) + } + } + } + + } else { + //Fetch token information + token_info, err := c.w.ReadToken(tokenId) + if err != nil { + response.Message = "Failed to get token chain block, token does not exist" + return response, err + } + + //Get token type + type_string := RBTString + if token_info.TokenValue < 1.0 { + type_string = PartString + } + token_type := c.TokenType(type_string) + //Validate tokenchain for the provided token + response, err = c.ValidateTokenChain(user_did, token_info, token_type, blockCount) + if err != nil || !response.Status { + c.log.Error("token chain validation failed for token:", tokenId, "\nError :", err, "\nmsg:", response.Message) + if token_info.TokenStatus == wallet.TokenIsFree { + response, err1 := c.LockInvalidToken(tokenId, token_type, user_did) + if err1 != nil { + c.log.Error(response.Message, tokenId) + return response, err1 + } + c.log.Info(response.Message, tokenId) + return response, err + } + return response, err + } + } + return response, nil +} + +// Validates tokenchain for the given token upto the specified block height +func (c *Core) ValidateTokenChain(user_did string, token_info *wallet.Token, token_type int, blockCount int) (*model.BasicResponse, error) { + c.log.Info("--------validating tokenchain", token_info.TokenID, "---------") + response := &model.BasicResponse{ + Status: false, + } + validated_block_count := 0 + blockId := "" + + var blocks [][]byte + var prevBlockId string + var nextBlockID string + var err error + + //This for loop ensures that we fetch all the blocks in the token chain + //starting from genesis block to latest block + for { + //GetAllTokenBlocks returns next 100 blocks and nextBlockID of the 100th block, + //starting from the given block Id, in the direction: genesis to latest block + blocks, nextBlockID, err = c.w.GetAllTokenBlocks(token_info.TokenID, token_type, blockId) + if err != nil { + response.Message = "Failed to get token chain block" + return response, err + } + //the nextBlockID of the latest block is empty string + blockId = nextBlockID + if nextBlockID == "" { + break + } + } + + c.log.Info("token chain length", len(blocks)) + for i := len(blocks) - 1; i >= 0; i-- { + b := block.InitBlock(blocks[i], nil) + //validated_block_count keeps count of the number of blocks validated, including failed blocks + validated_block_count++ + + if b != nil { + //calculate block height + block_height, err := b.GetBlockNumber(token_info.TokenID) + if err != nil { + response.Message = "failed to fetch BlockNumber" + return response, fmt.Errorf("invalid token chain block") + } + + c.log.Info("validating at block height:", block_height) + + //fetch transaction type to validate the block accordingly + txn_type := b.GetTransType() + switch txn_type { + case block.TokenTransferredType: + //calculate previous block Id + prevBlock := block.InitBlock(blocks[i-1], nil) + prevBlockId, err = prevBlock.GetBlockID(token_info.TokenID) + if err != nil { + c.log.Error("invalid previous block") + continue + } + //validate rbt transfer block + response, err = c.Validate_RBTTransfer_Block(b, token_info.TokenID, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenGeneratedType: + //validate genesis block + response, err = c.ValidateGenesisBlock(b, *token_info, token_type, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenBurntType: + //validate RBT burnt block + response, err = c.Validate_RBTBurnt_Block(b, *token_info, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenPledgedType: + //calculate previous block Id + prevBlock := block.InitBlock(blocks[i-1], nil) + prevBlockId, err = prevBlock.GetBlockID(token_info.TokenID) + if err != nil { + c.log.Error("invalid previous block") + continue + } + //validate Pledged block + response, err = c.Validate_Pledged_or_Unpledged_Block(b, token_info.TokenID, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenUnpledgedType: + //calculate previous block Id + prevBlock := block.InitBlock(blocks[i-1], nil) + prevBlockId, err = prevBlock.GetBlockID(token_info.TokenID) + if err != nil { + c.log.Error("invalid previous block") + continue + } + //validate Pledged block + response, err = c.Validate_Pledged_or_Unpledged_Block(b, token_info.TokenID, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + case block.TokenContractCommited: + //calculate previous block Id + prevBlock := block.InitBlock(blocks[i-1], nil) + prevBlockId, err = prevBlock.GetBlockID(token_info.TokenID) + if err != nil { + c.log.Error("invalid previous block") + continue + } + //validate Pledged block + response, err = c.Validate_Pledged_or_Unpledged_Block(b, token_info.TokenID, prevBlockId, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + } + + } else { + c.log.Error("Invalid block") + } + + c.log.Info("validated_block_count", validated_block_count) + // //If blockCount is provided, then we will stop validating when we reach the blockCount + // //If blockCount is not provided,i.e., is 0, then it will never be equal to validated_block_count + // //and thus will be continued till genesis block + if validated_block_count == blockCount { + break + } + } + + //Get latest block in the token chain + latestBlock := c.w.GetLatestTokenBlock(token_info.TokenID, token_type) + + if latestBlock.GetTransType() == block.TokenTransferredType { + //Verify if the token is pinned only by the current owner aka receiver in the latest block + response, err = c.CurrentOwnerPinCheck(latestBlock, token_info.TokenID, user_did) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + + //verify if the current token state is pinned by the quorums in the latest block + response, err = c.CurrentQuorumStatePinCheck(latestBlock, token_info.TokenID, token_type, user_did) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + } else { + //Verify if the token is pinned only by the current owner aka receiver in the latest block + response, err = c.CurrentOwnerPinCheck(latestBlock, token_info.TokenID, user_did) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + } + + c.log.Info("token chain validated successfully") + response.Message = "token chain validated successfully" + response.Status = true + return response, nil +} + +// validate block of type: TokenTransferredType = "02" / TokenDeployedType = "09" / TokenExecutedType = "10" +func (c *Core) Validate_RBTTransfer_Block(b *block.Block, tokenId string, calculated_prevBlockId string, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{} + + //Validate block hash + response, err := c.ValidateBlockHash(b, tokenId, calculated_prevBlockId) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + //Validate sender signature + response, err = c.ValidateSender(b) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + //validate all quorums' signatures + response, err = c.ValidateQuorums(b, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + response.Status = true + response.Message = "RBT transfer block validated successfully" + c.log.Debug("successfully validated RBT transfer block") + return response, nil +} + +// validate block of type : TokenBurntType = "08" +func (c *Core) Validate_RBTBurnt_Block(b *block.Block, token_info wallet.Token, calculated_prevBlockId string, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{} + + //Validate block hash + response, err := c.ValidateBlockHash(b, token_info.TokenID, calculated_prevBlockId) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + + //validate burnt-token owner signature + response, err = c.Validate_Token_Owner(b, user_did) + if err != nil { + response.Message = "invalid token owner in RBT burnt block" + c.log.Error("invalid token owner in RBT burnt block") + return response, fmt.Errorf("failed to validate token owner in RBT burnt block") + } + + response.Status = true + response.Message = "RBT burnt block validated successfully" + c.log.Debug("successfully validated RBT burnt block") + return response, nil +} + +// validate block of type : TokenPledgedType = "04" / TokenUnpledgedType = "06" / TokenContractCommited = "11" +func (c *Core) Validate_Pledged_or_Unpledged_Block(b *block.Block, tokenId string, calculated_prevBlockId string, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{} + + //Validate block hash + response, err := c.ValidateBlockHash(b, tokenId, calculated_prevBlockId) + if err != nil { + c.log.Error("msg", response.Message) + return response, err + } + + //validate burnt-token owner signature + response, err = c.Validate_Token_Owner(b, user_did) + if err != nil { + response.Message = "invalid token owner in RBT burnt block" + c.log.Error("invalid token owner in RBT burnt block") + return response, fmt.Errorf("failed to validate token owner in RBT burnt block") + } + + response.Status = true + response.Message = "RBT pledged/unpledged/committed block validated successfully" + c.log.Debug("successfully validated RBT pledged/unpledged/committed block") + return response, nil +} + +// genesis block validation : validate block of type: TokenGeneratedType = "05" +func (c *Core) ValidateGenesisBlock(b *block.Block, token_info wallet.Token, token_type int, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{} + + //Validate block hash of genesis block + response, err := c.ValidateBlockHash(b, token_info.TokenID, "") + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + //initial token owner signature verification + response, err = c.Validate_Token_Owner(b, user_did) + if err != nil { + response.Message = "invalid token owner in genesis block" + c.log.Error("invalid token owner in genesis block") + return response, fmt.Errorf("failed to validate token owner in genesis block") + } + + //if part token, validate parent token chain + if token_type == token.TestPartTokenType { + response, err = c.Validate_ParentToken_LatestBlock(token_info.ParentTokenID, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + } + + response.Status = true + response.Message = "genesis block validated successfully" + c.log.Debug("validated genesis block") + return response, nil +} + +// Validate Parent token latest block if token is part token +func (c *Core) Validate_ParentToken_LatestBlock(parent_tokenId string, user_did string) (*model.BasicResponse, error) { + c.log.Debug("validating parent token chain latest block", parent_tokenId) + response := &model.BasicResponse{ + Status: false, + } + + parent_token_info, err := c.w.ReadToken(parent_tokenId) + if err != nil { + b, err := c.getFromIPFS(parent_tokenId) + if err != nil { + c.log.Error("failed to get parent token detials from ipfs", "err", err, "token", parent_tokenId) + response.Message = "failed to get parent token detials from ipfs" + return response, err + } + _, iswholeToken, _ := token.CheckWholeToken(string(b)) + token_type := token.RBTTokenType + token_value := float64(1) + token_owner := "" + if !iswholeToken { + blk := util.StrToHex(string(b)) + rb, err := rac.InitRacBlock(blk, nil) + if err != nil { + c.log.Error("invalid token, invalid rac block", "err", err) + response.Message = "invalid token, invalid rac block" + return response, err + } + token_type = rac.RacType2TokenType(rb.GetRacType()) + if c.TokenType(PartString) == token_type { + token_value = rb.GetRacValue() + } + token_owner = rb.GetDID() + } + parent_token_info = &wallet.Token{ + TokenID: parent_tokenId, + TokenValue: token_value, + TokenStatus: wallet.TokenIsBurnt, + DID: token_owner, + } + } + + if parent_token_info.TokenStatus != wallet.TokenIsBurnt { + response.Message = "parent token not in burnt state" + c.log.Error("msg", response.Message) + return response, err + } + type_string := RBTString + if parent_token_info.TokenValue < 1.0 { + type_string = PartString + } + parent_token_type := c.TokenType(type_string) + + //Get latest block in the token chain + parent_token_latestBlock := c.w.GetLatestTokenBlock(parent_tokenId, parent_token_type) + response, err = c.Validate_RBTBurnt_Block(parent_token_latestBlock, *parent_token_info, "", user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + + //if parent token is also a part token, then validate it's parent token latest block + if parent_token_type == c.TokenType(PartString) { + if parent_token_info.ParentTokenID == "" { + genesis_block := c.w.GetGenesisTokenBlock(parent_tokenId, parent_token_type) + grand_parent_token, _, err := genesis_block.GetParentDetials(parent_tokenId) + if err != nil { + c.log.Error("failed to get grand parent tokens to validate") + } + c.log.Debug("grand parent token:", grand_parent_token) + parent_token_info.ParentTokenID = grand_parent_token + } + response, err = c.Validate_ParentToken_LatestBlock(parent_token_info.ParentTokenID, user_did) + if err != nil { + c.log.Error("msg", response.Message, "err", err) + return response, err + } + } + + c.log.Debug("validated parent tokenchain latest block:", parent_tokenId) + response.Status = true + response.Message = "validated parent tokenchain latest block" + return response, nil +} + +// Validate block hash and previous block hash +func (c *Core) ValidateBlockHash(b *block.Block, tokenId string, calculated_prevBlockId string) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + //fetching block hash from block map using key 'TCBlockHash' + stored_blockHash, err := b.GetHash() + if err != nil { + c.log.Error("failed to fetch block hash") + response.Message = "failed to fetch block hash, could not validate block hash" + return response, err + } + + //if previous block Id verification is not neessary, then calculated_prevBlockId can be paased as an empty string + if calculated_prevBlockId != "" { + //fetching previous block-Id from block map using key 'TTPreviousBlockIDKey' + stored_prevBlockId, err := b.GetPrevBlockID(tokenId) + if err != nil { + c.log.Error("failed to fetch previous-block-Id") + response.Message = "failed to fetch previous-block-Id, could not validate block hash" + return response, err + } + + //check the validity of the stored previous block-ID + if calculated_prevBlockId != stored_prevBlockId { + c.log.Error("previous-block-Id does not match") + response.Message = "previous-block-Id does not match, block hash validation failed" + return response, err + } + } + + //calculate block hash from block data + calculated_blockHash, err := b.CalculateBlockHash() + if err != nil { + c.log.Error("err", err) + } + + // block_hash_map := blockMap[TCBlockHashKey] + if stored_blockHash != calculated_blockHash { + c.log.Error("block hash does not match") + c.log.Debug("stored block hash", stored_blockHash) + c.log.Debug("calculated block hash", calculated_blockHash) + response.Message = "block hash does not match, block hash validation failed" + return response, fmt.Errorf("block hash does not match, block hash validation failed") + } + + response.Status = true + response.Message = "block hash validated succesfully" + c.log.Debug("block hash validated") + return response, nil +} + +// sender signature verification in a (non-genesis)block +func (c *Core) ValidateSender(b *block.Block) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + // block_map := b.GetBlockMap() + sender := b.GetSenderDID() + + sender_sign := b.GetInitiatorSignature() + //check if it is a block addded to chain before adding sender signature to block structure + if sender_sign == nil { + c.log.Info("old block, sender signature not found") + response.Message = "old block, sender signature not found" + return response, nil + } else if sender_sign.DID != sender { + c.log.Info("invalid sender, sender did does not match") + response.Message = "invalid sender, sender did does not match" + return response, fmt.Errorf("invalid sender, sender did does not match") + } + + var sender_didType int + //sign type = 0, means it is a BIP signature and the did was created in light mode + //sign type = 1, means it is an NLSS-based signature and the did was created using NLSS scheme + //and thus the did could be initialised in basic mode to fetch the public key + if sender_sign.SignType == 0 { + sender_didType = did.LiteDIDMode + } else { + sender_didType = did.BasicDIDMode + } + + //Initialise sender did + didCrypto, err := c.InitialiseDID(sender, sender_didType) + if err != nil { + c.log.Error("failed to initialise sender did:", sender) + response.Message = "failed to initialise sender did" + return response, err + } + + //sender signature verification + if sender_didType == did.LiteDIDMode { + response.Status, err = didCrypto.PvtVerify([]byte(sender_sign.Hash), util.StrToHex(sender_sign.Private_sign)) + if err != nil { + c.log.Error("failed to verify sender:", sender, "err", err) + response.Message = "invalid sender" + return response, err + } + } else { + response.Status, err = didCrypto.NlssVerify(sender_sign.Hash, util.StrToHex(sender_sign.NLSS_share), util.StrToHex(sender_sign.Private_sign)) + if err != nil { + c.log.Error("failed to verify sender:", sender, "err", err) + response.Message = "invalid sender" + return response, err + } + } + + response.Message = "sender validated successfully" + c.log.Debug("sender validated successfully") + return response, nil +} + +// token owner signature verification +func (c *Core) Validate_Token_Owner(b *block.Block, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + signers, err := b.GetSigner() + if err != nil { + c.log.Error("failed to get signers", "err", err) + return response, err + } + for _, signer := range signers { + var dc did.DIDCrypto + switch b.GetTransType() { + case block.TokenGeneratedType, block.TokenBurntType: + dc, err = c.SetupForienDID(signer, user_did) + if err != nil { + c.log.Error("failed to setup foreign DID", signer, "err", err) + return response, err + } + default: + dc, err = c.SetupForienDIDQuorum(signer, user_did) + if err != nil { + c.log.Error("failed to setup foreign DID quorum", signer, "err", err) + return response, err + } + } + err := b.VerifySignature(dc) + if err != nil { + c.log.Error("Failed to verify signature of signer", signer, "err", err) + return response, err + } + } + + response.Status = true + response.Message = "block validated successfully" + c.log.Debug("validated token owner successfully") + return response, nil +} + +// quorums signature validation +func (c *Core) ValidateQuorums(b *block.Block, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + //signed data aka transaction Id + signed_data := b.GetTid() + quorum_sign_list, err := b.GetQuorumSignatureList() + if err != nil || quorum_sign_list == nil { + c.log.Error("failed to get quorum signature list") + } + + response.Status = true + for _, qrm := range quorum_sign_list { + qrm_DIDCrypto, err := c.SetupForienDIDQuorum(qrm.DID, user_did) + if err != nil { + c.log.Error("failed to initialise quorum:", qrm.DID, "err", err) + continue + } + var verificationStatus bool + if qrm.SignType == "0" { //qrm sign type = 0, means qrm signature is BIP sign and DID is created in Lite mode + verificationStatus, err = qrm_DIDCrypto.PvtVerify([]byte(signed_data), util.StrToHex(qrm.PrivSignature)) + if err != nil { + c.log.Error("failed signature verification for quorum:", qrm.DID) + } + } else { + verificationStatus, err = qrm_DIDCrypto.NlssVerify((signed_data), util.StrToHex(qrm.Signature), util.StrToHex(qrm.PrivSignature)) + if err != nil { + c.log.Error("failed signature verification for quorum:", qrm.DID) + } + } + response.Status = response.Status && verificationStatus + } + + response.Message = "quorums validated successfully" + c.log.Debug("validated all quorums successfully") + return response, nil +} + +// latest block owner(receiver) pin check +func (c *Core) CurrentOwnerPinCheck(b *block.Block, tokenId string, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + //current owner should be the receiver in the latest block + current_owner := b.GetOwner() + var current_ownerPeerID string + if current_owner == user_did { + current_ownerPeerID = c.peerID + } else { + current_ownerPeerID = c.w.GetPeerID(current_owner) + } + + results := make([]MultiPinCheckRes, 1) + var wg sync.WaitGroup + wg.Add(1) + go c.pinCheck(tokenId, 0, current_ownerPeerID, "", results, &wg) + wg.Wait() + for i := range results { + if results[i].Error != nil { + c.log.Error("Error occured", "error", results[i].Error) + response.Message = "Error while cheking Token multiple Pins" + return response, results[i].Error + } + if results[i].Status { + c.log.Error("Token has multiple owners", "token", results[i].Token, "owners", results[i].Owners) + response.Message = "Token has multiple owners" + return response, fmt.Errorf("token has multiple owners") + } + } + + response.Status = true + response.Message = "current owner pin checked successfully" + c.log.Debug("current owner pin checked successfully") + return response, nil +} + +// latest block pledged quorum pin check +func (c *Core) CurrentQuorumStatePinCheck(b *block.Block, tokenId string, token_type int, user_did string) (*model.BasicResponse, error) { + response := &model.BasicResponse{ + Status: false, + } + + //Get quorumList along with peerIds : QuorumList + var quorumList []string + quorum_sign_list, err := b.GetQuorumSignatureList() + if err != nil || quorum_sign_list == nil { + c.log.Error("failed to get quorum signature list from latest block") + response.Message = "state pincheck failed" + return response, err + } + for _, qrm := range quorum_sign_list { + qrm_peerId := c.w.GetPeerID(qrm.DID) + quorumList = append(quorumList, qrm_peerId+"."+qrm.DID) + } + + tokenStateCheckResult := make([]TokenStateCheckResult, 1) + c.log.Debug("entering validation to check if token state is exhausted") + var wg sync.WaitGroup + wg.Add(1) + go c.checkTokenState(tokenId, user_did, 0, tokenStateCheckResult, &wg, quorumList, token_type) + wg.Wait() + + for i := range tokenStateCheckResult { + if tokenStateCheckResult[i].Error != nil { + c.log.Error("Error occured", "error", tokenStateCheckResult[i].Error) + response.Message = "Error while cheking Token State Message : " + tokenStateCheckResult[i].Message + response.Status = false + return response, tokenStateCheckResult[i].Error + } + if tokenStateCheckResult[i].Exhausted { + c.log.Debug("Token state has been exhausted, Token being Double spent:", tokenStateCheckResult[i].Token) + response.Message = tokenStateCheckResult[i].Message + response.Status = false + return response, fmt.Errorf("token state has been exhausted") + } + c.log.Debug("Token", tokenStateCheckResult[i].Token, "Message", tokenStateCheckResult[i].Message) + response.Status = true + response.Message = tokenStateCheckResult[i].Message + } + + return response, nil +} diff --git a/core/wallet/smart_contract.go b/core/wallet/smart_contract.go index a37d4c86..9a41c717 100644 --- a/core/wallet/smart_contract.go +++ b/core/wallet/smart_contract.go @@ -123,3 +123,10 @@ func (w *Wallet) GetSmartContractTokenUrl(smartcontracttoken string) (string, er url := callback.CallBackUrl return url, nil } + +func (w *Wallet) LockSmartContract(wt *SmartContract) error { + w.l.Lock() + defer w.l.Unlock() + wt.ContractStatus = TokenIsLocked + return w.s.Update(SmartContractStorage, wt, "deployer=? AND smart_contract_hash=?", wt.Deployer, wt.SmartContractHash) +} diff --git a/core/wallet/wallet.go b/core/wallet/wallet.go index 0dee3c99..0270fd59 100644 --- a/core/wallet/wallet.go +++ b/core/wallet/wallet.go @@ -3,6 +3,7 @@ package wallet import ( "fmt" "sync" + "path" ipfsnode "github.com/ipfs/go-ipfs-api" "github.com/rubixchain/rubixgoplatform/core/model" @@ -76,19 +77,19 @@ func InitWallet(s storage.Storage, dir string, log logger.Logger) (*Wallet, erro WriteBuffer: 64 * 1024 * 1024, } - tdb, err := leveldb.OpenFile(dir+TokenChainStorage, op) + tdb, err := leveldb.OpenFile(path.Join(dir, TokenChainStorage), op) if err != nil { w.log.Error("failed to configure token chain block storage", "err", err) return nil, fmt.Errorf("failed to configure token chain block storage") } w.tcs.DB = *tdb - ntdb, err := leveldb.OpenFile(dir+NFTChainStorage, op) + ntdb, err := leveldb.OpenFile(path.Join(dir, NFTChainStorage), op) if err != nil { w.log.Error("failed to configure NFT chain block storage", "err", err) return nil, fmt.Errorf("failed to configure NFT chain block storage") } w.ntcs.DB = *ntdb - dtdb, err := leveldb.OpenFile(dir+DataChainStorage, op) + dtdb, err := leveldb.OpenFile(path.Join(dir, DataChainStorage), op) if err != nil { w.log.Error("failed to configure data chain block storage", "err", err) return nil, fmt.Errorf("failed to configure data chain block storage") @@ -145,7 +146,7 @@ func InitWallet(s storage.Storage, dir string, log logger.Logger) (*Wallet, erro return nil, err } - smartcontracTokenchainstorageDB, err := leveldb.OpenFile(dir+SmartContractTokenChainStorage, op) + smartcontracTokenchainstorageDB, err := leveldb.OpenFile(path.Join(dir, SmartContractTokenChainStorage), op) if err != nil { w.log.Error("failed to configure token chain block storage", "err", err) return nil, fmt.Errorf("failed to configure token chain block storage") diff --git a/did/did.go b/did/did.go index 572badd1..ec00e768 100644 --- a/did/did.go +++ b/did/did.go @@ -9,6 +9,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "time" @@ -313,7 +314,7 @@ func (d *DID) CreateDID(didCreate *DIDCreate) (string, error) { return "", err } - newDIrName := d.dir + did + newDIrName := path.Join(d.dir, did) err = os.MkdirAll(newDIrName, os.ModeDir|os.ModePerm) if err != nil { diff --git a/go.mod b/go.mod index a165f5e1..42cf4535 100644 --- a/go.mod +++ b/go.mod @@ -16,10 +16,9 @@ require ( ) require ( - filippo.io/keygen v0.0.0-20230306160926-5201437acf8e // indirect + filippo.io/keygen v0.0.0-20230306160926-5201437acf8e github.com/btcsuite/btcd v0.23.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1 v1.0.4 - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/denisenkom/go-mssqldb v0.12.3 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fatih/color v1.15.0 @@ -48,6 +47,7 @@ require ( github.com/multiformats/go-multihash v0.1.0 // indirect github.com/natefinch/atomic v1.0.1 github.com/pierrec/lz4 v2.6.1+incompatible + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.3 // indirect github.com/swaggo/files v1.0.0 // indirect github.com/swaggo/http-swagger v1.3.4 diff --git a/go.sum b/go.sum index a8fe684c..b96804a6 100644 --- a/go.sum +++ b/go.sum @@ -608,8 +608,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLC github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/EnsurityTechnologies/helper v1.0.0 h1:x6kaCFvqH35/P8eD8Vkx/IUUkbvDqyh4KVwqDJWIfWA= -github.com/EnsurityTechnologies/helper v1.0.0/go.mod h1:KESBOBjgzlkimm3dDwr49wjbMXWtaoqrA3SiwhxGDwQ= github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= @@ -670,6 +668,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -685,6 +684,7 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -692,13 +692,8 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1 v1.0.4 h1:0XErmfJBiVbl0NvyclGn4jr+1hIylDf5beFi9W0o7Fc= -github.com/decred/dcrd/dcrec/secp256k1 v1.0.4/go.mod h1:00z7mJdugt+GBAzPN1QrDRGCXxyKUiexEHu6ukxEw3k= -github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 h1:3GIJYXQDAKpLEFriGFN8SbSffak10UXHGdIcFaMPykY= -github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0/go.mod h1:3s92l0paYkZoIHuj4X93Teg/HB7eGM9x/zokGw+u4mY= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= @@ -902,6 +897,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= @@ -1085,6 +1082,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1098,6 +1096,10 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2 github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -1174,7 +1176,6 @@ golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -1861,6 +1862,7 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= diff --git a/main.go b/main.go index 256a6096..b1da5399 100644 --- a/main.go +++ b/main.go @@ -1,24 +1,11 @@ package main import ( - "os" - "github.com/rubixchain/rubixgoplatform/command" _ "github.com/rubixchain/rubixgoplatform/wrapper/ensweb" ) -// @title Rubix Core -// @version 0.9 -// @description Rubix core API to control & manage the node. - -// @contact.name API Support -// @contact.email murali.c@ensurity.com - -// @BasePath - -// @securityDefinitions.apikey SessionToken -// @in header -// @name Session-Token func main() { - command.Run(os.Args) + // Rubix CLI Entrypoint + command.Execute() } diff --git a/server/server.go b/server/server.go index 9eb80804..517024a9 100644 --- a/server/server.go +++ b/server/server.go @@ -168,6 +168,7 @@ func (s *Server) RegisterRoutes() { s.AddRoute(setup.APIUnpledgePOWPledgeTokens, "POST", s.AuthHandle(s.UnpledgePoWBasedPledgedTokens, false, s.AuthError, true)) s.AddRoute(setup.APIInitiatePinRBT, "POST", s.AuthHandle(s.APIInitiatePinRBT, true, s.AuthError, false)) s.AddRoute(setup.APIRecoverRBT, "POST", s.AuthHandle(s.APIRecoverRBT, true, s.AuthError, false)) + s.AddRoute(setup.APIValidateTokenChain, "GET", s.AuthHandle(s.APIValidateTokenChain, false, s.AuthError, false)) } func (s *Server) ExitFunc() error { diff --git a/server/smart_contract.go b/server/smart_contract.go index b4c531e2..4a4a909c 100644 --- a/server/smart_contract.go +++ b/server/smart_contract.go @@ -408,8 +408,8 @@ func (s *Server) APIExecuteSmartContract(req *ensweb.Request) *ensweb.Result { return s.BasicResponse(req, false, "Invalid smart contract token", nil) } - is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(executeReq.ExecutorAddress) - if !strings.HasPrefix(executeReq.ExecutorAddress, "bafybmi") || len(executeReq.ExecutorAddress) != 59 || !is_alphanumeric { + is_alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(did) + if !strings.HasPrefix(did, "bafybmi") || len(did) != 59 || !is_alphanumeric { s.log.Error("Invalid executer DID") return s.BasicResponse(req, false, "Invalid executer DID", nil) } diff --git a/server/tokens.go b/server/tokens.go index 1d50bb9b..77904d57 100644 --- a/server/tokens.go +++ b/server/tokens.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "regexp" + "strconv" "strings" "github.com/rubixchain/rubixgoplatform/core/model" @@ -304,3 +305,40 @@ func (s *Server) APICheckPinnedState(req *ensweb.Request) *ensweb.Result { br.Message = "Got Pins on " + tokenstatehash + ". Updated the pledging detail in table and removed from pledged token state table." return s.RenderJSON(req, br, http.StatusOK) } + +func (s *Server) APIValidateTokenChain(req *ensweb.Request) *ensweb.Result { + user_did := s.GetQuerry(req, "did") + token := s.GetQuerry(req, "token") + blockCount_str := s.GetQuerry(req, "blockcount") + smartContractChainValidation_str := s.GetQuerry(req, "SCChainValidation") + blockCount, err := strconv.Atoi(blockCount_str) + if err != nil { + return s.BasicResponse(req, false, "Failed to convert blockCount string into integer", nil) + } + + if user_did == "" { + return s.BasicResponse(req, false, "user did is not provided", nil) + } + + smartContractChainValidation, err := strconv.ParseBool(smartContractChainValidation_str) + if err != nil { + return s.BasicResponse(req, false, "Error converting string to boolean", nil) + } + + var br *model.BasicResponse + if smartContractChainValidation { + s.log.Debug("validating smart contract") + br, err = s.c.SmartContractTokenChainValidation(user_did, token, blockCount) + if err != nil { + return s.BasicResponse(req, false, "Failed to validate token(s)", nil) + } + } else { + s.log.Debug("validating rbt token") + br, err = s.c.TokenChainValidation(user_did, token, blockCount) + if err != nil { + return s.BasicResponse(req, false, "Failed to validate token(s)", nil) + } + } + + return s.RenderJSON(req, br, http.StatusOK) +} diff --git a/setup/setup.go b/setup/setup.go index 98e918c4..a0ec0d8a 100644 --- a/setup/setup.go +++ b/setup/setup.go @@ -75,6 +75,7 @@ const ( APIUnpledgePOWPledgeTokens string = "/api/unpledge-pow-unpledge-tokens" APIInitiatePinRBT string = "/api/initiate-pin-token" APIRecoverRBT string = "/api/recover-token" + APIValidateTokenChain string = "/api/validate-token-chain" ) // jwt.RegisteredClaims diff --git a/tests/fixtures/testswarm_linux.key b/tests/fixtures/testswarm_linux.key index 534e7acb..44e60f24 100644 --- a/tests/fixtures/testswarm_linux.key +++ b/tests/fixtures/testswarm_linux.key @@ -1,3 +1,3 @@ -/key/swarm/psk/1.0.0/ -/base16/ -278b9a199c43fa84178920bd9f5cbcd69e933ddf02a8f69e47a3ea5a1705513f \ No newline at end of file +/key/swarm/psk/1.0.0/ +/base16/ +1348a8a940aef4791fba811f665e7bba6c48b2070ec324e4685b58dde8ee4972 \ No newline at end of file diff --git a/tests/node/commands.py b/tests/node/commands.py index b0c07bd1..aaa9d5a4 100644 --- a/tests/node/commands.py +++ b/tests/node/commands.py @@ -57,9 +57,9 @@ def cmd_run_rubix_servers(node_name, server_port_idx): cmd_string = "" if is_windows_os(): - cmd_string = f"powershell -Command Start-Process -FilePath '.\\rubixgoplatform.exe' -ArgumentList 'run -p {node_name} -n {server_port_idx} -s -testNet -grpcPort {grpc_port}' -WindowStyle Hidden" + cmd_string = f"powershell -Command Start-Process -FilePath '.\\rubixgoplatform.exe' -ArgumentList 'run --p {node_name} --n {server_port_idx} --s --testNet --grpcPort {grpc_port}' -WindowStyle Hidden" else: - cmd_string = f"tmux new -s {node_name} -d ./rubixgoplatform run -p {node_name} -n {server_port_idx} -s -testNet -grpcPort {grpc_port}" + cmd_string = f"tmux new -s {node_name} -d ./rubixgoplatform run --p {node_name} --n {server_port_idx} --s --testNet --grpcPort {grpc_port}" _, code = run_command(cmd_string) if code != 0: @@ -93,9 +93,9 @@ def check_if_nodes_is_running(server_idx): def cmd_create_did(server_port, grpc_port, did_type = 4): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform createdid -port {server_port} -grpcPort {grpc_port} -didType {did_type}" + cmd_string = f"./rubixgoplatform did create --port {server_port} --didType {did_type}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform createdid -port {server_port} -grpcPort {grpc_port} -didType {did_type}" + cmd_string = f".\\rubixgoplatform did create --port {server_port} --didType {did_type}" output, code = run_command(cmd_string, True) print(output) @@ -116,9 +116,9 @@ def cmd_create_did(server_port, grpc_port, did_type = 4): def cmd_register_did(did_id, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform registerdid -did {did_id} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform did register --did {did_id} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform registerdid -did {did_id} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform did register --did {did_id} --port {server_port}" output, code = run_command(cmd_string, True) print(output) @@ -130,9 +130,9 @@ def cmd_register_did(did_id, server_port, grpc_port): def cmd_add_peer_details(peer_id, did_id, did_type, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform addpeerdetails -peerID {peer_id} -did {did_id} -didType {did_type} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform node peer add --peerID {peer_id} --did {did_id} --didType {did_type} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform addpeerdetails -peerID {peer_id} -did {did_id} -didType {did_type} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform node peer add --peerID {peer_id} --did {did_id} --didType {did_type} --port {server_port}" output, code = run_command(cmd_string, True) print(output) @@ -144,9 +144,9 @@ def cmd_add_peer_details(peer_id, did_id, did_type, server_port, grpc_port): def cmd_generate_rbt(did_id, numTokens, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform generatetestrbt -did {did_id} -numTokens {numTokens} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform tx rbt generate-test-tokens --did {did_id} --numTokens {numTokens} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform generatetestrbt -did {did_id} -numTokens {numTokens} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform tx rbt generate-test-tokens --did {did_id} --numTokens {numTokens} --port {server_port}" output, code = run_command(cmd_string, True) if code != 0: @@ -157,9 +157,9 @@ def cmd_generate_rbt(did_id, numTokens, server_port, grpc_port): def cmd_add_quorum_dids(server_port, grpc_port, quorumlist = "quorumlist.json"): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform addquorum -port {server_port} -grpcPort {grpc_port} -quorumList {quorumlist}" + cmd_string = f"./rubixgoplatform quorum add --port {server_port} --quorumList {quorumlist}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform addquorum -port {server_port} -grpcPort {grpc_port} -quorumList {quorumlist}" + cmd_string = f".\\rubixgoplatform quorum add --port {server_port} --quorumList {quorumlist}" output, code = run_command(cmd_string, True) print(output) if code != 0: @@ -170,9 +170,9 @@ def cmd_add_quorum_dids(server_port, grpc_port, quorumlist = "quorumlist.json"): def cmd_shutdown_node(server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform shutdown -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform node shutdown --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform shutdown -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform node shutdown --port {server_port}" output, _ = run_command(cmd_string, True) print(output) @@ -181,9 +181,9 @@ def cmd_shutdown_node(server_port, grpc_port): def cmd_setup_quorum_dids(did, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform setupquorum -did {did} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform quorum setup --did {did} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform setupquorum -did {did} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform quorum setup --did {did} --port {server_port}" output, code = run_command(cmd_string, True) print(output) if code != 0: @@ -194,9 +194,9 @@ def cmd_setup_quorum_dids(did, server_port, grpc_port): def cmd_get_peer_id(server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform get-peer-id -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform node peer local-id --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform get-peer-id -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform node peer local-id --port {server_port}" output, code = run_command(cmd_string) if code != 0: @@ -206,9 +206,9 @@ def cmd_get_peer_id(server_port, grpc_port): def check_account_info(did, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform getaccountinfo -did {did} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform did info --did {did} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform getaccountinfo -did {did} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform did info --did {did} --port {server_port}" output, code = run_command(cmd_string) if code != 0: @@ -219,9 +219,9 @@ def check_account_info(did, server_port, grpc_port): # Note: address != did, address = peerId.didId def cmd_rbt_transfer(sender_address, receiver_address, rbt_amount, server_port, grpc_port): os.chdir("../" + get_build_dir()) - cmd_string = f"./rubixgoplatform transferrbt -senderAddr {sender_address} -receiverAddr {receiver_address} -rbtAmount {rbt_amount} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f"./rubixgoplatform tx rbt transfer --senderAddr {sender_address} --receiverAddr {receiver_address} --rbtAmount {rbt_amount} --port {server_port}" if is_windows_os(): - cmd_string = f".\\rubixgoplatform transferrbt -senderAddr {sender_address} -receiverAddr {receiver_address} -rbtAmount {rbt_amount} -port {server_port} -grpcPort {grpc_port}" + cmd_string = f".\\rubixgoplatform tx rbt transfer --senderAddr {sender_address} --receiverAddr {receiver_address} --rbtAmount {rbt_amount} --port {server_port}" output, code = run_command(cmd_string, True) print(output) if code != 0: