From 27f9da09240ca19db9d447a2b01913fb4c54aa40 Mon Sep 17 00:00:00 2001 From: saito Date: Tue, 21 Nov 2023 18:57:34 +0800 Subject: [PATCH 01/14] feat(ioctl): add znode commands configs --- ioctl/config/config.go | 4 +++ ioctl/config/configsetget.go | 12 +++++++ ioctl/newcmd/config/config.go | 16 +++++++++ ioctl/newcmd/config/config_test.go | 54 +++++++++++++++++++++--------- 4 files changed, 71 insertions(+), 15 deletions(-) diff --git a/ioctl/config/config.go b/ioctl/config/config.go index 76f9ecdb99..ed722292b6 100644 --- a/ioctl/config/config.go +++ b/ioctl/config/config.go @@ -67,6 +67,10 @@ type Config struct { Language string `json:"language" yaml:"language"` Nsv2height uint64 `json:"nsv2height" yaml:"nsv2height"` AnalyserEndpoint string `json:"analyserEndpoint" yaml:"analyserEndpoint"` + // ZnodeEndpint IoTeX Zero-node endpint + ZnodeEndpoint string `json:"znodeEndpoint" yaml:"znodeEndpoint"` + // ZnodeContractAddress znode contract address + ZnodeContractAddress string `json:"znodeContractAddress" yaml:"znodeContractAddress"` } var ( diff --git a/ioctl/config/configsetget.go b/ioctl/config/configsetget.go index 3663107243..0e7801599b 100644 --- a/ioctl/config/configsetget.go +++ b/ioctl/config/configsetget.go @@ -27,6 +27,8 @@ const ( _localPattern = "localhost" _endpointPattern = "(" + _ipPattern + "|(" + _domainPattern + ")" + "|(" + _localPattern + "))" + `(:\d{1,5})?` _defaultAnalyserEndpoint = "https://iotex-analyser-api-mainnet.chainanalytics.org" + // _defaultZnodeContractAddress default znode contract address + _defaultZnodeContractAddress = "0x190Cc9af23504ac5Dc461376C1e2319bc3B9cD29" ) var ( @@ -148,6 +150,10 @@ func Get(arg string) error { fmt.Println(ReadConfig.Nsv2height) case "analyserEndpoint": fmt.Println(ReadConfig.AnalyserEndpoint) + case "znodeEndpoint": + fmt.Println(ReadConfig.ZnodeEndpoint) + case "znodeContractAddress": + fmt.Println(ReadConfig.ZnodeContractAddress) case "all": fmt.Println(ReadConfig.String()) } @@ -276,6 +282,10 @@ func set(args []string) error { return output.NewError(output.ValidationError, "invalid height", nil) } ReadConfig.Nsv2height = height + case "znodeEndpoint": + ReadConfig.ZnodeEndpoint = args[1] + case "znodeContractAddress": + ReadConfig.ZnodeContractAddress = args[1] } err := writeConfig() if err != nil { @@ -294,6 +304,8 @@ func reset() error { ReadConfig.Explorer = "iotexscan" ReadConfig.Language = "English" ReadConfig.AnalyserEndpoint = _defaultAnalyserEndpoint + ReadConfig.ZnodeEndpoint = "" + ReadConfig.ZnodeContractAddress = _defaultZnodeContractAddress err := writeConfig() if err != nil { diff --git a/ioctl/newcmd/config/config.go b/ioctl/newcmd/config/config.go index 6e694a51ab..4127ca8607 100644 --- a/ioctl/newcmd/config/config.go +++ b/ioctl/newcmd/config/config.go @@ -34,6 +34,8 @@ const ( _endpointPattern = "(" + _ipPattern + "|(" + _domainPattern + ")" + "|(" + _localPattern + "))" + `(:\d{1,5})?` _defaultAnalyserEndpoint = "https://iotex-analyser-api-mainnet.chainanalytics.org" _defaultConfigFileName = "config.default" + // _defaultZnodeContractAddress default znode contract address + _defaultZnodeContractAddress = "0x190Cc9af23504ac5Dc461376C1e2319bc3B9cD29" ) var ( @@ -115,6 +117,10 @@ func InitConfig() (config.Config, string, error) { info.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint completeness = false } + if info.readConfig.ZnodeContractAddress == "" { + info.readConfig.ZnodeContractAddress = _defaultZnodeContractAddress + completeness = false + } if !completeness { if err = info.writeConfig(); err != nil { return info.readConfig, info.defaultConfigFile, err @@ -144,6 +150,8 @@ func (c *info) reset() error { c.readConfig.Explorer = _validExpl[0] c.readConfig.Language = _supportedLanguage[0] c.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint + c.readConfig.ZnodeEndpoint = "" + c.readConfig.ZnodeContractAddress = _defaultZnodeContractAddress err := c.writeConfig() if err != nil { @@ -202,6 +210,10 @@ func (c *info) set(args []string, insecure bool, client ioctl.Client) (string, e return "", errors.Wrapf(err, "invalid height %d", height) } c.readConfig.Nsv2height = height + case "znodeEndpoint": + c.readConfig.ZnodeEndpoint = args[1] + case "znodeContractAddress": + c.readConfig.ZnodeContractAddress = args[1] default: return "", config.ErrConfigNotMatch } @@ -237,6 +249,10 @@ func (c *info) get(arg string) (string, error) { return strconv.FormatUint(c.readConfig.Nsv2height, 10), nil case "analyserEndpoint": return c.readConfig.AnalyserEndpoint, nil + case "znodeEndpoint": + return c.readConfig.ZnodeEndpoint, nil + case "znodeContractAddress": + return c.readConfig.ZnodeContractAddress, nil case "all": return jsonString(c.readConfig) default: diff --git a/ioctl/newcmd/config/config_test.go b/ioctl/newcmd/config/config_test.go index b9d0619dc2..f4659d61bf 100644 --- a/ioctl/newcmd/config/config_test.go +++ b/ioctl/newcmd/config/config_test.go @@ -47,13 +47,15 @@ func TestConfigGet(t *testing.T) { require := require.New(t) testPath := t.TempDir() info := newInfo(config.Config{ - Wallet: testPath, - SecureConnect: true, - Aliases: make(map[string]string), - DefaultAccount: config.Context{AddressOrAlias: "test"}, - Explorer: "iotexscan", - Language: "English", - AnalyserEndpoint: "testAnalyser", + Wallet: testPath, + SecureConnect: true, + Aliases: make(map[string]string), + DefaultAccount: config.Context{AddressOrAlias: "test"}, + Explorer: "iotexscan", + Language: "English", + AnalyserEndpoint: "testAnalyser", + ZnodeEndpoint: "testZnodeEndpoint", + ZnodeContractAddress: "testZnodeContractAddress", }, testPath) tcs := []struct { @@ -88,9 +90,17 @@ func TestConfigGet(t *testing.T) { "analyserEndpoint", "testAnalyser", }, + { + "znodeEndpoint", + "testZnodeEndpoint", + }, + { + "znodeContractAddress", + "testZnodeContractAddress", + }, { "all", - "\"endpoint\": \"\",\n \"secureConnect\": true,\n \"aliases\": {},\n \"defaultAccount\": {\n \"addressOrAlias\": \"test\"\n },\n \"explorer\": \"iotexscan\",\n \"language\": \"English\",\n \"nsv2height\": 0,\n \"analyserEndpoint\": \"testAnalyser\"\n}", + "\"endpoint\": \"\",\n \"secureConnect\": true,\n \"aliases\": {},\n \"defaultAccount\": {\n \"addressOrAlias\": \"test\"\n },\n \"explorer\": \"iotexscan\",\n \"language\": \"English\",\n \"nsv2height\": 0,\n \"analyserEndpoint\": \"testAnalyser\",\n \"znodeEndpoint\": \"testZnodeEndpoint\",\n \"znodeContractAddress\": \"testZnodeContractAddress\"\n}", }, } @@ -110,13 +120,15 @@ func TestConfigReset(t *testing.T) { cfgFile := fmt.Sprintf("%s/%s", cfgDir, "config.test") info := newInfo(config.Config{ - Wallet: "wallet", - Endpoint: "testEndpoint", - SecureConnect: false, - DefaultAccount: config.Context{AddressOrAlias: ""}, - Explorer: "explorer", - Language: "Croatian", - AnalyserEndpoint: "testAnalyser", + Wallet: "wallet", + Endpoint: "testEndpoint", + SecureConnect: false, + DefaultAccount: config.Context{AddressOrAlias: ""}, + Explorer: "explorer", + Language: "Croatian", + AnalyserEndpoint: "testAnalyser", + ZnodeEndpoint: "testZnodeEndpoint", + ZnodeContractAddress: "testZnodeContractAddress", }, cfgFile) // write the config to the temp dir and then reset @@ -131,6 +143,8 @@ func TestConfigReset(t *testing.T) { require.Equal("testAnalyser", cfg.AnalyserEndpoint) require.Equal("explorer", cfg.Explorer) require.Equal(config.Context{AddressOrAlias: ""}, cfg.DefaultAccount) + require.Equal("testZnodeEndpoint", cfg.ZnodeEndpoint) + require.Equal("testZnodeContractAddress", cfg.ZnodeContractAddress) require.NoError(info.reset()) require.NoError(info.loadConfig()) @@ -144,6 +158,8 @@ func TestConfigReset(t *testing.T) { require.Equal(_defaultAnalyserEndpoint, resetCfg.AnalyserEndpoint) require.Equal("iotexscan", resetCfg.Explorer) require.Equal(*new(config.Context), resetCfg.DefaultAccount) + require.Equal("", resetCfg.ZnodeEndpoint) + require.Equal(_defaultZnodeContractAddress, resetCfg.ZnodeContractAddress) } func TestConfigSet(t *testing.T) { @@ -209,6 +225,14 @@ func TestConfigSet(t *testing.T) { []string{"unknownField", ""}, "no matching config", }, + { + []string{"znodeEndpoint", "testZnodeEndpoint"}, + "testZnodeEndpoint", + }, + { + []string{"znodeContractAddress", "testZnodeContractAddress"}, + "testZnodeContractAddress", + }, } for _, tc := range tcs { From cdef48b7c0977982be1a53edb3f875b70dcf1797 Mon Sep 17 00:00:00 2001 From: saito Date: Tue, 21 Nov 2023 18:57:34 +0800 Subject: [PATCH 02/14] feat(ioctl): add znode commands configs --- ioctl/config/config.go | 4 +++ ioctl/config/configsetget.go | 16 +++++++-- ioctl/newcmd/config/config.go | 16 +++++++++ ioctl/newcmd/config/config_test.go | 54 +++++++++++++++++++++--------- 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/ioctl/config/config.go b/ioctl/config/config.go index 76f9ecdb99..ed722292b6 100644 --- a/ioctl/config/config.go +++ b/ioctl/config/config.go @@ -67,6 +67,10 @@ type Config struct { Language string `json:"language" yaml:"language"` Nsv2height uint64 `json:"nsv2height" yaml:"nsv2height"` AnalyserEndpoint string `json:"analyserEndpoint" yaml:"analyserEndpoint"` + // ZnodeEndpint IoTeX Zero-node endpint + ZnodeEndpoint string `json:"znodeEndpoint" yaml:"znodeEndpoint"` + // ZnodeContractAddress znode contract address + ZnodeContractAddress string `json:"znodeContractAddress" yaml:"znodeContractAddress"` } var ( diff --git a/ioctl/config/configsetget.go b/ioctl/config/configsetget.go index 3663107243..9b826e5cb5 100644 --- a/ioctl/config/configsetget.go +++ b/ioctl/config/configsetget.go @@ -27,12 +27,14 @@ const ( _localPattern = "localhost" _endpointPattern = "(" + _ipPattern + "|(" + _domainPattern + ")" + "|(" + _localPattern + "))" + `(:\d{1,5})?` _defaultAnalyserEndpoint = "https://iotex-analyser-api-mainnet.chainanalytics.org" + // _defaultZnodeContractAddress default znode contract address + _defaultZnodeContractAddress = "0x190Cc9af23504ac5Dc461376C1e2319bc3B9cD29" ) var ( _supportedLanguage = []string{"English", "中文"} - _validArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height"} - _validGetArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height", "analyserEndpoint", "all"} + _validArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height", "znodeEndpoint", "znodeContractAddress"} + _validGetArgs = []string{"endpoint", "wallet", "explorer", "defaultacc", "language", "nsv2height", "analyserEndpoint", "znodeEndpoint", "znodeContractAddress", "all"} _validExpl = []string{"iotexscan", "iotxplorer"} _endpointCompile = regexp.MustCompile("^" + _endpointPattern + "$") ) @@ -148,6 +150,10 @@ func Get(arg string) error { fmt.Println(ReadConfig.Nsv2height) case "analyserEndpoint": fmt.Println(ReadConfig.AnalyserEndpoint) + case "znodeEndpoint": + fmt.Println(ReadConfig.ZnodeEndpoint) + case "znodeContractAddress": + fmt.Println(ReadConfig.ZnodeContractAddress) case "all": fmt.Println(ReadConfig.String()) } @@ -276,6 +282,10 @@ func set(args []string) error { return output.NewError(output.ValidationError, "invalid height", nil) } ReadConfig.Nsv2height = height + case "znodeEndpoint": + ReadConfig.ZnodeEndpoint = args[1] + case "znodeContractAddress": + ReadConfig.ZnodeContractAddress = args[1] } err := writeConfig() if err != nil { @@ -294,6 +304,8 @@ func reset() error { ReadConfig.Explorer = "iotexscan" ReadConfig.Language = "English" ReadConfig.AnalyserEndpoint = _defaultAnalyserEndpoint + ReadConfig.ZnodeEndpoint = "" + ReadConfig.ZnodeContractAddress = _defaultZnodeContractAddress err := writeConfig() if err != nil { diff --git a/ioctl/newcmd/config/config.go b/ioctl/newcmd/config/config.go index 6e694a51ab..4127ca8607 100644 --- a/ioctl/newcmd/config/config.go +++ b/ioctl/newcmd/config/config.go @@ -34,6 +34,8 @@ const ( _endpointPattern = "(" + _ipPattern + "|(" + _domainPattern + ")" + "|(" + _localPattern + "))" + `(:\d{1,5})?` _defaultAnalyserEndpoint = "https://iotex-analyser-api-mainnet.chainanalytics.org" _defaultConfigFileName = "config.default" + // _defaultZnodeContractAddress default znode contract address + _defaultZnodeContractAddress = "0x190Cc9af23504ac5Dc461376C1e2319bc3B9cD29" ) var ( @@ -115,6 +117,10 @@ func InitConfig() (config.Config, string, error) { info.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint completeness = false } + if info.readConfig.ZnodeContractAddress == "" { + info.readConfig.ZnodeContractAddress = _defaultZnodeContractAddress + completeness = false + } if !completeness { if err = info.writeConfig(); err != nil { return info.readConfig, info.defaultConfigFile, err @@ -144,6 +150,8 @@ func (c *info) reset() error { c.readConfig.Explorer = _validExpl[0] c.readConfig.Language = _supportedLanguage[0] c.readConfig.AnalyserEndpoint = _defaultAnalyserEndpoint + c.readConfig.ZnodeEndpoint = "" + c.readConfig.ZnodeContractAddress = _defaultZnodeContractAddress err := c.writeConfig() if err != nil { @@ -202,6 +210,10 @@ func (c *info) set(args []string, insecure bool, client ioctl.Client) (string, e return "", errors.Wrapf(err, "invalid height %d", height) } c.readConfig.Nsv2height = height + case "znodeEndpoint": + c.readConfig.ZnodeEndpoint = args[1] + case "znodeContractAddress": + c.readConfig.ZnodeContractAddress = args[1] default: return "", config.ErrConfigNotMatch } @@ -237,6 +249,10 @@ func (c *info) get(arg string) (string, error) { return strconv.FormatUint(c.readConfig.Nsv2height, 10), nil case "analyserEndpoint": return c.readConfig.AnalyserEndpoint, nil + case "znodeEndpoint": + return c.readConfig.ZnodeEndpoint, nil + case "znodeContractAddress": + return c.readConfig.ZnodeContractAddress, nil case "all": return jsonString(c.readConfig) default: diff --git a/ioctl/newcmd/config/config_test.go b/ioctl/newcmd/config/config_test.go index b9d0619dc2..f4659d61bf 100644 --- a/ioctl/newcmd/config/config_test.go +++ b/ioctl/newcmd/config/config_test.go @@ -47,13 +47,15 @@ func TestConfigGet(t *testing.T) { require := require.New(t) testPath := t.TempDir() info := newInfo(config.Config{ - Wallet: testPath, - SecureConnect: true, - Aliases: make(map[string]string), - DefaultAccount: config.Context{AddressOrAlias: "test"}, - Explorer: "iotexscan", - Language: "English", - AnalyserEndpoint: "testAnalyser", + Wallet: testPath, + SecureConnect: true, + Aliases: make(map[string]string), + DefaultAccount: config.Context{AddressOrAlias: "test"}, + Explorer: "iotexscan", + Language: "English", + AnalyserEndpoint: "testAnalyser", + ZnodeEndpoint: "testZnodeEndpoint", + ZnodeContractAddress: "testZnodeContractAddress", }, testPath) tcs := []struct { @@ -88,9 +90,17 @@ func TestConfigGet(t *testing.T) { "analyserEndpoint", "testAnalyser", }, + { + "znodeEndpoint", + "testZnodeEndpoint", + }, + { + "znodeContractAddress", + "testZnodeContractAddress", + }, { "all", - "\"endpoint\": \"\",\n \"secureConnect\": true,\n \"aliases\": {},\n \"defaultAccount\": {\n \"addressOrAlias\": \"test\"\n },\n \"explorer\": \"iotexscan\",\n \"language\": \"English\",\n \"nsv2height\": 0,\n \"analyserEndpoint\": \"testAnalyser\"\n}", + "\"endpoint\": \"\",\n \"secureConnect\": true,\n \"aliases\": {},\n \"defaultAccount\": {\n \"addressOrAlias\": \"test\"\n },\n \"explorer\": \"iotexscan\",\n \"language\": \"English\",\n \"nsv2height\": 0,\n \"analyserEndpoint\": \"testAnalyser\",\n \"znodeEndpoint\": \"testZnodeEndpoint\",\n \"znodeContractAddress\": \"testZnodeContractAddress\"\n}", }, } @@ -110,13 +120,15 @@ func TestConfigReset(t *testing.T) { cfgFile := fmt.Sprintf("%s/%s", cfgDir, "config.test") info := newInfo(config.Config{ - Wallet: "wallet", - Endpoint: "testEndpoint", - SecureConnect: false, - DefaultAccount: config.Context{AddressOrAlias: ""}, - Explorer: "explorer", - Language: "Croatian", - AnalyserEndpoint: "testAnalyser", + Wallet: "wallet", + Endpoint: "testEndpoint", + SecureConnect: false, + DefaultAccount: config.Context{AddressOrAlias: ""}, + Explorer: "explorer", + Language: "Croatian", + AnalyserEndpoint: "testAnalyser", + ZnodeEndpoint: "testZnodeEndpoint", + ZnodeContractAddress: "testZnodeContractAddress", }, cfgFile) // write the config to the temp dir and then reset @@ -131,6 +143,8 @@ func TestConfigReset(t *testing.T) { require.Equal("testAnalyser", cfg.AnalyserEndpoint) require.Equal("explorer", cfg.Explorer) require.Equal(config.Context{AddressOrAlias: ""}, cfg.DefaultAccount) + require.Equal("testZnodeEndpoint", cfg.ZnodeEndpoint) + require.Equal("testZnodeContractAddress", cfg.ZnodeContractAddress) require.NoError(info.reset()) require.NoError(info.loadConfig()) @@ -144,6 +158,8 @@ func TestConfigReset(t *testing.T) { require.Equal(_defaultAnalyserEndpoint, resetCfg.AnalyserEndpoint) require.Equal("iotexscan", resetCfg.Explorer) require.Equal(*new(config.Context), resetCfg.DefaultAccount) + require.Equal("", resetCfg.ZnodeEndpoint) + require.Equal(_defaultZnodeContractAddress, resetCfg.ZnodeContractAddress) } func TestConfigSet(t *testing.T) { @@ -209,6 +225,14 @@ func TestConfigSet(t *testing.T) { []string{"unknownField", ""}, "no matching config", }, + { + []string{"znodeEndpoint", "testZnodeEndpoint"}, + "testZnodeEndpoint", + }, + { + []string{"znodeContractAddress", "testZnodeContractAddress"}, + "testZnodeContractAddress", + }, } for _, tc := range tcs { From 0c3a36000f323683f267357163739125d3946d13 Mon Sep 17 00:00:00 2001 From: saito Date: Wed, 22 Nov 2023 01:09:45 +0800 Subject: [PATCH 03/14] feat(ioctl): support znode message committing and querying commands(based #3986) --- ioctl/cmd/root.go | 2 + ioctl/cmd/znode/znode.go | 52 +++++++++++++ ioctl/cmd/znode/znodemessage.go | 52 +++++++++++++ ioctl/cmd/znode/znodemessagequery.go | 84 ++++++++++++++++++++ ioctl/cmd/znode/znodemessagesend.go | 112 +++++++++++++++++++++++++++ 5 files changed, 302 insertions(+) create mode 100644 ioctl/cmd/znode/znode.go create mode 100644 ioctl/cmd/znode/znodemessage.go create mode 100644 ioctl/cmd/znode/znodemessagequery.go create mode 100644 ioctl/cmd/znode/znodemessagesend.go diff --git a/ioctl/cmd/root.go b/ioctl/cmd/root.go index d0bb41a4f3..9535eb8a52 100644 --- a/ioctl/cmd/root.go +++ b/ioctl/cmd/root.go @@ -20,6 +20,7 @@ import ( "github.com/iotexproject/iotex-core/ioctl/cmd/node" "github.com/iotexproject/iotex-core/ioctl/cmd/update" "github.com/iotexproject/iotex-core/ioctl/cmd/version" + "github.com/iotexproject/iotex-core/ioctl/cmd/znode" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" ) @@ -71,6 +72,7 @@ func NewIoctl() *cobra.Command { rootCmd.AddCommand(hdwallet.HdwalletCmd) rootCmd.AddCommand(jwt.JwtCmd) rootCmd.AddCommand(ins.InsCmd) + rootCmd.AddCommand(znode.ZnodeCmd) rootCmd.PersistentFlags().StringVarP(&output.Format, "output-format", "o", "", config.TranslateInLang(_flagOutputFormatUsages, config.UILanguage)) diff --git a/ioctl/cmd/znode/znode.go b/ioctl/cmd/znode/znode.go new file mode 100644 index 0000000000..c45c70bfbf --- /dev/null +++ b/ioctl/cmd/znode/znode.go @@ -0,0 +1,52 @@ +package znode + +import ( + "github.com/spf13/cobra" + + "github.com/iotexproject/iotex-core/ioctl/config" +) + +var ( + // ZnodeCmd represents the znode command + ZnodeCmd = &cobra.Command{ + Use: "znode", + Short: config.TranslateInLang(znodeCmdShorts, config.UILanguage), + } + + // znodeCmdShorts command multi-lang supports + znodeCmdShorts = map[config.Language]string{ + config.English: "Znode operations", + config.Chinese: "Znode 操作", + } + + // + _flagChainEndpointUsages = map[config.Language]string{ + config.English: "set endpoint for once", + config.Chinese: "一次设置端点", + } + _flagZnodeEndpointUsages = map[config.Language]string{ + config.English: "set znode endpoint for once", + config.Chinese: "一次设置znode端点", + } + _flagZnodeContractAddressUsages = map[config.Language]string{ + config.English: "set znode contract address for once", + config.Chinese: "一次设置znode合约地址", + } +) + +func init() { + ZnodeCmd.AddCommand(znodeMessage) + + ZnodeCmd.PersistentFlags().StringVar( + &config.ReadConfig.Endpoint, "endpoint", + config.ReadConfig.Endpoint, config.TranslateInLang(_flagChainEndpointUsages, config.UILanguage), + ) + ZnodeCmd.PersistentFlags().StringVar( + &config.ReadConfig.ZnodeEndpoint, "znode-endpoint", + config.ReadConfig.ZnodeEndpoint, config.TranslateInLang(_flagZnodeEndpointUsages, config.UILanguage), + ) + ZnodeCmd.PersistentFlags().StringVar( + &config.ReadConfig.ZnodeContractAddress, "znode-contract-address", + config.ReadConfig.ZnodeContractAddress, config.TranslateInLang(_flagZnodeContractAddressUsages, config.UILanguage), + ) +} diff --git a/ioctl/cmd/znode/znodemessage.go b/ioctl/cmd/znode/znodemessage.go new file mode 100644 index 0000000000..db1e48d00a --- /dev/null +++ b/ioctl/cmd/znode/znodemessage.go @@ -0,0 +1,52 @@ +package znode + +import ( + "github.com/spf13/cobra" + "time" + + "github.com/iotexproject/iotex-core/ioctl/config" +) + +var ( + // znodeMessage represents the znode message command + znodeMessage = &cobra.Command{ + Use: "message", + Short: config.TranslateInLang(znodeMessageShorts, config.UILanguage), + } + + // znodeMessageShorts znode message shorts multi-lang support + znodeMessageShorts = map[config.Language]string{ + config.English: "znode message operations", + config.Chinese: "znode消息操作", + } +) + +func init() { + znodeMessage.AddCommand(znodeMessageSend) + znodeMessage.AddCommand(znodeMessageQuery) +} + +type sendMessageReq struct { + ProjectID uint64 `json:"projectID"` + ProjectVersion string `json:"projectVersion"` + Data string `json:"data"` +} + +type sendMessageRsp struct { + MessageID string `json:"taskID"` +} + +type queryMessageRsp struct { + ID string `json:"id"` + ProjectID uint64 `json:"projectID"` + ProjectVersion string `json:"projectVersion"` + Data string `json:"data"` + ReceivedAt *time.Time `json:"receivedAt"` + SubmitProvingAt *time.Time `json:"submitProvingAt,omitempty"` + ProofResult string `json:"proofResult,omitempty"` + SubmitToBlockchainAt *time.Time `json:"SubmitToBlockchainAt,omitempty"` + TxHash string `json:"txHash,omitempty"` + Succeed bool `json:"succeed"` + ErrorMessage string `json:"errorMessage,omitempty"` + // TODO field `Status` +} diff --git a/ioctl/cmd/znode/znodemessagequery.go b/ioctl/cmd/znode/znodemessagequery.go new file mode 100644 index 0000000000..9bfa60bb37 --- /dev/null +++ b/ioctl/cmd/znode/znodemessagequery.go @@ -0,0 +1,84 @@ +package znode + +import ( + "encoding/json" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "io" + "net/http" + "net/url" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" +) + +var ( + // znodeMessageQuery represents the znode query message command + znodeMessageQuery = &cobra.Command{ + Use: "query", + Short: config.TranslateInLang(znodeMessageQueryShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + id, err := cmd.Flags().GetString("message-id") + if err != nil { + return errors.Wrap(err, "failed to get flag message-id") + } + + out, err := queryMessageStatus(id) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // znodeMessageSendShorts znode message query shorts multi-lang support + znodeMessageQueryShorts = map[config.Language]string{ + config.English: "query message status from znode", + config.Chinese: "向znode查询消息状态", + } + + _flagMessageIDUsages = map[config.Language]string{ + config.English: "message id", + config.Chinese: "消息ID", + } +) + +func init() { + znodeMessageQuery.Flags().StringP("message-id", "i", "", config.TranslateInLang(_flagMessageIDUsages, config.UILanguage)) + _ = znodeMessageQuery.MarkFlagRequired("message-id") +} + +func queryMessageStatus(id string) (string, error) { + u := url.URL{ + Scheme: "http", + Host: config.ReadConfig.ZnodeEndpoint, + Path: "/message/" + id, + } + + rsp, err := http.Get(u.String()) + if err != nil { + return "", errors.Wrap(err, "call znode failed") + } + defer rsp.Body.Close() + + switch sc := rsp.StatusCode; sc { + case http.StatusNotFound: + return "", errors.Errorf("the message [%s] is not found or expired", id) + case http.StatusOK: + default: + return "", errors.Errorf("responded status code: %d", sc) + } + + rspbody, err := io.ReadAll(rsp.Body) + if err != nil { + return "", errors.Wrap(err, "read responded body failed") + } + + rspdata := &queryMessageRsp{} + if err = json.Unmarshal(rspbody, rspdata); err != nil { + return "", errors.Wrap(err, "parse responded body failed") + } + out, err := json.MarshalIndent(rspdata, "", " ") + return string(out), err +} diff --git a/ioctl/cmd/znode/znodemessagesend.go b/ioctl/cmd/znode/znodemessagesend.go new file mode 100644 index 0000000000..8d81dbfc19 --- /dev/null +++ b/ioctl/cmd/znode/znodemessagesend.go @@ -0,0 +1,112 @@ +package znode + +import ( + "bytes" + "encoding/json" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "io" + "net/http" + "net/url" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" +) + +var ( + // znodeMessageSend represents the znode send message command + znodeMessageSend = &cobra.Command{ + Use: "send", + Short: config.TranslateInLang(znodeMessageSendShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + projectID, err := cmd.Flags().GetUint64("project-id") + if err != nil { + return output.PrintError(err) + } + projectVersion, err := cmd.Flags().GetString("project-version") + if err != nil { + return output.PrintError(err) + } + data, err := cmd.Flags().GetString("data") + if err != nil { + return output.PrintError(err) + } + out, err := sendMessageToZnode(projectID, projectVersion, data) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // znodeMessageSendShorts znode message send shorts multi-lang support + znodeMessageSendShorts = map[config.Language]string{ + config.English: "send message to znode for zk proofing", + config.Chinese: "向znode发送消息请求zk证明", + } + + _flagProjectIDUsages = map[config.Language]string{ + config.English: "project id", + config.Chinese: "项目ID", + } + _flagProjectVersionUsages = map[config.Language]string{ + config.English: "project version", + config.Chinese: "项目版本", + } + _flagSendDataUsages = map[config.Language]string{ + config.English: "send data", + config.Chinese: "要发送的数据", + } +) + +func init() { + znodeMessageSend.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + znodeMessageSend.Flags().StringP("project-version", "v", "", config.TranslateInLang(_flagProjectVersionUsages, config.UILanguage)) + znodeMessageSend.Flags().StringP("data", "d", "", config.TranslateInLang(_flagSendDataUsages, config.UILanguage)) + + _ = znodeMessageSend.MarkFlagRequired("project-id") + _ = znodeMessageSend.MarkFlagRequired("project-version") + _ = znodeMessageSend.MarkFlagRequired("data") +} + +func sendMessageToZnode(projectID uint64, projectVersion string, data string) (string, error) { + reqbody, err := json.Marshal(&sendMessageReq{ + ProjectID: projectID, + ProjectVersion: projectVersion, + Data: data, + }) + if err != nil { + return "", errors.Wrap(err, "failed to build call message") + } + + u := url.URL{ + Scheme: "http", + Host: config.ReadConfig.ZnodeEndpoint, + Path: "/message", + } + + rsp, err := http.Post(u.String(), "application/json", bytes.NewReader(reqbody)) + if err != nil { + return "", errors.Wrap(err, "call znode failed") + } + defer rsp.Body.Close() + + if rsp.StatusCode != http.StatusOK { + return "", errors.Errorf("call znode failed: %s", rsp.Status) + } + + rspbody, err := io.ReadAll(rsp.Body) + if err != nil { + return "", errors.Wrap(err, "failed to read responded content") + } + rspdata := &sendMessageRsp{} + if err = json.Unmarshal(rspbody, rspdata); err != nil { + return "", errors.Wrap(err, "failed to parse responded content") + } + out, err := json.MarshalIndent(rspdata, "", " ") + if err != nil { + return "", errors.Wrap(err, "failed to serialize output") + } + return string(out), err +} From 1ff3a819fd6dacad71b9396c5b1cd9f98b23361d Mon Sep 17 00:00:00 2001 From: saito Date: Wed, 22 Nov 2023 01:14:03 +0800 Subject: [PATCH 04/14] chore: code fmt --- ioctl/cmd/znode/znodemessage.go | 3 ++- ioctl/cmd/znode/znodemessagequery.go | 5 +++-- ioctl/cmd/znode/znodemessagesend.go | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ioctl/cmd/znode/znodemessage.go b/ioctl/cmd/znode/znodemessage.go index db1e48d00a..e9239cb558 100644 --- a/ioctl/cmd/znode/znodemessage.go +++ b/ioctl/cmd/znode/znodemessage.go @@ -1,9 +1,10 @@ package znode import ( - "github.com/spf13/cobra" "time" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/config" ) diff --git a/ioctl/cmd/znode/znodemessagequery.go b/ioctl/cmd/znode/znodemessagequery.go index 9bfa60bb37..62ef19f848 100644 --- a/ioctl/cmd/znode/znodemessagequery.go +++ b/ioctl/cmd/znode/znodemessagequery.go @@ -2,12 +2,13 @@ package znode import ( "encoding/json" - "github.com/pkg/errors" - "github.com/spf13/cobra" "io" "net/http" "net/url" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" ) diff --git a/ioctl/cmd/znode/znodemessagesend.go b/ioctl/cmd/znode/znodemessagesend.go index 8d81dbfc19..423d198297 100644 --- a/ioctl/cmd/znode/znodemessagesend.go +++ b/ioctl/cmd/znode/znodemessagesend.go @@ -3,12 +3,13 @@ package znode import ( "bytes" "encoding/json" - "github.com/pkg/errors" - "github.com/spf13/cobra" "io" "net/http" "net/url" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" ) From 8d0c55404d73631d476338590e2716de0dcf01ea Mon Sep 17 00:00:00 2001 From: saito Date: Wed, 22 Nov 2023 02:08:33 +0800 Subject: [PATCH 05/14] draft --- ioctl/cmd/znode/znode.go | 1 + ioctl/cmd/znode/znodeproject.go | 26 + ioctl/cmd/znode/znodeprojectconst.go | 714 ++++++++++++++++++++++++++ ioctl/cmd/znode/znodeprojectcreate.go | 58 +++ ioctl/cmd/znode/znodeprojectquery.go | 41 ++ ioctl/cmd/znode/znodeprojectupdate.go | 55 ++ 6 files changed, 895 insertions(+) create mode 100644 ioctl/cmd/znode/znodeproject.go create mode 100644 ioctl/cmd/znode/znodeprojectconst.go create mode 100644 ioctl/cmd/znode/znodeprojectcreate.go create mode 100644 ioctl/cmd/znode/znodeprojectquery.go create mode 100644 ioctl/cmd/znode/znodeprojectupdate.go diff --git a/ioctl/cmd/znode/znode.go b/ioctl/cmd/znode/znode.go index c45c70bfbf..3b725bdb7d 100644 --- a/ioctl/cmd/znode/znode.go +++ b/ioctl/cmd/znode/znode.go @@ -36,6 +36,7 @@ var ( func init() { ZnodeCmd.AddCommand(znodeMessage) + ZnodeCmd.AddCommand(znodeProject) ZnodeCmd.PersistentFlags().StringVar( &config.ReadConfig.Endpoint, "endpoint", diff --git a/ioctl/cmd/znode/znodeproject.go b/ioctl/cmd/znode/znodeproject.go new file mode 100644 index 0000000000..aa5c191b4e --- /dev/null +++ b/ioctl/cmd/znode/znodeproject.go @@ -0,0 +1,26 @@ +package znode + +import ( + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/spf13/cobra" +) + +var ( + // znodeProject represents the znode project management command + znodeProject = &cobra.Command{ + Use: "project", + Short: config.TranslateInLang(znodeProjectShorts, config.UILanguage), + } + + // znodeProjectShorts znode project shorts multi-lang support + znodeProjectShorts = map[config.Language]string{ + config.English: "znode project management", + config.Chinese: "znode项目管理", + } +) + +func init() { + znodeProject.AddCommand(znodeProjectCreate) + znodeProject.AddCommand(znodeProjectUpdate) + znodeProject.AddCommand(znodeProjectQuery) +} diff --git a/ioctl/cmd/znode/znodeprojectconst.go b/ioctl/cmd/znode/znodeprojectconst.go new file mode 100644 index 0000000000..7bb000580b --- /dev/null +++ b/ioctl/cmd/znode/znodeprojectconst.go @@ -0,0 +1,714 @@ +package znode + +import ( + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "go.uber.org/zap" + + "github.com/iotexproject/iotex-core/pkg/log" +) + +const _znodeProjectContractJsonABI = `[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721IncorrectOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721InsufficientApproval", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC721InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "ERC721InvalidOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721InvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC721InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC721InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721NonexistentToken", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "projectId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "projectId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "OperatorRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "projectId", + "type": "uint64" + } + ], + "name": "ProjectPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "projectId", + "type": "uint64" + } + ], + "name": "ProjectUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "projectId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "ProjectUpserted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + }, + { + "internalType": "address", + "name": "_operator", + "type": "address" + } + ], + "name": "addOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + } + ], + "name": "canOperateProject", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_uri", + "type": "string" + }, + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + } + ], + "name": "createProject", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + } + ], + "name": "pauseProject", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "projects", + "outputs": [ + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + }, + { + "internalType": "address", + "name": "_operator", + "type": "address" + } + ], + "name": "removeOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + } + ], + "name": "unpauseProject", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_projectId", + "type": "uint64" + }, + { + "internalType": "string", + "name": "_uri", + "type": "string" + }, + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + } + ], + "name": "updateProject", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +]` + +var ( + _znodeProjectContractAddress string + _znodeProjectContractABI abi.ABI +) + +func init() { + var err error + _znodeProjectContractABI, err = abi.JSON(strings.NewReader(_znodeProjectContractJsonABI)) + if err != nil { + log.L().Panic("cannot get abi JSON data", zap.Error(err)) + } +} diff --git a/ioctl/cmd/znode/znodeprojectcreate.go b/ioctl/cmd/znode/znodeprojectcreate.go new file mode 100644 index 0000000000..5848c78a7b --- /dev/null +++ b/ioctl/cmd/znode/znodeprojectcreate.go @@ -0,0 +1,58 @@ +package znode + +import ( + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/spf13/cobra" +) + +var ( + // znodeProjectCreate represents the create znode project command + znodeProjectCreate = &cobra.Command{ + Use: "create", + Short: config.TranslateInLang(znodeProjectCreateShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + uri, err := cmd.Flags().GetString("project-uri") + if err != nil { + return output.PrintError(err) + } + hash, err := cmd.Flags().GetString("project-hash") + if err != nil { + return output.PrintError(err) + } + out, err := createProject(uri, hash) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // znodeProjectSendShorts create znode project shorts multi-lang support + znodeProjectCreateShorts = map[config.Language]string{ + config.English: "create znode project", + config.Chinese: "创建项目", + } + + _flagProjectUriUsages = map[config.Language]string{ + config.English: "project config fetch uri", + config.Chinese: "项目配置拉取地址", + } + _flagProjectHashUsages = map[config.Language]string{ + config.English: "project config hash for validating", + config.Chinese: "项目配置hash", + } +) + +func init() { + znodeProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + znodeProjectCreate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + + _ = znodeProjectCreate.MarkFlagRequired("project-uri") + _ = znodeProjectCreate.MarkFlagRequired("project-hash") +} + +func createProject(uri, hash string) (string, error) { + return "", nil +} diff --git a/ioctl/cmd/znode/znodeprojectquery.go b/ioctl/cmd/znode/znodeprojectquery.go new file mode 100644 index 0000000000..5429d03046 --- /dev/null +++ b/ioctl/cmd/znode/znodeprojectquery.go @@ -0,0 +1,41 @@ +package znode + +import ( + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/spf13/cobra" +) + +var ( + // znodeProjectQuery represents the query znode project command + znodeProjectQuery = &cobra.Command{ + Use: "query", + Short: config.TranslateInLang(znodeProjectQueryShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + id, err := cmd.Flags().GetUint64("project-id") + if err != nil { + return output.PrintError(err) + } + out, err := queryProject(id) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // znodeProjectQueryShorts query znode project shorts multi-lang support + znodeProjectQueryShorts = map[config.Language]string{ + config.English: "query znode project", + config.Chinese: "查询项目", + } +) + +func init() { + +} + +func queryProject(id uint64) (string, error) { + return "", nil +} diff --git a/ioctl/cmd/znode/znodeprojectupdate.go b/ioctl/cmd/znode/znodeprojectupdate.go new file mode 100644 index 0000000000..b7c04e6a34 --- /dev/null +++ b/ioctl/cmd/znode/znodeprojectupdate.go @@ -0,0 +1,55 @@ +package znode + +import ( + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/spf13/cobra" +) + +var ( + // znodeProjectUpdate represents the update znode project command + znodeProjectUpdate = &cobra.Command{ + Use: "update", + Short: config.TranslateInLang(znodeProjectCreateShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + id, err := cmd.Flags().GetUint64("project-id") + if err != nil { + return output.PrintError(err) + } + uri, err := cmd.Flags().GetString("project-uri") + if err != nil { + return output.PrintError(err) + } + hash, err := cmd.Flags().GetString("project-hash") + if err != nil { + return output.PrintError(err) + } + out, err := updateProject(id, uri, hash) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // znodeProjectUpdateShorts update znode project shorts multi-lang support + znodeProjectUpdateShorts = map[config.Language]string{ + config.English: "update znode project", + config.Chinese: "更新项目", + } +) + +func init() { + znodeProjectCreate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + znodeProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + znodeProjectCreate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + + _ = znodeProjectCreate.MarkFlagRequired("project-id") + _ = znodeProjectCreate.MarkFlagRequired("project-uri") + _ = znodeProjectCreate.MarkFlagRequired("project-hash") +} + +func updateProject(id uint64, uri, hash string) (string, error) { + return "", nil +} From 937a89d6e87c98472897c078eb00780edba2914c Mon Sep 17 00:00:00 2001 From: saito Date: Thu, 23 Nov 2023 20:35:29 +0800 Subject: [PATCH 06/14] feat(ioctl): support ws project mgr commands --- ioctl/cmd/action/action.go | 90 +++--- ...{znodeprojectconst.go => znodeproject.abi} | 28 +- ioctl/cmd/znode/znodeproject.go | 270 ++++++++++++++++++ ioctl/cmd/znode/znodeprojectcreate.go | 78 ++++- ioctl/cmd/znode/znodeprojectquery.go | 24 +- ioctl/cmd/znode/znodeprojectupdate.go | 42 ++- 6 files changed, 455 insertions(+), 77 deletions(-) rename ioctl/cmd/znode/{znodeprojectconst.go => znodeproject.abi} (95%) diff --git a/ioctl/cmd/action/action.go b/ioctl/cmd/action/action.go index bb502b0d5f..e1f1b7bab9 100644 --- a/ioctl/cmd/action/action.go +++ b/ioctl/cmd/action/action.go @@ -212,26 +212,6 @@ func fixGasLimit(caller string, execution *action.Execution) (*action.Execution, // SendRaw sends raw action to blockchain func SendRaw(selp *iotextypes.Action) error { - conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) - if err != nil { - return output.NewError(output.NetworkError, "failed to connect to endpoint", err) - } - defer conn.Close() - cli := iotexapi.NewAPIServiceClient(conn) - ctx := context.Background() - - jwtMD, err := util.JwtAuth() - if err == nil { - ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) - } - - request := &iotexapi.SendActionRequest{Action: selp} - if _, err = cli.SendAction(ctx, request); err != nil { - if sta, ok := status.FromError(err); ok { - return output.NewError(output.APIError, sta.Message(), nil) - } - return output.NewError(output.NetworkError, "failed to invoke SendAction api", err) - } shash := hash.Hash256b(byteutil.Must(proto.Marshal(selp))) txhash := hex.EncodeToString(shash[:]) message := sendMessage{Info: "Action has been sent to blockchain.", TxHash: txhash, URL: "https://"} @@ -250,16 +230,48 @@ func SendRaw(selp *iotextypes.Action) error { return nil } +// SendRawAndRespond sends raw action to blockchain with response and error return +func SendRawAndRespond(selp *iotextypes.Action) (*iotexapi.SendActionResponse, error) { + conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) + if err != nil { + return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) + } + defer conn.Close() + cli := iotexapi.NewAPIServiceClient(conn) + ctx := context.Background() + + jwtMD, err := util.JwtAuth() + if err == nil { + ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) + } + + request := &iotexapi.SendActionRequest{Action: selp} + response, err := cli.SendAction(ctx, request) + if err != nil { + if sta, ok := status.FromError(err); ok { + return nil, output.NewError(output.APIError, sta.Message(), nil) + } + return nil, output.NewError(output.NetworkError, "failed to invoke SendAction api", err) + } + return response, nil +} + // SendAction sends signed action to blockchain func SendAction(elp action.Envelope, signer string) error { + _, err := SendActionAndResponse(elp, signer) + return err +} + +// SendActionAndResponse sends signed action to blockchain with response and error return +func SendActionAndResponse(elp action.Envelope, signer string) (*iotexapi.SendActionResponse, error) { prvKey, err := account.PrivateKeyFromSigner(signer, _passwordFlag.Value().(string)) if err != nil { - return err + return nil, err } chainMeta, err := bc.GetChainMeta() if err != nil { - return output.NewError(0, "failed to get chain meta", err) + return nil, output.NewError(0, "failed to get chain meta", err) } elp.SetChainID(chainMeta.GetChainID()) @@ -268,7 +280,7 @@ func SendAction(elp action.Envelope, signer string) error { signer = addr.String() nonce, err := nonce(signer) if err != nil { - return output.NewError(0, "failed to get nonce ", err) + return nil, output.NewError(0, "failed to get nonce ", err) } elp.SetNonce(nonce) } @@ -276,16 +288,16 @@ func SendAction(elp action.Envelope, signer string) error { sealed, err := action.Sign(elp, prvKey) prvKey.Zero() if err != nil { - return output.NewError(output.CryptoError, "failed to sign action", err) + return nil, output.NewError(output.CryptoError, "failed to sign action", err) } if err := isBalanceEnough(signer, sealed); err != nil { - return output.NewError(0, "failed to pass balance check", err) // TODO: undefined error + return nil, output.NewError(0, "failed to pass balance check", err) // TODO: undefined error } selp := sealed.Proto() actionInfo, err := printActionProto(selp) if err != nil { - return output.NewError(0, "failed to print action proto message", err) + return nil, output.NewError(0, "failed to print action proto message", err) } if _yesFlag.Value() == false { @@ -295,47 +307,53 @@ func SendAction(elp action.Envelope, signer string) error { fmt.Println(message.String()) if _, err := fmt.Scanf("%s", &confirm); err != nil { - return output.NewError(output.InputError, "failed to input yes", err) + return nil, output.NewError(output.InputError, "failed to input yes", err) } if !strings.EqualFold(confirm, "yes") { output.PrintResult("quit") - return nil + return nil, nil } } - return SendRaw(selp) + return SendRawAndRespond(selp) } // Execute sends signed execution transaction to blockchain func Execute(contract string, amount *big.Int, bytecode []byte) error { + _, err := ExecuteAndResponse(contract, amount, bytecode) + return err +} + +// ExecuteAndResponse sends signed execution transaction to blockchain and with response and error return +func ExecuteAndResponse(contract string, amount *big.Int, bytecode []byte) (*iotexapi.SendActionResponse, error) { if len(contract) == 0 && len(bytecode) == 0 { - return output.NewError(output.InputError, "failed to deploy contract with empty bytecode", nil) + return nil, output.NewError(output.InputError, "failed to deploy contract with empty bytecode", nil) } gasPriceRau, err := gasPriceInRau() if err != nil { - return output.NewError(0, "failed to get gas price", err) + return nil, output.NewError(0, "failed to get gas price", err) } signer, err := Signer() if err != nil { - return output.NewError(output.AddressError, "failed to get signer address", err) + return nil, output.NewError(output.AddressError, "failed to get signer address", err) } nonce, err := nonce(signer) if err != nil { - return output.NewError(0, "failed to get nonce", err) + return nil, output.NewError(0, "failed to get nonce", err) } gasLimit := _gasLimitFlag.Value().(uint64) tx, err := action.NewExecution(contract, nonce, amount, gasLimit, gasPriceRau, bytecode) if err != nil || tx == nil { - return output.NewError(output.InstantiationError, "failed to make a Execution instance", err) + return nil, output.NewError(output.InstantiationError, "failed to make a Execution instance", err) } if gasLimit == 0 { tx, err = fixGasLimit(signer, tx) if err != nil || tx == nil { - return output.NewError(0, "failed to fix Execution gaslimit", err) + return nil, output.NewError(0, "failed to fix Execution gaslimit", err) } gasLimit = tx.GasLimit() } - return SendAction( + return SendActionAndResponse( (&action.EnvelopeBuilder{}). SetNonce(nonce). SetGasPrice(gasPriceRau). diff --git a/ioctl/cmd/znode/znodeprojectconst.go b/ioctl/cmd/znode/znodeproject.abi similarity index 95% rename from ioctl/cmd/znode/znodeprojectconst.go rename to ioctl/cmd/znode/znodeproject.abi index 7bb000580b..0cdd79290d 100644 --- a/ioctl/cmd/znode/znodeprojectconst.go +++ b/ioctl/cmd/znode/znodeproject.abi @@ -1,15 +1,4 @@ -package znode - -import ( - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "go.uber.org/zap" - - "github.com/iotexproject/iotex-core/pkg/log" -) - -const _znodeProjectContractJsonABI = `[ +[ { "inputs": [], "stateMutability": "nonpayable", @@ -698,17 +687,4 @@ const _znodeProjectContractJsonABI = `[ "stateMutability": "nonpayable", "type": "function" } -]` - -var ( - _znodeProjectContractAddress string - _znodeProjectContractABI abi.ABI -) - -func init() { - var err error - _znodeProjectContractABI, err = abi.JSON(strings.NewReader(_znodeProjectContractJsonABI)) - if err != nil { - log.L().Panic("cannot get abi JSON data", zap.Error(err)) - } -} +] \ No newline at end of file diff --git a/ioctl/cmd/znode/znodeproject.go b/ioctl/cmd/znode/znodeproject.go index aa5c191b4e..8afe7e8464 100644 --- a/ioctl/cmd/znode/znodeproject.go +++ b/ioctl/cmd/znode/znodeproject.go @@ -1,6 +1,30 @@ package znode import ( + "bytes" + "context" + _ "embed" + "encoding/hex" + "fmt" + "github.com/cenkalti/backoff" + "github.com/ethereum/go-ethereum/common" + "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/pkg/errors" + "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "math/big" + "reflect" + "strings" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/spf13/cobra" ) @@ -17,10 +41,256 @@ var ( config.English: "znode project management", config.Chinese: "znode项目管理", } + + _flagProjectRegisterContractAddressUsages = map[config.Language]string{ + config.English: "project register contract address", + config.Chinese: "项目注册合约地址", + } + + znodeProjectRegisterContractAddress string + znodeProjectRegisterContractABI abi.ABI + + //go:embed znodeproject.abi + znodeProjectRegisterContractJsonABI []byte +) + +const ( + createZnodeProjectFuncName = "createProject" + createZnodeProjectEventName = "ProjectUpserted" + updateZnodeProjectFuncName = "updateProject" + queryZnodeProjectFuncName = "projects" ) func init() { + var err error + znodeProjectRegisterContractABI, err = abi.JSON(bytes.NewReader(znodeProjectRegisterContractJsonABI)) + if err != nil { + log.L().Panic("cannot get abi JSON data", zap.Error(err)) + } + znodeProject.AddCommand(znodeProjectCreate) znodeProject.AddCommand(znodeProjectUpdate) znodeProject.AddCommand(znodeProjectQuery) + + znodeProject.PersistentFlags().StringVarP( + &znodeProjectRegisterContractAddress, + "contract-address", + "c", + "", + config.TranslateInLang(_flagProjectRegisterContractAddressUsages, config.UILanguage), + ) + _ = znodeProject.MarkFlagRequired("contract-address") +} + +func convertStringToAbiBytes32(hash string) (interface{}, error) { + t, _ := abi.NewType("bytes32", "", nil) + + bytecode, err := hex.DecodeString(util.TrimHexPrefix(hash)) + if err != nil { + return nil, err + } + + if t.Size != len(bytecode) { + return nil, errors.New("invalid arg") + } + + bytesType := reflect.ArrayOf(t.Size, reflect.TypeOf(uint8(0))) + bytesVal := reflect.New(bytesType).Elem() + + for i, b := range bytecode { + bytesVal.Index(i).Set(reflect.ValueOf(b)) + } + + return bytesVal.Interface(), nil +} + +func waitReceiptByActionHash(h string) (*iotexapi.GetReceiptByActionResponse, error) { + conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure) + if err != nil { + return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err) + } + defer conn.Close() + cli := iotexapi.NewAPIServiceClient(conn) + ctx := context.Background() + + jwtMD, err := util.JwtAuth() + if err == nil { + ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) + } + + var rsp *iotexapi.GetReceiptByActionResponse + err = backoff.Retry(func() error { + rsp, err = cli.GetReceiptByAction(ctx, &iotexapi.GetReceiptByActionRequest{ + ActionHash: h, + }) + return err + }, backoff.WithMaxRetries(backoff.NewConstantBackOff(30*time.Second), 3)) + if err != nil { + sta, ok := status.FromError(err) + if ok && sta.Code() == codes.NotFound { + return nil, output.NewError(output.APIError, "not found", nil) + } else if ok { + return nil, output.NewError(output.APIError, sta.Message(), nil) + } + return nil, output.NewError(output.NetworkError, "failed to invoke GetReceiptByAction api", err) + } + return rsp, nil +} + +func getEventInputsByName(logs []*iotextypes.Log, eventName string) (map[string]any, error) { + var ( + abievent *abi.Event + log *iotextypes.Log + ) + for _, l := range logs { + evabi, err := znodeProjectRegisterContractABI.EventByID(common.BytesToHash(l.Topics[0])) + if err != nil { + return nil, errors.Wrapf(err, "get event abi from topic %v failed", l.Topics[0]) + } + if evabi.Name == eventName { + abievent, log = evabi, l + break + } + } + + if abievent == nil || log == nil { + return nil, errors.Errorf("event not found: %s", eventName) + } + + inputs := make(map[string]any) + if len(log.Data) > 0 { + if err := abievent.Inputs.UnpackIntoMap(inputs, log.Data); err != nil { + return nil, errors.Wrap(err, "unpack event data failed") + } + } + args := make(abi.Arguments, 0) + for _, arg := range abievent.Inputs { + if arg.Indexed { + args = append(args, arg) + } + } + topics := make([]common.Hash, 0) + for i, topic := range log.Topics { + if i > 0 { + topics = append(topics, common.BytesToHash(topic)) + } + } + if err := abi.ParseTopicsIntoMap(inputs, args, topics); err != nil { + return nil, errors.Wrap(err, "unpack event indexed fields failed") + } + + return inputs, nil +} + +func parseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { + resultBytes, err := hex.DecodeString(result) + if err != nil { + return "", errors.Wrap(err, "failed to decode result") + } + + var ( + outputArgs = targetAbi.Methods[targetMethod].Outputs + tupleStr = make([]string, 0, len(outputArgs)) + ) + + v, err := targetAbi.Unpack(targetMethod, resultBytes) + if err != nil { + return "", errors.Wrap(err, "failed to parse output") + } + + if len(outputArgs) == 1 { + elemStr, _ := parseOutputArgument(v[0], &outputArgs[0].Type) + return elemStr, nil + } + + for i, field := range v { + elemStr, _ := parseOutputArgument(field, &outputArgs[i].Type) + tupleStr = append(tupleStr, outputArgs[i].Name+":"+elemStr) + } + return "{" + strings.Join(tupleStr, " ") + "}", nil +} + +func parseOutputArgument(v interface{}, t *abi.Type) (string, bool) { + str := fmt.Sprint(v) + ok := false + + switch t.T { + case abi.StringTy, abi.BoolTy: + // case abi.StringTy & abi.BoolTy can be handled by fmt.Sprint() + ok = true + + case abi.TupleTy: + if reflect.TypeOf(v).Kind() == reflect.Struct { + ok = true + + tupleStr := make([]string, 0, len(t.TupleElems)) + for i, elem := range t.TupleElems { + elemStr, elemOk := parseOutputArgument(reflect.ValueOf(v).Field(i).Interface(), elem) + tupleStr = append(tupleStr, t.TupleRawNames[i]+":"+elemStr) + ok = ok && elemOk + } + + str = "{" + strings.Join(tupleStr, " ") + "}" + } + + case abi.SliceTy, abi.ArrayTy: + if reflect.TypeOf(v).Kind() == reflect.Slice || reflect.TypeOf(v).Kind() == reflect.Array { + ok = true + + value := reflect.ValueOf(v) + sliceStr := make([]string, 0, value.Len()) + for i := 0; i < value.Len(); i++ { + elemStr, elemOk := parseOutputArgument(value.Index(i).Interface(), t.Elem) + sliceStr = append(sliceStr, elemStr) + ok = ok && elemOk + } + + str = "[" + strings.Join(sliceStr, " ") + "]" + } + + case abi.IntTy, abi.UintTy: + if reflect.TypeOf(v) == reflect.TypeOf(big.NewInt(0)) { + var bigInt *big.Int + bigInt, ok = v.(*big.Int) + if ok { + str = bigInt.String() + } + } else if 2 <= reflect.TypeOf(v).Kind() && reflect.TypeOf(v).Kind() <= 11 { + // other integer types (int8,uint16,...) can be handled by fmt.Sprint(v) + ok = true + } + + case abi.AddressTy: + if reflect.TypeOf(v) == reflect.TypeOf(common.Address{}) { + var ethAddr common.Address + ethAddr, ok = v.(common.Address) + if ok { + ioAddress, err := address.FromBytes(ethAddr.Bytes()) + if err == nil { + str = ioAddress.String() + } + } + } + + case abi.BytesTy: + if reflect.TypeOf(v) == reflect.TypeOf([]byte{}) { + var bytes []byte + bytes, ok = v.([]byte) + if ok { + str = "0x" + hex.EncodeToString(bytes) + } + } + + case abi.FixedBytesTy, abi.FunctionTy: + if reflect.TypeOf(v).Kind() == reflect.Array && reflect.TypeOf(v).Elem() == reflect.TypeOf(byte(0)) { + bytesValue := reflect.ValueOf(v) + byteSlice := reflect.MakeSlice(reflect.TypeOf([]byte{}), bytesValue.Len(), bytesValue.Len()) + reflect.Copy(byteSlice, bytesValue) + + str = "0x" + hex.EncodeToString(byteSlice.Bytes()) + ok = true + } + } + + return str, ok } diff --git a/ioctl/cmd/znode/znodeprojectcreate.go b/ioctl/cmd/znode/znodeprojectcreate.go index 5848c78a7b..4376b8e343 100644 --- a/ioctl/cmd/znode/znodeprojectcreate.go +++ b/ioctl/cmd/znode/znodeprojectcreate.go @@ -1,9 +1,14 @@ package znode import ( + "fmt" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/pkg/errors" "github.com/spf13/cobra" + "math/big" ) var ( @@ -43,16 +48,85 @@ var ( config.English: "project config hash for validating", config.Chinese: "项目配置hash", } + /* + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "projects", + "outputs": [ + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + + */ ) func init() { znodeProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) - znodeProjectCreate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + znodeProjectCreate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + znodeProjectCreate.Flags().StringP("contract-address", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = znodeProjectCreate.MarkFlagRequired("project-uri") _ = znodeProjectCreate.MarkFlagRequired("project-hash") } func createProject(uri, hash string) (string, error) { - return "", nil + contract, err := util.Address(znodeProjectRegisterContractAddress) + if err != nil { + return "", output.NewError(output.AddressError, "failed to get project register contract address", err) + } + + hashArg, err := convertStringToAbiBytes32(hash) + if err != nil { + return "", err + } + + bytecode, err := znodeProjectRegisterContractABI.Pack( + createZnodeProjectFuncName, + uri, hashArg, + ) + if err != nil { + return "", output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) + } + + res, err := action.ExecuteAndResponse(contract, big.NewInt(0), bytecode) + if err != nil { + return "", errors.Wrap(err, "execute contract failed") + } + + r, err := waitReceiptByActionHash(res.ActionHash) + if err != nil { + return "", errors.Wrap(err, "wait contract execution receipt failed") + } + + inputs, err := getEventInputsByName(r.ReceiptInfo.Receipt.Logs, createZnodeProjectEventName) + if err != nil { + return "", errors.Wrap(err, "get receipt event failed") + } + projectid, ok := inputs["projectId"] + if !ok { + return "", errors.New("result not found in event inputs") + } + return fmt.Sprint(projectid), nil } diff --git a/ioctl/cmd/znode/znodeprojectquery.go b/ioctl/cmd/znode/znodeprojectquery.go index 5429d03046..655ccd97d9 100644 --- a/ioctl/cmd/znode/znodeprojectquery.go +++ b/ioctl/cmd/znode/znodeprojectquery.go @@ -1,8 +1,13 @@ package znode import ( + "fmt" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -33,9 +38,26 @@ var ( ) func init() { + znodeProjectQuery.Flags().Uint64P("project-id", "i", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + _ = znodeProjectQuery.MarkFlagRequired("project-id") } func queryProject(id uint64) (string, error) { - return "", nil + contract, err := util.Address(znodeProjectRegisterContractAddress) + if err != nil { + return "", output.NewError(output.AddressError, "failed to get project register contract address", err) + } + + bytecode, err := znodeProjectRegisterContractABI.Pack(queryZnodeProjectFuncName, id) + if err != nil { + return "", output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) + } + + addr, _ := address.FromString(contract) + data, err := action.Read(addr, "0", bytecode) + if err != nil { + return "", errors.Wrap(err, "read contract failed") + } + return parseOutput(&znodeProjectRegisterContractABI, queryZnodeProjectFuncName, data) } diff --git a/ioctl/cmd/znode/znodeprojectupdate.go b/ioctl/cmd/znode/znodeprojectupdate.go index b7c04e6a34..6b6aed38da 100644 --- a/ioctl/cmd/znode/znodeprojectupdate.go +++ b/ioctl/cmd/znode/znodeprojectupdate.go @@ -1,16 +1,21 @@ package znode import ( + "fmt" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/pkg/errors" "github.com/spf13/cobra" + "math/big" ) var ( // znodeProjectUpdate represents the update znode project command znodeProjectUpdate = &cobra.Command{ Use: "update", - Short: config.TranslateInLang(znodeProjectCreateShorts, config.UILanguage), + Short: config.TranslateInLang(znodeProjectUpdateShorts, config.UILanguage), RunE: func(cmd *cobra.Command, args []string) error { id, err := cmd.Flags().GetUint64("project-id") if err != nil { @@ -24,12 +29,7 @@ var ( if err != nil { return output.PrintError(err) } - out, err := updateProject(id, uri, hash) - if err != nil { - return output.PrintError(err) - } - output.PrintResult(out) - return nil + return output.PrintError(updateProject(id, uri, hash)) }, } @@ -41,15 +41,33 @@ var ( ) func init() { - znodeProjectCreate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) - znodeProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) - znodeProjectCreate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + znodeProjectUpdate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + znodeProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + znodeProjectUpdate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = znodeProjectCreate.MarkFlagRequired("project-id") _ = znodeProjectCreate.MarkFlagRequired("project-uri") _ = znodeProjectCreate.MarkFlagRequired("project-hash") } -func updateProject(id uint64, uri, hash string) (string, error) { - return "", nil +func updateProject(projectID uint64, uri, hash string) error { + contract, err := util.Address(znodeProjectRegisterContractAddress) + if err != nil { + return output.NewError(output.AddressError, "failed to get project register contract address", err) + } + + hashArg, err := convertStringToAbiBytes32(hash) + if err != nil { + return errors.Wrap(err, "convert input arg failed") + } + + bytecode, err := znodeProjectRegisterContractABI.Pack( + updateZnodeProjectFuncName, + projectID, uri, hashArg, + ) + if err != nil { + return output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) + } + + return action.Execute(contract, big.NewInt(0), bytecode) } From 7c9b35a3bf69a800cef49ecebcb5def9da3a7c7a Mon Sep 17 00:00:00 2001 From: saito Date: Fri, 24 Nov 2023 14:39:37 +0800 Subject: [PATCH 07/14] feat(ioctl): support w3bstream message committing and querying commands(based #3986) --- ioctl/cmd/root.go | 2 + ioctl/cmd/ws/ws.go | 44 +++++++++++++ ioctl/cmd/ws/wsmessage.go | 47 ++++++++++++++ ioctl/cmd/ws/wsmessagequery.go | 85 +++++++++++++++++++++++++ ioctl/cmd/ws/wsmessagesend.go | 113 +++++++++++++++++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 ioctl/cmd/ws/ws.go create mode 100644 ioctl/cmd/ws/wsmessage.go create mode 100644 ioctl/cmd/ws/wsmessagequery.go create mode 100644 ioctl/cmd/ws/wsmessagesend.go diff --git a/ioctl/cmd/root.go b/ioctl/cmd/root.go index d0bb41a4f3..84129b9b88 100644 --- a/ioctl/cmd/root.go +++ b/ioctl/cmd/root.go @@ -20,6 +20,7 @@ import ( "github.com/iotexproject/iotex-core/ioctl/cmd/node" "github.com/iotexproject/iotex-core/ioctl/cmd/update" "github.com/iotexproject/iotex-core/ioctl/cmd/version" + "github.com/iotexproject/iotex-core/ioctl/cmd/ws" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" ) @@ -71,6 +72,7 @@ func NewIoctl() *cobra.Command { rootCmd.AddCommand(hdwallet.HdwalletCmd) rootCmd.AddCommand(jwt.JwtCmd) rootCmd.AddCommand(ins.InsCmd) + rootCmd.AddCommand(ws.WsCmd) rootCmd.PersistentFlags().StringVarP(&output.Format, "output-format", "o", "", config.TranslateInLang(_flagOutputFormatUsages, config.UILanguage)) diff --git a/ioctl/cmd/ws/ws.go b/ioctl/cmd/ws/ws.go new file mode 100644 index 0000000000..2f7d1b4dec --- /dev/null +++ b/ioctl/cmd/ws/ws.go @@ -0,0 +1,44 @@ +package ws + +import ( + "github.com/spf13/cobra" + + "github.com/iotexproject/iotex-core/ioctl/config" +) + +var ( + // WsCmd represents the w3bstream command + WsCmd = &cobra.Command{ + Use: "ws", + Short: config.TranslateInLang(wsCmdShorts, config.UILanguage), + } + + // wsCmdShorts command multi-lang supports + wsCmdShorts = map[config.Language]string{ + config.English: "W3bstream node operations", + config.Chinese: "W3bstream节点操作", + } + + _flagChainEndpointUsages = map[config.Language]string{ + config.English: "set endpoint for once", + config.Chinese: "一次设置端点", + } + + _flagWsEndpointUsages = map[config.Language]string{ + config.English: "set w3bsteram endpoint for once", + config.Chinese: "一次设置w3bstream端点", + } +) + +func init() { + WsCmd.AddCommand(wsMessage) + + WsCmd.PersistentFlags().StringVar( + &config.ReadConfig.Endpoint, "endpoint", + config.ReadConfig.Endpoint, config.TranslateInLang(_flagChainEndpointUsages, config.UILanguage), + ) + WsCmd.PersistentFlags().StringVar( + &config.ReadConfig.WsEndpoint, "ws-endpoint", + config.ReadConfig.WsEndpoint, config.TranslateInLang(_flagWsEndpointUsages, config.UILanguage), + ) +} diff --git a/ioctl/cmd/ws/wsmessage.go b/ioctl/cmd/ws/wsmessage.go new file mode 100644 index 0000000000..79a2d3d506 --- /dev/null +++ b/ioctl/cmd/ws/wsmessage.go @@ -0,0 +1,47 @@ +package ws + +import ( + "time" + + "github.com/spf13/cobra" + + "github.com/iotexproject/iotex-core/ioctl/config" +) + +var ( + // wsMessage represents the w3bstream message command + wsMessage = &cobra.Command{ + Use: "message", + Short: config.TranslateInLang(wsMessageShorts, config.UILanguage), + } + + // wsMessageShorts w3bstream message shorts multi-lang support + wsMessageShorts = map[config.Language]string{ + config.English: "w3bstream message operations", + config.Chinese: "w3bstream消息操作", + } +) + +func init() { + wsMessage.AddCommand(wsMessageSend) + wsMessage.AddCommand(wsMessageQuery) +} + +type sendMessageReq struct { + ProjectID uint64 `json:"projectID"` + ProjectVersion string `json:"projectVersion"` + Data string `json:"data"` +} + +type sendMessageRsp struct { + MessageID string `json:"messageID"` +} + +type queryMessageRsp struct { + MessageID string `json:"messageID"` + States []struct { + State string `json:"state"` + Time time.Time `json:"time"` + Description string `json:"description"` + } `json:"states"` +} diff --git a/ioctl/cmd/ws/wsmessagequery.go b/ioctl/cmd/ws/wsmessagequery.go new file mode 100644 index 0000000000..5b050c3bb8 --- /dev/null +++ b/ioctl/cmd/ws/wsmessagequery.go @@ -0,0 +1,85 @@ +package ws + +import ( + "encoding/json" + "io" + "net/http" + "net/url" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" +) + +var ( + // wsMessageQuery represents the w3bstream query message command + wsMessageQuery = &cobra.Command{ + Use: "query", + Short: config.TranslateInLang(wsMessageQueryShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + id, err := cmd.Flags().GetString("message-id") + if err != nil { + return errors.Wrap(err, "failed to get flag message-id") + } + + out, err := queryMessageStatus(id) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // wsMessageSendShorts w3bstream message query shorts multi-lang support + wsMessageQueryShorts = map[config.Language]string{ + config.English: "query message status from w3bstream", + config.Chinese: "向w3bstream查询消息状态", + } + + _flagMessageIDUsages = map[config.Language]string{ + config.English: "message id", + config.Chinese: "消息ID", + } +) + +func init() { + wsMessageQuery.Flags().StringP("message-id", "i", "", config.TranslateInLang(_flagMessageIDUsages, config.UILanguage)) + _ = wsMessageQuery.MarkFlagRequired("message-id") +} + +func queryMessageStatus(id string) (string, error) { + u := url.URL{ + Scheme: "http", + Host: config.ReadConfig.WsEndpoint, + Path: "/message/" + id, + } + + rsp, err := http.Get(u.String()) + if err != nil { + return "", errors.Wrap(err, "call w3bstream failed") + } + defer rsp.Body.Close() + + switch sc := rsp.StatusCode; sc { + case http.StatusNotFound: + return "", errors.Errorf("the message [%s] is not found or expired", id) + case http.StatusOK: + default: + return "", errors.Errorf("responded status code: %d", sc) + } + + rspbody, err := io.ReadAll(rsp.Body) + if err != nil { + return "", errors.Wrap(err, "read responded body failed") + } + + rspdata := &queryMessageRsp{} + if err = json.Unmarshal(rspbody, rspdata); err != nil { + return "", errors.Wrap(err, "parse responded body failed") + } + out, err := json.MarshalIndent(rspdata, "", " ") + return string(out), err +} diff --git a/ioctl/cmd/ws/wsmessagesend.go b/ioctl/cmd/ws/wsmessagesend.go new file mode 100644 index 0000000000..2362040e0c --- /dev/null +++ b/ioctl/cmd/ws/wsmessagesend.go @@ -0,0 +1,113 @@ +package ws + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/iotexproject/iotex-core/ioctl/config" + "github.com/iotexproject/iotex-core/ioctl/output" +) + +var ( + // wsMessageSend represents the w3bstream send message command + wsMessageSend = &cobra.Command{ + Use: "send", + Short: config.TranslateInLang(wsMessageSendShorts, config.UILanguage), + RunE: func(cmd *cobra.Command, args []string) error { + projectID, err := cmd.Flags().GetUint64("project-id") + if err != nil { + return output.PrintError(err) + } + projectVersion, err := cmd.Flags().GetString("project-version") + if err != nil { + return output.PrintError(err) + } + data, err := cmd.Flags().GetString("data") + if err != nil { + return output.PrintError(err) + } + out, err := sendMessage(projectID, projectVersion, data) + if err != nil { + return output.PrintError(err) + } + output.PrintResult(out) + return nil + }, + } + + // wsMessageSendShorts w3bstream message send shorts multi-lang support + wsMessageSendShorts = map[config.Language]string{ + config.English: "send message to w3bstream for zk proofing", + config.Chinese: "向w3bstream发送消息请求zk证明", + } + + _flagProjectIDUsages = map[config.Language]string{ + config.English: "project id", + config.Chinese: "项目ID", + } + _flagProjectVersionUsages = map[config.Language]string{ + config.English: "project version", + config.Chinese: "项目版本", + } + _flagSendDataUsages = map[config.Language]string{ + config.English: "send data", + config.Chinese: "要发送的数据", + } +) + +func init() { + wsMessageSend.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + wsMessageSend.Flags().StringP("project-version", "v", "", config.TranslateInLang(_flagProjectVersionUsages, config.UILanguage)) + wsMessageSend.Flags().StringP("data", "d", "", config.TranslateInLang(_flagSendDataUsages, config.UILanguage)) + + _ = wsMessageSend.MarkFlagRequired("project-id") + _ = wsMessageSend.MarkFlagRequired("project-version") + _ = wsMessageSend.MarkFlagRequired("data") +} + +func sendMessage(projectID uint64, projectVersion string, data string) (string, error) { + reqbody, err := json.Marshal(&sendMessageReq{ + ProjectID: projectID, + ProjectVersion: projectVersion, + Data: data, + }) + if err != nil { + return "", errors.Wrap(err, "failed to build call message") + } + + u := url.URL{ + Scheme: "http", + Host: config.ReadConfig.WsEndpoint, + Path: "/message", + } + + rsp, err := http.Post(u.String(), "application/json", bytes.NewReader(reqbody)) + if err != nil { + return "", errors.Wrap(err, "call w3bsteam failed") + } + defer rsp.Body.Close() + + if rsp.StatusCode != http.StatusOK { + return "", errors.Errorf("call w3bsteam failed: %s", rsp.Status) + } + + rspbody, err := io.ReadAll(rsp.Body) + if err != nil { + return "", errors.Wrap(err, "failed to read responded content") + } + rspdata := &sendMessageRsp{} + if err = json.Unmarshal(rspbody, rspdata); err != nil { + return "", errors.Wrap(err, "failed to parse responded content") + } + out, err := json.MarshalIndent(rspdata, "", " ") + if err != nil { + return "", errors.Wrap(err, "failed to serialize output") + } + return string(out), err +} From ae56452b67e30ffad35760cb9307913b20bafcb4 Mon Sep 17 00:00:00 2001 From: saito Date: Fri, 24 Nov 2023 14:57:34 +0800 Subject: [PATCH 08/14] feat(ioctl): ws node project management --- .../znodeproject.go => ws/wsproject.go} | 48 ++++---- .../znodeproject.abi => ws/wsproject.json} | 0 .../wsprojectcreate.go} | 64 +++------- .../wsprojectquery.go} | 24 ++-- .../wsprojectupdate.go} | 32 ++--- ioctl/cmd/znode/znode.go | 53 -------- ioctl/cmd/znode/znodemessage.go | 53 -------- ioctl/cmd/znode/znodemessagequery.go | 85 ------------- ioctl/cmd/znode/znodemessagesend.go | 113 ------------------ 9 files changed, 68 insertions(+), 404 deletions(-) rename ioctl/cmd/{znode/znodeproject.go => ws/wsproject.go} (85%) rename ioctl/cmd/{znode/znodeproject.abi => ws/wsproject.json} (100%) rename ioctl/cmd/{znode/znodeprojectcreate.go => ws/wsprojectcreate.go} (57%) rename ioctl/cmd/{znode/znodeprojectquery.go => ws/wsprojectquery.go} (59%) rename ioctl/cmd/{znode/znodeprojectupdate.go => ws/wsprojectupdate.go} (55%) delete mode 100644 ioctl/cmd/znode/znode.go delete mode 100644 ioctl/cmd/znode/znodemessage.go delete mode 100644 ioctl/cmd/znode/znodemessagequery.go delete mode 100644 ioctl/cmd/znode/znodemessagesend.go diff --git a/ioctl/cmd/znode/znodeproject.go b/ioctl/cmd/ws/wsproject.go similarity index 85% rename from ioctl/cmd/znode/znodeproject.go rename to ioctl/cmd/ws/wsproject.go index 8afe7e8464..8f75a0f411 100644 --- a/ioctl/cmd/znode/znodeproject.go +++ b/ioctl/cmd/ws/wsproject.go @@ -1,4 +1,4 @@ -package znode +package ws import ( "bytes" @@ -30,16 +30,16 @@ import ( ) var ( - // znodeProject represents the znode project management command - znodeProject = &cobra.Command{ + // wsProject represents the w3bstream project management command + wsProject = &cobra.Command{ Use: "project", - Short: config.TranslateInLang(znodeProjectShorts, config.UILanguage), + Short: config.TranslateInLang(wsProjectShorts, config.UILanguage), } - // znodeProjectShorts znode project shorts multi-lang support - znodeProjectShorts = map[config.Language]string{ - config.English: "znode project management", - config.Chinese: "znode项目管理", + // wsProjectShorts w3bstream project shorts multi-lang support + wsProjectShorts = map[config.Language]string{ + config.English: "w3bstream project management", + config.Chinese: "w3bstream项目管理", } _flagProjectRegisterContractAddressUsages = map[config.Language]string{ @@ -47,39 +47,39 @@ var ( config.Chinese: "项目注册合约地址", } - znodeProjectRegisterContractAddress string - znodeProjectRegisterContractABI abi.ABI + wsProjectRegisterContractAddress string + wsProjectRegisterContractABI abi.ABI - //go:embed znodeproject.abi - znodeProjectRegisterContractJsonABI []byte + //go:embed wsproject.json + wsProjectRegisterContractJsonABI []byte ) const ( - createZnodeProjectFuncName = "createProject" - createZnodeProjectEventName = "ProjectUpserted" - updateZnodeProjectFuncName = "updateProject" - queryZnodeProjectFuncName = "projects" + createWsProjectFuncName = "createProject" + createWsProjectEventName = "ProjectUpserted" + updateWsProjectFuncName = "updateProject" + queryWsProjectFuncName = "projects" ) func init() { var err error - znodeProjectRegisterContractABI, err = abi.JSON(bytes.NewReader(znodeProjectRegisterContractJsonABI)) + wsProjectRegisterContractABI, err = abi.JSON(bytes.NewReader(wsProjectRegisterContractJsonABI)) if err != nil { log.L().Panic("cannot get abi JSON data", zap.Error(err)) } - znodeProject.AddCommand(znodeProjectCreate) - znodeProject.AddCommand(znodeProjectUpdate) - znodeProject.AddCommand(znodeProjectQuery) + wsProject.AddCommand(wsProjectCreate) + wsProject.AddCommand(wsProjectUpdate) + wsProject.AddCommand(wsProjectQuery) - znodeProject.PersistentFlags().StringVarP( - &znodeProjectRegisterContractAddress, + wsProject.PersistentFlags().StringVarP( + &wsProjectRegisterContractAddress, "contract-address", "c", "", config.TranslateInLang(_flagProjectRegisterContractAddressUsages, config.UILanguage), ) - _ = znodeProject.MarkFlagRequired("contract-address") + _ = wsProject.MarkFlagRequired("contract-address") } func convertStringToAbiBytes32(hash string) (interface{}, error) { @@ -143,7 +143,7 @@ func getEventInputsByName(logs []*iotextypes.Log, eventName string) (map[string] log *iotextypes.Log ) for _, l := range logs { - evabi, err := znodeProjectRegisterContractABI.EventByID(common.BytesToHash(l.Topics[0])) + evabi, err := wsProjectRegisterContractABI.EventByID(common.BytesToHash(l.Topics[0])) if err != nil { return nil, errors.Wrapf(err, "get event abi from topic %v failed", l.Topics[0]) } diff --git a/ioctl/cmd/znode/znodeproject.abi b/ioctl/cmd/ws/wsproject.json similarity index 100% rename from ioctl/cmd/znode/znodeproject.abi rename to ioctl/cmd/ws/wsproject.json diff --git a/ioctl/cmd/znode/znodeprojectcreate.go b/ioctl/cmd/ws/wsprojectcreate.go similarity index 57% rename from ioctl/cmd/znode/znodeprojectcreate.go rename to ioctl/cmd/ws/wsprojectcreate.go index 4376b8e343..e35f233513 100644 --- a/ioctl/cmd/znode/znodeprojectcreate.go +++ b/ioctl/cmd/ws/wsprojectcreate.go @@ -1,4 +1,4 @@ -package znode +package ws import ( "fmt" @@ -12,10 +12,10 @@ import ( ) var ( - // znodeProjectCreate represents the create znode project command - znodeProjectCreate = &cobra.Command{ + // wsProjectCreate represents the create w3bstream project command + wsProjectCreate = &cobra.Command{ Use: "create", - Short: config.TranslateInLang(znodeProjectCreateShorts, config.UILanguage), + Short: config.TranslateInLang(wsProjectCreateShorts, config.UILanguage), RunE: func(cmd *cobra.Command, args []string) error { uri, err := cmd.Flags().GetString("project-uri") if err != nil { @@ -34,9 +34,9 @@ var ( }, } - // znodeProjectSendShorts create znode project shorts multi-lang support - znodeProjectCreateShorts = map[config.Language]string{ - config.English: "create znode project", + // wsProjectCreateShorts create w3bstream project shorts multi-lang support + wsProjectCreateShorts = map[config.Language]string{ + config.English: "create w3bstream project", config.Chinese: "创建项目", } @@ -48,51 +48,19 @@ var ( config.English: "project config hash for validating", config.Chinese: "项目配置hash", } - /* - { - "inputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "name": "projects", - "outputs": [ - { - "internalType": "string", - "name": "uri", - "type": "string" - }, - { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "paused", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - - */ ) func init() { - znodeProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) - znodeProjectCreate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) - znodeProjectCreate.Flags().StringP("contract-address", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + wsProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + wsProjectCreate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + wsProjectCreate.Flags().StringP("contract-address", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) - _ = znodeProjectCreate.MarkFlagRequired("project-uri") - _ = znodeProjectCreate.MarkFlagRequired("project-hash") + _ = wsProjectCreate.MarkFlagRequired("project-uri") + _ = wsProjectCreate.MarkFlagRequired("project-hash") } func createProject(uri, hash string) (string, error) { - contract, err := util.Address(znodeProjectRegisterContractAddress) + contract, err := util.Address(wsProjectRegisterContractAddress) if err != nil { return "", output.NewError(output.AddressError, "failed to get project register contract address", err) } @@ -102,8 +70,8 @@ func createProject(uri, hash string) (string, error) { return "", err } - bytecode, err := znodeProjectRegisterContractABI.Pack( - createZnodeProjectFuncName, + bytecode, err := wsProjectRegisterContractABI.Pack( + createWsProjectFuncName, uri, hashArg, ) if err != nil { @@ -120,7 +88,7 @@ func createProject(uri, hash string) (string, error) { return "", errors.Wrap(err, "wait contract execution receipt failed") } - inputs, err := getEventInputsByName(r.ReceiptInfo.Receipt.Logs, createZnodeProjectEventName) + inputs, err := getEventInputsByName(r.ReceiptInfo.Receipt.Logs, createWsProjectEventName) if err != nil { return "", errors.Wrap(err, "get receipt event failed") } diff --git a/ioctl/cmd/znode/znodeprojectquery.go b/ioctl/cmd/ws/wsprojectquery.go similarity index 59% rename from ioctl/cmd/znode/znodeprojectquery.go rename to ioctl/cmd/ws/wsprojectquery.go index 655ccd97d9..494a55a4f6 100644 --- a/ioctl/cmd/znode/znodeprojectquery.go +++ b/ioctl/cmd/ws/wsprojectquery.go @@ -1,4 +1,4 @@ -package znode +package ws import ( "fmt" @@ -12,10 +12,10 @@ import ( ) var ( - // znodeProjectQuery represents the query znode project command - znodeProjectQuery = &cobra.Command{ + // wsProjectQuery represents the query w3bstream project command + wsProjectQuery = &cobra.Command{ Use: "query", - Short: config.TranslateInLang(znodeProjectQueryShorts, config.UILanguage), + Short: config.TranslateInLang(wsProjectQueryShorts, config.UILanguage), RunE: func(cmd *cobra.Command, args []string) error { id, err := cmd.Flags().GetUint64("project-id") if err != nil { @@ -30,26 +30,26 @@ var ( }, } - // znodeProjectQueryShorts query znode project shorts multi-lang support - znodeProjectQueryShorts = map[config.Language]string{ - config.English: "query znode project", + // wsProjectQueryShorts query w3bstream project shorts multi-lang support + wsProjectQueryShorts = map[config.Language]string{ + config.English: "query w3bstream project", config.Chinese: "查询项目", } ) func init() { - znodeProjectQuery.Flags().Uint64P("project-id", "i", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + wsProjectQuery.Flags().Uint64P("project-id", "i", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) - _ = znodeProjectQuery.MarkFlagRequired("project-id") + _ = wsProjectQuery.MarkFlagRequired("project-id") } func queryProject(id uint64) (string, error) { - contract, err := util.Address(znodeProjectRegisterContractAddress) + contract, err := util.Address(wsProjectRegisterContractAddress) if err != nil { return "", output.NewError(output.AddressError, "failed to get project register contract address", err) } - bytecode, err := znodeProjectRegisterContractABI.Pack(queryZnodeProjectFuncName, id) + bytecode, err := wsProjectRegisterContractABI.Pack(queryWsProjectFuncName, id) if err != nil { return "", output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) } @@ -59,5 +59,5 @@ func queryProject(id uint64) (string, error) { if err != nil { return "", errors.Wrap(err, "read contract failed") } - return parseOutput(&znodeProjectRegisterContractABI, queryZnodeProjectFuncName, data) + return parseOutput(&wsProjectRegisterContractABI, queryWsProjectFuncName, data) } diff --git a/ioctl/cmd/znode/znodeprojectupdate.go b/ioctl/cmd/ws/wsprojectupdate.go similarity index 55% rename from ioctl/cmd/znode/znodeprojectupdate.go rename to ioctl/cmd/ws/wsprojectupdate.go index 6b6aed38da..510a8e0856 100644 --- a/ioctl/cmd/znode/znodeprojectupdate.go +++ b/ioctl/cmd/ws/wsprojectupdate.go @@ -1,4 +1,4 @@ -package znode +package ws import ( "fmt" @@ -12,10 +12,10 @@ import ( ) var ( - // znodeProjectUpdate represents the update znode project command - znodeProjectUpdate = &cobra.Command{ + // wsProjectUpdate represents the update w3bstream project command + wsProjectUpdate = &cobra.Command{ Use: "update", - Short: config.TranslateInLang(znodeProjectUpdateShorts, config.UILanguage), + Short: config.TranslateInLang(wsProjectUpdateShorts, config.UILanguage), RunE: func(cmd *cobra.Command, args []string) error { id, err := cmd.Flags().GetUint64("project-id") if err != nil { @@ -33,25 +33,25 @@ var ( }, } - // znodeProjectUpdateShorts update znode project shorts multi-lang support - znodeProjectUpdateShorts = map[config.Language]string{ - config.English: "update znode project", + // wsProjectUpdateShorts update w3bstream project shorts multi-lang support + wsProjectUpdateShorts = map[config.Language]string{ + config.English: "update w3bstream project", config.Chinese: "更新项目", } ) func init() { - znodeProjectUpdate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) - znodeProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) - znodeProjectUpdate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + wsProjectUpdate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + wsProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + wsProjectUpdate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) - _ = znodeProjectCreate.MarkFlagRequired("project-id") - _ = znodeProjectCreate.MarkFlagRequired("project-uri") - _ = znodeProjectCreate.MarkFlagRequired("project-hash") + _ = wsProjectCreate.MarkFlagRequired("project-id") + _ = wsProjectCreate.MarkFlagRequired("project-uri") + _ = wsProjectCreate.MarkFlagRequired("project-hash") } func updateProject(projectID uint64, uri, hash string) error { - contract, err := util.Address(znodeProjectRegisterContractAddress) + contract, err := util.Address(wsProjectRegisterContractAddress) if err != nil { return output.NewError(output.AddressError, "failed to get project register contract address", err) } @@ -61,8 +61,8 @@ func updateProject(projectID uint64, uri, hash string) error { return errors.Wrap(err, "convert input arg failed") } - bytecode, err := znodeProjectRegisterContractABI.Pack( - updateZnodeProjectFuncName, + bytecode, err := wsProjectRegisterContractABI.Pack( + updateWsProjectFuncName, projectID, uri, hashArg, ) if err != nil { diff --git a/ioctl/cmd/znode/znode.go b/ioctl/cmd/znode/znode.go deleted file mode 100644 index 3b725bdb7d..0000000000 --- a/ioctl/cmd/znode/znode.go +++ /dev/null @@ -1,53 +0,0 @@ -package znode - -import ( - "github.com/spf13/cobra" - - "github.com/iotexproject/iotex-core/ioctl/config" -) - -var ( - // ZnodeCmd represents the znode command - ZnodeCmd = &cobra.Command{ - Use: "znode", - Short: config.TranslateInLang(znodeCmdShorts, config.UILanguage), - } - - // znodeCmdShorts command multi-lang supports - znodeCmdShorts = map[config.Language]string{ - config.English: "Znode operations", - config.Chinese: "Znode 操作", - } - - // - _flagChainEndpointUsages = map[config.Language]string{ - config.English: "set endpoint for once", - config.Chinese: "一次设置端点", - } - _flagZnodeEndpointUsages = map[config.Language]string{ - config.English: "set znode endpoint for once", - config.Chinese: "一次设置znode端点", - } - _flagZnodeContractAddressUsages = map[config.Language]string{ - config.English: "set znode contract address for once", - config.Chinese: "一次设置znode合约地址", - } -) - -func init() { - ZnodeCmd.AddCommand(znodeMessage) - ZnodeCmd.AddCommand(znodeProject) - - ZnodeCmd.PersistentFlags().StringVar( - &config.ReadConfig.Endpoint, "endpoint", - config.ReadConfig.Endpoint, config.TranslateInLang(_flagChainEndpointUsages, config.UILanguage), - ) - ZnodeCmd.PersistentFlags().StringVar( - &config.ReadConfig.ZnodeEndpoint, "znode-endpoint", - config.ReadConfig.ZnodeEndpoint, config.TranslateInLang(_flagZnodeEndpointUsages, config.UILanguage), - ) - ZnodeCmd.PersistentFlags().StringVar( - &config.ReadConfig.ZnodeContractAddress, "znode-contract-address", - config.ReadConfig.ZnodeContractAddress, config.TranslateInLang(_flagZnodeContractAddressUsages, config.UILanguage), - ) -} diff --git a/ioctl/cmd/znode/znodemessage.go b/ioctl/cmd/znode/znodemessage.go deleted file mode 100644 index e9239cb558..0000000000 --- a/ioctl/cmd/znode/znodemessage.go +++ /dev/null @@ -1,53 +0,0 @@ -package znode - -import ( - "time" - - "github.com/spf13/cobra" - - "github.com/iotexproject/iotex-core/ioctl/config" -) - -var ( - // znodeMessage represents the znode message command - znodeMessage = &cobra.Command{ - Use: "message", - Short: config.TranslateInLang(znodeMessageShorts, config.UILanguage), - } - - // znodeMessageShorts znode message shorts multi-lang support - znodeMessageShorts = map[config.Language]string{ - config.English: "znode message operations", - config.Chinese: "znode消息操作", - } -) - -func init() { - znodeMessage.AddCommand(znodeMessageSend) - znodeMessage.AddCommand(znodeMessageQuery) -} - -type sendMessageReq struct { - ProjectID uint64 `json:"projectID"` - ProjectVersion string `json:"projectVersion"` - Data string `json:"data"` -} - -type sendMessageRsp struct { - MessageID string `json:"taskID"` -} - -type queryMessageRsp struct { - ID string `json:"id"` - ProjectID uint64 `json:"projectID"` - ProjectVersion string `json:"projectVersion"` - Data string `json:"data"` - ReceivedAt *time.Time `json:"receivedAt"` - SubmitProvingAt *time.Time `json:"submitProvingAt,omitempty"` - ProofResult string `json:"proofResult,omitempty"` - SubmitToBlockchainAt *time.Time `json:"SubmitToBlockchainAt,omitempty"` - TxHash string `json:"txHash,omitempty"` - Succeed bool `json:"succeed"` - ErrorMessage string `json:"errorMessage,omitempty"` - // TODO field `Status` -} diff --git a/ioctl/cmd/znode/znodemessagequery.go b/ioctl/cmd/znode/znodemessagequery.go deleted file mode 100644 index 62ef19f848..0000000000 --- a/ioctl/cmd/znode/znodemessagequery.go +++ /dev/null @@ -1,85 +0,0 @@ -package znode - -import ( - "encoding/json" - "io" - "net/http" - "net/url" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/iotexproject/iotex-core/ioctl/config" - "github.com/iotexproject/iotex-core/ioctl/output" -) - -var ( - // znodeMessageQuery represents the znode query message command - znodeMessageQuery = &cobra.Command{ - Use: "query", - Short: config.TranslateInLang(znodeMessageQueryShorts, config.UILanguage), - RunE: func(cmd *cobra.Command, args []string) error { - id, err := cmd.Flags().GetString("message-id") - if err != nil { - return errors.Wrap(err, "failed to get flag message-id") - } - - out, err := queryMessageStatus(id) - if err != nil { - return output.PrintError(err) - } - output.PrintResult(out) - return nil - }, - } - - // znodeMessageSendShorts znode message query shorts multi-lang support - znodeMessageQueryShorts = map[config.Language]string{ - config.English: "query message status from znode", - config.Chinese: "向znode查询消息状态", - } - - _flagMessageIDUsages = map[config.Language]string{ - config.English: "message id", - config.Chinese: "消息ID", - } -) - -func init() { - znodeMessageQuery.Flags().StringP("message-id", "i", "", config.TranslateInLang(_flagMessageIDUsages, config.UILanguage)) - _ = znodeMessageQuery.MarkFlagRequired("message-id") -} - -func queryMessageStatus(id string) (string, error) { - u := url.URL{ - Scheme: "http", - Host: config.ReadConfig.ZnodeEndpoint, - Path: "/message/" + id, - } - - rsp, err := http.Get(u.String()) - if err != nil { - return "", errors.Wrap(err, "call znode failed") - } - defer rsp.Body.Close() - - switch sc := rsp.StatusCode; sc { - case http.StatusNotFound: - return "", errors.Errorf("the message [%s] is not found or expired", id) - case http.StatusOK: - default: - return "", errors.Errorf("responded status code: %d", sc) - } - - rspbody, err := io.ReadAll(rsp.Body) - if err != nil { - return "", errors.Wrap(err, "read responded body failed") - } - - rspdata := &queryMessageRsp{} - if err = json.Unmarshal(rspbody, rspdata); err != nil { - return "", errors.Wrap(err, "parse responded body failed") - } - out, err := json.MarshalIndent(rspdata, "", " ") - return string(out), err -} diff --git a/ioctl/cmd/znode/znodemessagesend.go b/ioctl/cmd/znode/znodemessagesend.go deleted file mode 100644 index 423d198297..0000000000 --- a/ioctl/cmd/znode/znodemessagesend.go +++ /dev/null @@ -1,113 +0,0 @@ -package znode - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "net/url" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/iotexproject/iotex-core/ioctl/config" - "github.com/iotexproject/iotex-core/ioctl/output" -) - -var ( - // znodeMessageSend represents the znode send message command - znodeMessageSend = &cobra.Command{ - Use: "send", - Short: config.TranslateInLang(znodeMessageSendShorts, config.UILanguage), - RunE: func(cmd *cobra.Command, args []string) error { - projectID, err := cmd.Flags().GetUint64("project-id") - if err != nil { - return output.PrintError(err) - } - projectVersion, err := cmd.Flags().GetString("project-version") - if err != nil { - return output.PrintError(err) - } - data, err := cmd.Flags().GetString("data") - if err != nil { - return output.PrintError(err) - } - out, err := sendMessageToZnode(projectID, projectVersion, data) - if err != nil { - return output.PrintError(err) - } - output.PrintResult(out) - return nil - }, - } - - // znodeMessageSendShorts znode message send shorts multi-lang support - znodeMessageSendShorts = map[config.Language]string{ - config.English: "send message to znode for zk proofing", - config.Chinese: "向znode发送消息请求zk证明", - } - - _flagProjectIDUsages = map[config.Language]string{ - config.English: "project id", - config.Chinese: "项目ID", - } - _flagProjectVersionUsages = map[config.Language]string{ - config.English: "project version", - config.Chinese: "项目版本", - } - _flagSendDataUsages = map[config.Language]string{ - config.English: "send data", - config.Chinese: "要发送的数据", - } -) - -func init() { - znodeMessageSend.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) - znodeMessageSend.Flags().StringP("project-version", "v", "", config.TranslateInLang(_flagProjectVersionUsages, config.UILanguage)) - znodeMessageSend.Flags().StringP("data", "d", "", config.TranslateInLang(_flagSendDataUsages, config.UILanguage)) - - _ = znodeMessageSend.MarkFlagRequired("project-id") - _ = znodeMessageSend.MarkFlagRequired("project-version") - _ = znodeMessageSend.MarkFlagRequired("data") -} - -func sendMessageToZnode(projectID uint64, projectVersion string, data string) (string, error) { - reqbody, err := json.Marshal(&sendMessageReq{ - ProjectID: projectID, - ProjectVersion: projectVersion, - Data: data, - }) - if err != nil { - return "", errors.Wrap(err, "failed to build call message") - } - - u := url.URL{ - Scheme: "http", - Host: config.ReadConfig.ZnodeEndpoint, - Path: "/message", - } - - rsp, err := http.Post(u.String(), "application/json", bytes.NewReader(reqbody)) - if err != nil { - return "", errors.Wrap(err, "call znode failed") - } - defer rsp.Body.Close() - - if rsp.StatusCode != http.StatusOK { - return "", errors.Errorf("call znode failed: %s", rsp.Status) - } - - rspbody, err := io.ReadAll(rsp.Body) - if err != nil { - return "", errors.Wrap(err, "failed to read responded content") - } - rspdata := &sendMessageRsp{} - if err = json.Unmarshal(rspbody, rspdata); err != nil { - return "", errors.Wrap(err, "failed to parse responded content") - } - out, err := json.MarshalIndent(rspdata, "", " ") - if err != nil { - return "", errors.Wrap(err, "failed to serialize output") - } - return string(out), err -} From 3f361c39ec66829fed11e78e482b2d8afd8c4271 Mon Sep 17 00:00:00 2001 From: saito Date: Mon, 27 Nov 2023 14:54:20 +0800 Subject: [PATCH 09/14] feat(ioctl): ws node project management --- ioctl/cmd/ws/ws.go | 1 + ioctl/cmd/ws/wsproject.go | 29 +++++++++++++++-------------- ioctl/cmd/ws/wsprojectcreate.go | 6 +----- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/ioctl/cmd/ws/ws.go b/ioctl/cmd/ws/ws.go index 2f7d1b4dec..b4c0fedba0 100644 --- a/ioctl/cmd/ws/ws.go +++ b/ioctl/cmd/ws/ws.go @@ -32,6 +32,7 @@ var ( func init() { WsCmd.AddCommand(wsMessage) + WsCmd.AddCommand(wsProject) WsCmd.PersistentFlags().StringVar( &config.ReadConfig.Endpoint, "endpoint", diff --git a/ioctl/cmd/ws/wsproject.go b/ioctl/cmd/ws/wsproject.go index 8f75a0f411..c4298f5438 100644 --- a/ioctl/cmd/ws/wsproject.go +++ b/ioctl/cmd/ws/wsproject.go @@ -6,27 +6,28 @@ import ( _ "embed" "encoding/hex" "fmt" + "math/big" + "reflect" + "strings" + "time" + "github.com/cenkalti/backoff" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" - "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-core/ioctl/output" - "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/iotexproject/iotex-core/pkg/log" - "github.com/iotexproject/iotex-proto/golang/iotexapi" - "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" + "github.com/spf13/cobra" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "math/big" - "reflect" - "strings" - "time" - "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/ioctl/config" - "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/output" + "github.com/iotexproject/iotex-core/ioctl/util" + "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" ) var ( @@ -51,7 +52,7 @@ var ( wsProjectRegisterContractABI abi.ABI //go:embed wsproject.json - wsProjectRegisterContractJsonABI []byte + wsProjectRegisterContractJSONABI []byte ) const ( @@ -63,7 +64,7 @@ const ( func init() { var err error - wsProjectRegisterContractABI, err = abi.JSON(bytes.NewReader(wsProjectRegisterContractJsonABI)) + wsProjectRegisterContractABI, err = abi.JSON(bytes.NewReader(wsProjectRegisterContractJSONABI)) if err != nil { log.L().Panic("cannot get abi JSON data", zap.Error(err)) } diff --git a/ioctl/cmd/ws/wsprojectcreate.go b/ioctl/cmd/ws/wsprojectcreate.go index e35f233513..23e2ef4a46 100644 --- a/ioctl/cmd/ws/wsprojectcreate.go +++ b/ioctl/cmd/ws/wsprojectcreate.go @@ -53,7 +53,6 @@ var ( func init() { wsProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) wsProjectCreate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) - wsProjectCreate.Flags().StringP("contract-address", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = wsProjectCreate.MarkFlagRequired("project-uri") _ = wsProjectCreate.MarkFlagRequired("project-hash") @@ -70,10 +69,7 @@ func createProject(uri, hash string) (string, error) { return "", err } - bytecode, err := wsProjectRegisterContractABI.Pack( - createWsProjectFuncName, - uri, hashArg, - ) + bytecode, err := wsProjectRegisterContractABI.Pack(createWsProjectFuncName, uri, hashArg) if err != nil { return "", output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) } From 2f270a5a8978fdeeea869edecfe0fb0f79428e11 Mon Sep 17 00:00:00 2001 From: saito Date: Mon, 27 Nov 2023 16:11:56 +0800 Subject: [PATCH 10/14] feat(ioctl): ws node project management --- ioctl/cmd/ws/wsproject.go | 3 ++- ioctl/cmd/ws/wsprojectcreate.go | 4 ++-- ioctl/cmd/ws/wsprojectupdate.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ioctl/cmd/ws/wsproject.go b/ioctl/cmd/ws/wsproject.go index c4298f5438..70af86d1be 100644 --- a/ioctl/cmd/ws/wsproject.go +++ b/ioctl/cmd/ws/wsproject.go @@ -3,7 +3,7 @@ package ws import ( "bytes" "context" - _ "embed" + "embed" "encoding/hex" "fmt" "math/big" @@ -53,6 +53,7 @@ var ( //go:embed wsproject.json wsProjectRegisterContractJSONABI []byte + _ = embed.FS{} ) const ( diff --git a/ioctl/cmd/ws/wsprojectcreate.go b/ioctl/cmd/ws/wsprojectcreate.go index 23e2ef4a46..1aac06dc14 100644 --- a/ioctl/cmd/ws/wsprojectcreate.go +++ b/ioctl/cmd/ws/wsprojectcreate.go @@ -40,7 +40,7 @@ var ( config.Chinese: "创建项目", } - _flagProjectUriUsages = map[config.Language]string{ + _flagProjectURIUsages = map[config.Language]string{ config.English: "project config fetch uri", config.Chinese: "项目配置拉取地址", } @@ -51,7 +51,7 @@ var ( ) func init() { - wsProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + wsProjectCreate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectURIUsages, config.UILanguage)) wsProjectCreate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = wsProjectCreate.MarkFlagRequired("project-uri") diff --git a/ioctl/cmd/ws/wsprojectupdate.go b/ioctl/cmd/ws/wsprojectupdate.go index 510a8e0856..65b38f0806 100644 --- a/ioctl/cmd/ws/wsprojectupdate.go +++ b/ioctl/cmd/ws/wsprojectupdate.go @@ -42,7 +42,7 @@ var ( func init() { wsProjectUpdate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) - wsProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectUriUsages, config.UILanguage)) + wsProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectURIUsages, config.UILanguage)) wsProjectUpdate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = wsProjectCreate.MarkFlagRequired("project-id") From 4e54f808aead8b271fb21fec0665552855e00dd9 Mon Sep 17 00:00:00 2001 From: saito Date: Mon, 27 Nov 2023 17:00:59 +0800 Subject: [PATCH 11/14] feat(ioctl): ws node project management --- ioctl/cmd/ws/wsprojectcreate.go | 2 +- ioctl/cmd/ws/wsprojectupdate.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ioctl/cmd/ws/wsprojectcreate.go b/ioctl/cmd/ws/wsprojectcreate.go index 1aac06dc14..32e550ae14 100644 --- a/ioctl/cmd/ws/wsprojectcreate.go +++ b/ioctl/cmd/ws/wsprojectcreate.go @@ -92,5 +92,5 @@ func createProject(uri, hash string) (string, error) { if !ok { return "", errors.New("result not found in event inputs") } - return fmt.Sprint(projectid), nil + return fmt.Sprintf("Your project is successfully created. project id is : %d", projectid), nil } diff --git a/ioctl/cmd/ws/wsprojectupdate.go b/ioctl/cmd/ws/wsprojectupdate.go index 65b38f0806..f1887332a8 100644 --- a/ioctl/cmd/ws/wsprojectupdate.go +++ b/ioctl/cmd/ws/wsprojectupdate.go @@ -41,9 +41,9 @@ var ( ) func init() { - wsProjectUpdate.Flags().Uint64P("project-id", "p", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) + wsProjectUpdate.Flags().Uint64P("project-id", "i", 0, config.TranslateInLang(_flagProjectIDUsages, config.UILanguage)) wsProjectUpdate.Flags().StringP("project-uri", "u", "", config.TranslateInLang(_flagProjectURIUsages, config.UILanguage)) - wsProjectUpdate.Flags().StringP("project-hash", "h", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) + wsProjectUpdate.Flags().StringP("project-hash", "v", "", config.TranslateInLang(_flagProjectHashUsages, config.UILanguage)) _ = wsProjectCreate.MarkFlagRequired("project-id") _ = wsProjectCreate.MarkFlagRequired("project-uri") From 8db79762dd26a8ac29b0e0f3abe3a7b7f0a9cfff Mon Sep 17 00:00:00 2001 From: saito Date: Mon, 27 Nov 2023 18:06:44 +0800 Subject: [PATCH 12/14] feat(ioctl): ws node project management --- ioctl/cmd/ws/wsproject.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ioctl/cmd/ws/wsproject.go b/ioctl/cmd/ws/wsproject.go index 70af86d1be..b7664d112f 100644 --- a/ioctl/cmd/ws/wsproject.go +++ b/ioctl/cmd/ws/wsproject.go @@ -3,7 +3,7 @@ package ws import ( "bytes" "context" - "embed" + _ "embed" // import ws project ABI "encoding/hex" "fmt" "math/big" @@ -53,7 +53,6 @@ var ( //go:embed wsproject.json wsProjectRegisterContractJSONABI []byte - _ = embed.FS{} ) const ( From 3d4a77131eba9b6118dab7bf22277878678f64a8 Mon Sep 17 00:00:00 2001 From: saito Date: Tue, 28 Nov 2023 13:21:27 +0800 Subject: [PATCH 13/14] feat(ioctl): ws node project management --- ioctl/cmd/action/action.go | 12 +- ioctl/cmd/action/actionhash.go | 7 +- ioctl/cmd/action/actionsendraw.go | 3 +- ioctl/cmd/action/xrc20.go | 3 +- ioctl/cmd/action/xrc20const.go | 3 +- ioctl/cmd/contract/contract_test.go | 2 +- ioctl/cmd/contract/contracttestbytecode.go | 3 +- ioctl/cmd/contract/contracttestfunction.go | 5 +- ioctl/cmd/contract/parse.go | 2 +- ioctl/cmd/ws/wsproject.go | 121 +-------------------- ioctl/cmd/ws/wsprojectcreate.go | 8 +- ioctl/cmd/ws/wsprojectquery.go | 13 ++- ioctl/cmd/ws/wsprojectupdate.go | 8 +- 13 files changed, 40 insertions(+), 150 deletions(-) diff --git a/ioctl/cmd/action/action.go b/ioctl/cmd/action/action.go index e1f1b7bab9..dbcb528552 100644 --- a/ioctl/cmd/action/action.go +++ b/ioctl/cmd/action/action.go @@ -13,14 +13,13 @@ import ( "strings" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" - "github.com/spf13/cobra" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-proto/golang/iotexapi" "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/spf13/cobra" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/ioctl/cmd/account" @@ -212,6 +211,11 @@ func fixGasLimit(caller string, execution *action.Execution) (*action.Execution, // SendRaw sends raw action to blockchain func SendRaw(selp *iotextypes.Action) error { + _, err := SendRawAndRespond(selp) + if err != nil { + return err + } + shash := hash.Hash256b(byteutil.Must(proto.Marshal(selp))) txhash := hex.EncodeToString(shash[:]) message := sendMessage{Info: "Action has been sent to blockchain.", TxHash: txhash, URL: "https://"} diff --git a/ioctl/cmd/action/actionhash.go b/ioctl/cmd/action/actionhash.go index 30b0b53f04..cec795b92a 100644 --- a/ioctl/cmd/action/actionhash.go +++ b/ioctl/cmd/action/actionhash.go @@ -15,19 +15,18 @@ import ( protoV1 "github.com/golang/protobuf/proto" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" + "github.com/iotexproject/go-pkgs/crypto" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/spf13/cobra" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/iotexproject/go-pkgs/crypto" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/ioctl/cmd/alias" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/iotexproject/iotex-proto/golang/iotexapi" ) // Multi-language support diff --git a/ioctl/cmd/action/actionsendraw.go b/ioctl/cmd/action/actionsendraw.go index 19227b10ac..77ca89bbda 100644 --- a/ioctl/cmd/action/actionsendraw.go +++ b/ioctl/cmd/action/actionsendraw.go @@ -8,11 +8,10 @@ package action import ( "encoding/hex" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/spf13/cobra" "google.golang.org/protobuf/proto" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" ) diff --git a/ioctl/cmd/action/xrc20.go b/ioctl/cmd/action/xrc20.go index 9f72d21958..8558f7b4af 100644 --- a/ioctl/cmd/action/xrc20.go +++ b/ioctl/cmd/action/xrc20.go @@ -11,9 +11,8 @@ import ( "math/big" "strconv" - "github.com/spf13/cobra" - "github.com/iotexproject/iotex-address/address" + "github.com/spf13/cobra" "github.com/iotexproject/iotex-core/ioctl/cmd/alias" "github.com/iotexproject/iotex-core/ioctl/config" diff --git a/ioctl/cmd/action/xrc20const.go b/ioctl/cmd/action/xrc20const.go index 60fc1bf23e..a53f5d58f1 100644 --- a/ioctl/cmd/action/xrc20const.go +++ b/ioctl/cmd/action/xrc20const.go @@ -4,8 +4,9 @@ import ( "strings" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/iotexproject/iotex-core/pkg/log" "go.uber.org/zap" + + "github.com/iotexproject/iotex-core/pkg/log" ) const _abiConst = `[ diff --git a/ioctl/cmd/contract/contract_test.go b/ioctl/cmd/contract/contract_test.go index f12006202b..821ebc14b5 100644 --- a/ioctl/cmd/contract/contract_test.go +++ b/ioctl/cmd/contract/contract_test.go @@ -108,7 +108,7 @@ func TestParseOutput(t *testing.T) { } for _, test := range tests { - v, err := parseOutput(testAbi, test.method, test.outputs) + v, err := ParseOutput(testAbi, test.method, test.outputs) r.NoError(err) r.Equal(test.expectResult, fmt.Sprint(v)) } diff --git a/ioctl/cmd/contract/contracttestbytecode.go b/ioctl/cmd/contract/contracttestbytecode.go index 24a1d06a5b..e482885d78 100644 --- a/ioctl/cmd/contract/contracttestbytecode.go +++ b/ioctl/cmd/contract/contracttestbytecode.go @@ -8,9 +8,8 @@ package contract import ( "math/big" - "github.com/spf13/cobra" - "github.com/iotexproject/iotex-address/address" + "github.com/spf13/cobra" "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" diff --git a/ioctl/cmd/contract/contracttestfunction.go b/ioctl/cmd/contract/contracttestfunction.go index 04979fd041..d1647d6d0d 100644 --- a/ioctl/cmd/contract/contracttestfunction.go +++ b/ioctl/cmd/contract/contracttestfunction.go @@ -8,9 +8,8 @@ package contract import ( "math/big" - "github.com/spf13/cobra" - "github.com/iotexproject/iotex-address/address" + "github.com/spf13/cobra" "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" @@ -80,7 +79,7 @@ func contractTestFunction(args []string) error { return err } - result, err := parseOutput(abi, methodName, rowResult) + result, err := ParseOutput(abi, methodName, rowResult) if err != nil { result = rowResult } diff --git a/ioctl/cmd/contract/parse.go b/ioctl/cmd/contract/parse.go index 4766d770e5..790e1bc854 100644 --- a/ioctl/cmd/contract/parse.go +++ b/ioctl/cmd/contract/parse.go @@ -44,7 +44,7 @@ func parseInput(rowInput string) (map[string]interface{}, error) { return input, nil } -func parseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { +func ParseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { resultBytes, err := hex.DecodeString(result) if err != nil { return "", output.NewError(output.ConvertError, "failed to decode result", err) diff --git a/ioctl/cmd/ws/wsproject.go b/ioctl/cmd/ws/wsproject.go index b7664d112f..16938343a4 100644 --- a/ioctl/cmd/ws/wsproject.go +++ b/ioctl/cmd/ws/wsproject.go @@ -5,29 +5,25 @@ import ( "context" _ "embed" // import ws project ABI "encoding/hex" - "fmt" - "math/big" "reflect" - "strings" "time" "github.com/cenkalti/backoff" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" "github.com/spf13/cobra" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" "github.com/iotexproject/iotex-core/ioctl/util" "github.com/iotexproject/iotex-core/pkg/log" - "github.com/iotexproject/iotex-proto/golang/iotexapi" - "github.com/iotexproject/iotex-proto/golang/iotextypes" ) var ( @@ -182,116 +178,3 @@ func getEventInputsByName(logs []*iotextypes.Log, eventName string) (map[string] return inputs, nil } - -func parseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { - resultBytes, err := hex.DecodeString(result) - if err != nil { - return "", errors.Wrap(err, "failed to decode result") - } - - var ( - outputArgs = targetAbi.Methods[targetMethod].Outputs - tupleStr = make([]string, 0, len(outputArgs)) - ) - - v, err := targetAbi.Unpack(targetMethod, resultBytes) - if err != nil { - return "", errors.Wrap(err, "failed to parse output") - } - - if len(outputArgs) == 1 { - elemStr, _ := parseOutputArgument(v[0], &outputArgs[0].Type) - return elemStr, nil - } - - for i, field := range v { - elemStr, _ := parseOutputArgument(field, &outputArgs[i].Type) - tupleStr = append(tupleStr, outputArgs[i].Name+":"+elemStr) - } - return "{" + strings.Join(tupleStr, " ") + "}", nil -} - -func parseOutputArgument(v interface{}, t *abi.Type) (string, bool) { - str := fmt.Sprint(v) - ok := false - - switch t.T { - case abi.StringTy, abi.BoolTy: - // case abi.StringTy & abi.BoolTy can be handled by fmt.Sprint() - ok = true - - case abi.TupleTy: - if reflect.TypeOf(v).Kind() == reflect.Struct { - ok = true - - tupleStr := make([]string, 0, len(t.TupleElems)) - for i, elem := range t.TupleElems { - elemStr, elemOk := parseOutputArgument(reflect.ValueOf(v).Field(i).Interface(), elem) - tupleStr = append(tupleStr, t.TupleRawNames[i]+":"+elemStr) - ok = ok && elemOk - } - - str = "{" + strings.Join(tupleStr, " ") + "}" - } - - case abi.SliceTy, abi.ArrayTy: - if reflect.TypeOf(v).Kind() == reflect.Slice || reflect.TypeOf(v).Kind() == reflect.Array { - ok = true - - value := reflect.ValueOf(v) - sliceStr := make([]string, 0, value.Len()) - for i := 0; i < value.Len(); i++ { - elemStr, elemOk := parseOutputArgument(value.Index(i).Interface(), t.Elem) - sliceStr = append(sliceStr, elemStr) - ok = ok && elemOk - } - - str = "[" + strings.Join(sliceStr, " ") + "]" - } - - case abi.IntTy, abi.UintTy: - if reflect.TypeOf(v) == reflect.TypeOf(big.NewInt(0)) { - var bigInt *big.Int - bigInt, ok = v.(*big.Int) - if ok { - str = bigInt.String() - } - } else if 2 <= reflect.TypeOf(v).Kind() && reflect.TypeOf(v).Kind() <= 11 { - // other integer types (int8,uint16,...) can be handled by fmt.Sprint(v) - ok = true - } - - case abi.AddressTy: - if reflect.TypeOf(v) == reflect.TypeOf(common.Address{}) { - var ethAddr common.Address - ethAddr, ok = v.(common.Address) - if ok { - ioAddress, err := address.FromBytes(ethAddr.Bytes()) - if err == nil { - str = ioAddress.String() - } - } - } - - case abi.BytesTy: - if reflect.TypeOf(v) == reflect.TypeOf([]byte{}) { - var bytes []byte - bytes, ok = v.([]byte) - if ok { - str = "0x" + hex.EncodeToString(bytes) - } - } - - case abi.FixedBytesTy, abi.FunctionTy: - if reflect.TypeOf(v).Kind() == reflect.Array && reflect.TypeOf(v).Elem() == reflect.TypeOf(byte(0)) { - bytesValue := reflect.ValueOf(v) - byteSlice := reflect.MakeSlice(reflect.TypeOf([]byte{}), bytesValue.Len(), bytesValue.Len()) - reflect.Copy(byteSlice, bytesValue) - - str = "0x" + hex.EncodeToString(byteSlice.Bytes()) - ok = true - } - } - - return str, ok -} diff --git a/ioctl/cmd/ws/wsprojectcreate.go b/ioctl/cmd/ws/wsprojectcreate.go index 32e550ae14..ed4131dbb6 100644 --- a/ioctl/cmd/ws/wsprojectcreate.go +++ b/ioctl/cmd/ws/wsprojectcreate.go @@ -2,13 +2,15 @@ package ws import ( "fmt" + "math/big" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "math/big" ) var ( diff --git a/ioctl/cmd/ws/wsprojectquery.go b/ioctl/cmd/ws/wsprojectquery.go index 494a55a4f6..57d76162a7 100644 --- a/ioctl/cmd/ws/wsprojectquery.go +++ b/ioctl/cmd/ws/wsprojectquery.go @@ -2,13 +2,16 @@ package ws import ( "fmt" + "github.com/iotexproject/iotex-address/address" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" + "github.com/iotexproject/iotex-core/ioctl/cmd/contract" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/pkg/errors" - "github.com/spf13/cobra" ) var ( @@ -44,7 +47,7 @@ func init() { } func queryProject(id uint64) (string, error) { - contract, err := util.Address(wsProjectRegisterContractAddress) + contractAddr, err := util.Address(wsProjectRegisterContractAddress) if err != nil { return "", output.NewError(output.AddressError, "failed to get project register contract address", err) } @@ -54,10 +57,10 @@ func queryProject(id uint64) (string, error) { return "", output.NewError(output.ConvertError, fmt.Sprintf("failed to pack abi"), err) } - addr, _ := address.FromString(contract) + addr, _ := address.FromString(contractAddr) data, err := action.Read(addr, "0", bytecode) if err != nil { return "", errors.Wrap(err, "read contract failed") } - return parseOutput(&wsProjectRegisterContractABI, queryWsProjectFuncName, data) + return contract.ParseOutput(&wsProjectRegisterContractABI, queryWsProjectFuncName, data) } diff --git a/ioctl/cmd/ws/wsprojectupdate.go b/ioctl/cmd/ws/wsprojectupdate.go index f1887332a8..13a887ea71 100644 --- a/ioctl/cmd/ws/wsprojectupdate.go +++ b/ioctl/cmd/ws/wsprojectupdate.go @@ -2,13 +2,15 @@ package ws import ( "fmt" + "math/big" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/iotexproject/iotex-core/ioctl/cmd/action" "github.com/iotexproject/iotex-core/ioctl/config" "github.com/iotexproject/iotex-core/ioctl/output" "github.com/iotexproject/iotex-core/ioctl/util" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "math/big" ) var ( From f1335e42ab4c9f7b9e1a8260d55f81b9b2565754 Mon Sep 17 00:00:00 2001 From: saito Date: Tue, 28 Nov 2023 13:27:26 +0800 Subject: [PATCH 14/14] feat(ioctl): ws node project management --- ioctl/cmd/contract/parse.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ioctl/cmd/contract/parse.go b/ioctl/cmd/contract/parse.go index 790e1bc854..18ab531f78 100644 --- a/ioctl/cmd/contract/parse.go +++ b/ioctl/cmd/contract/parse.go @@ -44,6 +44,7 @@ func parseInput(rowInput string) (map[string]interface{}, error) { return input, nil } +// ParseOutput parse contract output data func ParseOutput(targetAbi *abi.ABI, targetMethod string, result string) (string, error) { resultBytes, err := hex.DecodeString(result) if err != nil {