diff --git a/cmd/swarm/config.go b/cmd/swarm/config.go deleted file mode 100644 index 598985347e..0000000000 --- a/cmd/swarm/config.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "errors" - "fmt" - "io" - "os" - "reflect" - "strconv" - "strings" - "unicode" - - cli "gopkg.in/urfave/cli.v1" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/log" - "github.com/XinFinOrg/XDPoSChain/node" - "github.com/naoina/toml" - - bzzapi "github.com/XinFinOrg/XDPoSChain/swarm/api" -) - -var ( - //flag definition for the dumpconfig command - DumpConfigCommand = cli.Command{ - Action: utils.MigrateFlags(dumpConfig), - Name: "dumpconfig", - Usage: "Show configuration values", - ArgsUsage: "", - Flags: app.Flags, - Category: "MISCELLANEOUS COMMANDS", - Description: `The dumpconfig command shows configuration values.`, - } - - //flag definition for the config file command - SwarmTomlConfigPathFlag = cli.StringFlag{ - Name: "config", - Usage: "TOML configuration file", - } -) - -//constants for environment variables -const ( - SWARM_ENV_CHEQUEBOOK_ADDR = "SWARM_CHEQUEBOOK_ADDR" - SWARM_ENV_ACCOUNT = "SWARM_ACCOUNT" - SWARM_ENV_LISTEN_ADDR = "SWARM_LISTEN_ADDR" - SWARM_ENV_PORT = "SWARM_PORT" - SWARM_ENV_NETWORK_ID = "SWARM_NETWORK_ID" - SWARM_ENV_SWAP_ENABLE = "SWARM_SWAP_ENABLE" - SWARM_ENV_SWAP_API = "SWARM_SWAP_API" - SWARM_ENV_SYNC_ENABLE = "SWARM_SYNC_ENABLE" - SWARM_ENV_ENS_API = "SWARM_ENS_API" - SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR" - SWARM_ENV_CORS = "SWARM_CORS" - SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES" - XDC_ENV_DATADIR = "XDC_DATADIR" -) - -// These settings ensure that TOML keys use the same names as Go struct fields. -var tomlSettings = toml.Config{ - NormFieldName: func(rt reflect.Type, key string) string { - return key - }, - FieldToKey: func(rt reflect.Type, field string) string { - return field - }, - MissingField: func(rt reflect.Type, field string) error { - link := "" - if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { - link = fmt.Sprintf(", check github.com/XinFinOrg/XDPoSChain/swarm/api/config.go for available fields") - } - return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) - }, -} - -//before booting the swarm node, build the configuration -func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { - //check for deprecated flags - checkDeprecated(ctx) - //start by creating a default config - config = bzzapi.NewDefaultConfig() - //first load settings from config file (if provided) - config, err = configFileOverride(config, ctx) - if err != nil { - return nil, err - } - //override settings provided by environment variables - config = envVarsOverride(config) - //override settings provided by command line - config = cmdLineOverride(config, ctx) - //validate configuration parameters - err = validateConfig(config) - - return -} - -//finally, after the configuration build phase is finished, initialize -func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) { - //at this point, all vars should be set in the Config - //get the account for the provided swarm account - prvkey := getAccount(config.BzzAccount, ctx, stack) - //set the resolved config path (XDC --datadir) - config.Path = stack.InstanceDir() - //finally, initialize the configuration - config.Init(prvkey) - //configuration phase completed here - log.Debug("Starting Swarm with the following parameters:") - //after having created the config, print it to screen - log.Debug(printConfig(config)) -} - -//override the current config with whatever is in the config file, if a config file has been provided -func configFileOverride(config *bzzapi.Config, ctx *cli.Context) (*bzzapi.Config, error) { - var err error - - //only do something if the -config flag has been set - if ctx.GlobalIsSet(SwarmTomlConfigPathFlag.Name) { - var filepath string - if filepath = ctx.GlobalString(SwarmTomlConfigPathFlag.Name); filepath == "" { - utils.Fatalf("Config file flag provided with invalid file path") - } - f, err := os.Open(filepath) - if err != nil { - return nil, err - } - defer f.Close() - - //decode the TOML file into a Config struct - //note that we are decoding into the existing defaultConfig; - //if an entry is not present in the file, the default entry is kept - err = tomlSettings.NewDecoder(f).Decode(&config) - // Add file name to errors that have a line number. - if _, ok := err.(*toml.LineError); ok { - err = errors.New(filepath + ", " + err.Error()) - } - } - return config, err -} - -//override the current config with whatever is provided through the command line -//most values are not allowed a zero value (empty string), if not otherwise noted -func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Config { - - if keyid := ctx.GlobalString(SwarmAccountFlag.Name); keyid != "" { - currentConfig.BzzAccount = keyid - } - - if chbookaddr := ctx.GlobalString(ChequebookAddrFlag.Name); chbookaddr != "" { - currentConfig.Contract = common.HexToAddress(chbookaddr) - } - - if networkid := ctx.GlobalString(SwarmNetworkIdFlag.Name); networkid != "" { - if id, _ := strconv.Atoi(networkid); id != 0 { - currentConfig.NetworkId = uint64(id) - } - } - - if ctx.GlobalIsSet(utils.DataDirFlag.Name) { - if datadir := ctx.GlobalString(utils.DataDirFlag.Name); datadir != "" { - currentConfig.Path = datadir - } - } - - bzzport := ctx.GlobalString(SwarmPortFlag.Name) - if len(bzzport) > 0 { - currentConfig.Port = bzzport - } - - if bzzaddr := ctx.GlobalString(SwarmListenAddrFlag.Name); bzzaddr != "" { - currentConfig.ListenAddr = bzzaddr - } - - if ctx.GlobalIsSet(SwarmSwapEnabledFlag.Name) { - currentConfig.SwapEnabled = true - } - - if ctx.GlobalIsSet(SwarmSyncEnabledFlag.Name) { - currentConfig.SyncEnabled = true - } - - currentConfig.SwapApi = ctx.GlobalString(SwarmSwapAPIFlag.Name) - if currentConfig.SwapEnabled && currentConfig.SwapApi == "" { - utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) - } - - if ctx.GlobalIsSet(EnsAPIFlag.Name) { - ensAPIs := ctx.GlobalStringSlice(EnsAPIFlag.Name) - // preserve backward compatibility to disable ENS with --ens-api="" - if len(ensAPIs) == 1 && ensAPIs[0] == "" { - ensAPIs = nil - } - currentConfig.EnsAPIs = ensAPIs - } - - if ensaddr := ctx.GlobalString(DeprecatedEnsAddrFlag.Name); ensaddr != "" { - currentConfig.EnsRoot = common.HexToAddress(ensaddr) - } - - if cors := ctx.GlobalString(CorsStringFlag.Name); cors != "" { - currentConfig.Cors = cors - } - - if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { - currentConfig.BootNodes = ctx.GlobalString(utils.BootnodesFlag.Name) - } - - return currentConfig - -} - -//override the current config with whatver is provided in environment variables -//most values are not allowed a zero value (empty string), if not otherwise noted -func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) { - - if keyid := os.Getenv(SWARM_ENV_ACCOUNT); keyid != "" { - currentConfig.BzzAccount = keyid - } - - if chbookaddr := os.Getenv(SWARM_ENV_CHEQUEBOOK_ADDR); chbookaddr != "" { - currentConfig.Contract = common.HexToAddress(chbookaddr) - } - - if networkid := os.Getenv(SWARM_ENV_NETWORK_ID); networkid != "" { - if id, _ := strconv.Atoi(networkid); id != 0 { - currentConfig.NetworkId = uint64(id) - } - } - - if datadir := os.Getenv(XDC_ENV_DATADIR); datadir != "" { - currentConfig.Path = datadir - } - - bzzport := os.Getenv(SWARM_ENV_PORT) - if len(bzzport) > 0 { - currentConfig.Port = bzzport - } - - if bzzaddr := os.Getenv(SWARM_ENV_LISTEN_ADDR); bzzaddr != "" { - currentConfig.ListenAddr = bzzaddr - } - - if swapenable := os.Getenv(SWARM_ENV_SWAP_ENABLE); swapenable != "" { - if swap, err := strconv.ParseBool(swapenable); err != nil { - currentConfig.SwapEnabled = swap - } - } - - if syncenable := os.Getenv(SWARM_ENV_SYNC_ENABLE); syncenable != "" { - if sync, err := strconv.ParseBool(syncenable); err != nil { - currentConfig.SyncEnabled = sync - } - } - - if swapapi := os.Getenv(SWARM_ENV_SWAP_API); swapapi != "" { - currentConfig.SwapApi = swapapi - } - - if currentConfig.SwapEnabled && currentConfig.SwapApi == "" { - utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) - } - - if ensapi := os.Getenv(SWARM_ENV_ENS_API); ensapi != "" { - currentConfig.EnsAPIs = strings.Split(ensapi, ",") - } - - if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" { - currentConfig.EnsRoot = common.HexToAddress(ensaddr) - } - - if cors := os.Getenv(SWARM_ENV_CORS); cors != "" { - currentConfig.Cors = cors - } - - if bootnodes := os.Getenv(SWARM_ENV_BOOTNODES); bootnodes != "" { - currentConfig.BootNodes = bootnodes - } - - return currentConfig -} - -// dumpConfig is the dumpconfig command. -// writes a default config to STDOUT -func dumpConfig(ctx *cli.Context) error { - cfg, err := buildConfig(ctx) - if err != nil { - utils.Fatalf(fmt.Sprintf("Uh oh - dumpconfig triggered an error %v", err)) - } - comment := "" - out, err := tomlSettings.Marshal(&cfg) - if err != nil { - return err - } - io.WriteString(os.Stdout, comment) - os.Stdout.Write(out) - return nil -} - -//deprecated flags checked here -func checkDeprecated(ctx *cli.Context) { - // exit if the deprecated --ethapi flag is set - if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" { - utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.") - } - // warn if --ens-api flag is set - if ctx.GlobalString(DeprecatedEnsAddrFlag.Name) != "" { - log.Warn("--ens-addr is no longer a valid command line flag, please use --ens-api to specify contract address.") - } -} - -//validate configuration parameters -func validateConfig(cfg *bzzapi.Config) (err error) { - for _, ensAPI := range cfg.EnsAPIs { - if ensAPI != "" { - if err := validateEnsAPIs(ensAPI); err != nil { - return fmt.Errorf("invalid format [tld:][contract-addr@]url for ENS API endpoint configuration %q: %v", ensAPI, err) - } - } - } - return nil -} - -//validate EnsAPIs configuration parameter -func validateEnsAPIs(s string) (err error) { - // missing contract address - if strings.HasPrefix(s, "@") { - return errors.New("missing contract address") - } - // missing url - if strings.HasSuffix(s, "@") { - return errors.New("missing url") - } - // missing tld - if strings.HasPrefix(s, ":") { - return errors.New("missing tld") - } - // missing url - if strings.HasSuffix(s, ":") { - return errors.New("missing url") - } - return nil -} - -//print a Config as string -func printConfig(config *bzzapi.Config) string { - out, err := tomlSettings.Marshal(&config) - if err != nil { - return fmt.Sprintf("Something is not right with the configuration: %v", err) - } - return string(out) -} diff --git a/cmd/swarm/config_test.go b/cmd/swarm/config_test.go deleted file mode 100644 index 8778591703..0000000000 --- a/cmd/swarm/config_test.go +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "io" - "os" - "os/exec" - "testing" - "time" - - "github.com/XinFinOrg/XDPoSChain/rpc" - "github.com/XinFinOrg/XDPoSChain/swarm" - "github.com/XinFinOrg/XDPoSChain/swarm/api" - - "github.com/docker/docker/pkg/reexec" -) - -func TestDumpConfig(t *testing.T) { - swarm := runSwarm(t, "dumpconfig") - defaultConf := api.NewDefaultConfig() - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatal(err) - } - swarm.Expect(string(out)) - swarm.ExpectExit() -} - -func TestFailsSwapEnabledNoSwapApi(t *testing.T) { - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545", - fmt.Sprintf("--%s", SwarmSwapEnabledFlag.Name), - } - - swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SWARM_ERR_SWAP_SET_NO_API + "\n") - swarm.ExpectExit() -} - -func TestFailsNoBzzAccount(t *testing.T) { - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), "54545", - } - - swarm := runSwarm(t, flags...) - swarm.Expect("Fatal: " + SWARM_ERR_NO_BZZACCOUNT + "\n") - swarm.ExpectExit() -} - -func TestCmdLineOverrides(t *testing.T) { - dir, err := os.MkdirTemp("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", - fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort, - fmt.Sprintf("--%s", SwarmSyncEnabledFlag.Name), - fmt.Sprintf("--%s", CorsStringFlag.Name), "*", - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - fmt.Sprintf("--%s", EnsAPIFlag.Name), "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkId != 42 { - t.Fatalf("Expected network ID to be %d, got %d", 42, info.NetworkId) - } - - if !info.SyncEnabled { - t.Fatal("Expected Sync to be enabled, but is false") - } - - if info.Cors != "*" { - t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors) - } - - node.Shutdown() -} - -func TestFileOverrides(t *testing.T) { - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - //create a config file - //first, create a default conf - defaultConf := api.NewDefaultConfig() - //change some values in order to test if they have been loaded - defaultConf.SyncEnabled = true - defaultConf.NetworkId = 54 - defaultConf.Port = httpPort - defaultConf.StoreParams.DbCapacity = 9000000 - defaultConf.ChunkerParams.Branches = 64 - defaultConf.HiveParams.CallInterval = 6000000000 - defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second - defaultConf.SyncParams.KeyBufferSize = 512 - //create a TOML string - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatalf("Error creating TOML file in TestFileOverride: %v", err) - } - //create file - f, err := os.CreateTemp("", "testconfig.toml") - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - //write file - _, err = f.WriteString(string(out)) - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - f.Sync() - - dir, err := os.MkdirTemp("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - flags := []string{ - fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--ipcpath", conf.IPCPath, - "--datadir", dir, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkId != 54 { - t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId) - } - - if !info.SyncEnabled { - t.Fatal("Expected Sync to be enabled, but is false") - } - - if info.StoreParams.DbCapacity != 9000000 { - t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId) - } - - if info.ChunkerParams.Branches != 64 { - t.Fatalf("Expected chunker params branches to be %d, got %d", 64, info.ChunkerParams.Branches) - } - - if info.HiveParams.CallInterval != 6000000000 { - t.Fatalf("Expected HiveParams CallInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.CallInterval)) - } - - if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second { - t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval) - } - - if info.SyncParams.KeyBufferSize != 512 { - t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize) - } - - node.Shutdown() -} - -func TestEnvVars(t *testing.T) { - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - envVars := os.Environ() - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmPortFlag.EnvVar, httpPort)) - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmNetworkIdFlag.EnvVar, "999")) - envVars = append(envVars, fmt.Sprintf("%s=%s", CorsStringFlag.EnvVar, "*")) - envVars = append(envVars, fmt.Sprintf("%s=%s", SwarmSyncEnabledFlag.EnvVar, "true")) - - dir, err := os.MkdirTemp("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - flags := []string{ - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - } - - //node.Cmd = runSwarm(t,flags...) - //node.Cmd.cmd.Env = envVars - //the above assignment does not work, so we need a custom Cmd here in order to pass envVars: - cmd := &exec.Cmd{ - Path: reexec.Self(), - Args: append([]string{"swarm-test"}, flags...), - Stderr: os.Stderr, - Stdout: os.Stdout, - } - cmd.Env = envVars - //stdout, err := cmd.StdoutPipe() - //if err != nil { - // t.Fatal(err) - //} - //stdout = bufio.NewReader(stdout) - var stdin io.WriteCloser - if stdin, err = cmd.StdinPipe(); err != nil { - t.Fatal(err) - } - if err := cmd.Start(); err != nil { - t.Fatal(err) - } - - //cmd.InputLine(testPassphrase) - io.WriteString(stdin, testPassphrase+"\n") - defer func() { - if t.Failed() { - node.Shutdown() - cmd.Process.Kill() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkId != 999 { - t.Fatalf("Expected network ID to be %d, got %d", 999, info.NetworkId) - } - - if info.Cors != "*" { - t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors) - } - - if !info.SyncEnabled { - t.Fatal("Expected Sync to be enabled, but is false") - } - - node.Shutdown() - cmd.Process.Kill() -} - -func TestCmdLineOverridesFile(t *testing.T) { - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - //create a config file - //first, create a default conf - defaultConf := api.NewDefaultConfig() - //change some values in order to test if they have been loaded - defaultConf.SyncEnabled = false - defaultConf.NetworkId = 54 - defaultConf.Port = "8588" - defaultConf.StoreParams.DbCapacity = 9000000 - defaultConf.ChunkerParams.Branches = 64 - defaultConf.HiveParams.CallInterval = 6000000000 - defaultConf.Swap.Params.Strategy.AutoCashInterval = 600 * time.Second - defaultConf.SyncParams.KeyBufferSize = 512 - //create a TOML file - out, err := tomlSettings.Marshal(&defaultConf) - if err != nil { - t.Fatalf("Error creating TOML file in TestFileOverride: %v", err) - } - //write file - f, err := os.CreateTemp("", "testconfig.toml") - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - //write file - _, err = f.WriteString(string(out)) - if err != nil { - t.Fatalf("Error writing TOML file in TestFileOverride: %v", err) - } - f.Sync() - - dir, err := os.MkdirTemp("", "bzztest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - expectNetworkId := uint64(77) - - flags := []string{ - fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "77", - fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort, - fmt.Sprintf("--%s", SwarmSyncEnabledFlag.Name), - fmt.Sprintf("--%s", SwarmTomlConfigPathFlag.Name), f.Name(), - fmt.Sprintf("--%s", SwarmAccountFlag.Name), account.Address.String(), - "--ens-api", "", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - } - node.Cmd = runSwarm(t, flags...) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - - if info.Port != httpPort { - t.Fatalf("Expected port to be %s, got %s", httpPort, info.Port) - } - - if info.NetworkId != expectNetworkId { - t.Fatalf("Expected network ID to be %d, got %d", expectNetworkId, info.NetworkId) - } - - if !info.SyncEnabled { - t.Fatal("Expected Sync to be enabled, but is false") - } - - if info.StoreParams.DbCapacity != 9000000 { - t.Fatalf("Expected network ID to be %d, got %d", 54, info.NetworkId) - } - - if info.ChunkerParams.Branches != 64 { - t.Fatalf("Expected chunker params branches to be %d, got %d", 64, info.ChunkerParams.Branches) - } - - if info.HiveParams.CallInterval != 6000000000 { - t.Fatalf("Expected HiveParams CallInterval to be %d, got %d", uint64(6000000000), uint64(info.HiveParams.CallInterval)) - } - - if info.Swap.Params.Strategy.AutoCashInterval != 600*time.Second { - t.Fatalf("Expected SwapParams AutoCashInterval to be %ds, got %d", 600, info.Swap.Params.Strategy.AutoCashInterval) - } - - if info.SyncParams.KeyBufferSize != 512 { - t.Fatalf("Expected info.SyncParams.KeyBufferSize to be %d, got %d", 512, info.SyncParams.KeyBufferSize) - } - - node.Shutdown() -} - -func TestValidateConfig(t *testing.T) { - for _, c := range []struct { - cfg *api.Config - err string - }{ - { - cfg: &api.Config{EnsAPIs: []string{ - "/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:12344", - }}, - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "eth:", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"eth:\": missing url", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "314159265dD8dbb310642f98f50C066173C1259b@", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"314159265dD8dbb310642f98f50C066173C1259b@\": missing url", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - ":314159265dD8dbb310642f98f50C066173C1259", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \":314159265dD8dbb310642f98f50C066173C1259\": missing tld", - }, - { - cfg: &api.Config{EnsAPIs: []string{ - "@/data/testnet/geth.ipc", - }}, - err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"@/data/testnet/geth.ipc\": missing contract address", - }, - } { - err := validateConfig(c.cfg) - if c.err != "" && err.Error() != c.err { - t.Errorf("expected error %q, got %q", c.err, err) - } - if c.err == "" && err != nil { - t.Errorf("unexpected error %q", err) - } - } -} diff --git a/cmd/swarm/db.go b/cmd/swarm/db.go deleted file mode 100644 index 6435db2f07..0000000000 --- a/cmd/swarm/db.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "io" - "os" - "path/filepath" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - "github.com/XinFinOrg/XDPoSChain/log" - "github.com/XinFinOrg/XDPoSChain/swarm/storage" - "gopkg.in/urfave/cli.v1" -) - -func dbExport(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 2 { - utils.Fatalf("invalid arguments, please specify both (path to a local chunk database) and (path to write the tar archive to, - for stdout)") - } - - store, err := openDbStore(args[0]) - if err != nil { - utils.Fatalf("error opening local chunk database: %s", err) - } - defer store.Close() - - var out io.Writer - if args[1] == "-" { - out = os.Stdout - } else { - f, err := os.Create(args[1]) - if err != nil { - utils.Fatalf("error opening output file: %s", err) - } - defer f.Close() - out = f - } - - count, err := store.Export(out) - if err != nil { - utils.Fatalf("error exporting local chunk database: %s", err) - } - - log.Info(fmt.Sprintf("successfully exported %d chunks", count)) -} - -func dbImport(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 2 { - utils.Fatalf("invalid arguments, please specify both (path to a local chunk database) and (path to read the tar archive from, - for stdin)") - } - - store, err := openDbStore(args[0]) - if err != nil { - utils.Fatalf("error opening local chunk database: %s", err) - } - defer store.Close() - - var in io.Reader - if args[1] == "-" { - in = os.Stdin - } else { - f, err := os.Open(args[1]) - if err != nil { - utils.Fatalf("error opening input file: %s", err) - } - defer f.Close() - in = f - } - - count, err := store.Import(in) - if err != nil { - utils.Fatalf("error importing local chunk database: %s", err) - } - - log.Info(fmt.Sprintf("successfully imported %d chunks", count)) -} - -func dbClean(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 1 { - utils.Fatalf("invalid arguments, please specify (path to a local chunk database)") - } - - store, err := openDbStore(args[0]) - if err != nil { - utils.Fatalf("error opening local chunk database: %s", err) - } - defer store.Close() - - store.Cleanup() -} - -func openDbStore(path string) (*storage.DbStore, error) { - if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil { - return nil, fmt.Errorf("invalid chunkdb path: %s", err) - } - hash := storage.MakeHashFunc("SHA3") - return storage.NewDbStore(path, hash, 10000000, 0) -} diff --git a/cmd/swarm/hash.go b/cmd/swarm/hash.go deleted file mode 100644 index 1a2583ac8b..0000000000 --- a/cmd/swarm/hash.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command bzzhash computes a swarm tree hash. -package main - -import ( - "fmt" - "os" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - "github.com/XinFinOrg/XDPoSChain/swarm/storage" - "gopkg.in/urfave/cli.v1" -) - -func hash(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 1 { - utils.Fatalf("Usage: swarm hash ") - } - f, err := os.Open(args[0]) - if err != nil { - utils.Fatalf("Error opening file " + args[0]) - } - defer f.Close() - - stat, _ := f.Stat() - chunker := storage.NewTreeChunker(storage.NewChunkerParams()) - key, err := chunker.Split(f, stat.Size(), nil, nil, nil) - if err != nil { - utils.Fatalf("%v\n", err) - } else { - fmt.Printf("%v\n", key) - } -} diff --git a/cmd/swarm/list.go b/cmd/swarm/list.go deleted file mode 100644 index e8772562c4..0000000000 --- a/cmd/swarm/list.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - "strings" - "text/tabwriter" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - swarm "github.com/XinFinOrg/XDPoSChain/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -func list(ctx *cli.Context) { - args := ctx.Args() - - if len(args) < 1 { - utils.Fatalf("Please supply a manifest reference as the first argument") - } else if len(args) > 2 { - utils.Fatalf("Too many arguments - usage 'swarm ls manifest [prefix]'") - } - manifest := args[0] - - var prefix string - if len(args) == 2 { - prefix = args[1] - } - - bzzapi := strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client := swarm.NewClient(bzzapi) - list, err := client.List(manifest, prefix) - if err != nil { - utils.Fatalf("Failed to generate file and directory list: %s", err) - } - - w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintln(w, "HASH\tCONTENT TYPE\tPATH") - for _, prefix := range list.CommonPrefixes { - fmt.Fprintf(w, "%s\t%s\t%s\n", "", "DIR", prefix) - } - for _, entry := range list.Entries { - fmt.Fprintf(w, "%s\t%s\t%s\n", entry.Hash, entry.ContentType, entry.Path) - } -} diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go deleted file mode 100644 index 9ca769070a..0000000000 --- a/cmd/swarm/main.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "crypto/ecdsa" - "fmt" - "os" - "os/signal" - "runtime" - "sort" - "strconv" - "strings" - "syscall" - - "github.com/XinFinOrg/XDPoSChain/accounts" - "github.com/XinFinOrg/XDPoSChain/accounts/keystore" - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/console" - "github.com/XinFinOrg/XDPoSChain/crypto" - "github.com/XinFinOrg/XDPoSChain/ethclient" - "github.com/XinFinOrg/XDPoSChain/internal/debug" - "github.com/XinFinOrg/XDPoSChain/log" - "github.com/XinFinOrg/XDPoSChain/node" - "github.com/XinFinOrg/XDPoSChain/p2p" - "github.com/XinFinOrg/XDPoSChain/p2p/discover" - "github.com/XinFinOrg/XDPoSChain/params" - "github.com/XinFinOrg/XDPoSChain/swarm" - bzzapi "github.com/XinFinOrg/XDPoSChain/swarm/api" - swarmmetrics "github.com/XinFinOrg/XDPoSChain/swarm/metrics" - - "gopkg.in/urfave/cli.v1" -) - -const clientIdentifier = "swarm" - -var ( - gitCommit string // Git SHA1 commit hash of the release (set via linker flags) - testbetBootNodes = []string{ - "enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429", - "enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430", - "enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431", - "enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432", - "enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433", - } -) - -var ( - ChequebookAddrFlag = cli.StringFlag{ - Name: "chequebook", - Usage: "chequebook contract address", - EnvVar: SWARM_ENV_CHEQUEBOOK_ADDR, - } - SwarmAccountFlag = cli.StringFlag{ - Name: "bzzaccount", - Usage: "Swarm account key file", - EnvVar: SWARM_ENV_ACCOUNT, - } - SwarmListenAddrFlag = cli.StringFlag{ - Name: "httpaddr", - Usage: "Swarm HTTP API listening interface", - EnvVar: SWARM_ENV_LISTEN_ADDR, - } - SwarmPortFlag = cli.StringFlag{ - Name: "bzzport", - Usage: "Swarm local http api port", - EnvVar: SWARM_ENV_PORT, - } - SwarmNetworkIdFlag = cli.IntFlag{ - Name: "bzznetworkid", - Usage: "Network identifier (integer, default 3=swarm testnet)", - EnvVar: SWARM_ENV_NETWORK_ID, - } - SwarmConfigPathFlag = cli.StringFlag{ - Name: "bzzconfig", - Usage: "DEPRECATED: please use --config path/to/TOML-file", - } - SwarmSwapEnabledFlag = cli.BoolFlag{ - Name: "swap", - Usage: "Swarm SWAP enabled (default false)", - EnvVar: SWARM_ENV_SWAP_ENABLE, - } - SwarmSwapAPIFlag = cli.StringFlag{ - Name: "swap-api", - Usage: "URL of the Ethereum API provider to use to settle SWAP payments", - EnvVar: SWARM_ENV_SWAP_API, - } - SwarmSyncEnabledFlag = cli.BoolTFlag{ - Name: "sync", - Usage: "Swarm Syncing enabled (default true)", - EnvVar: SWARM_ENV_SYNC_ENABLE, - } - EnsAPIFlag = cli.StringSliceFlag{ - Name: "ens-api", - Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", - EnvVar: SWARM_ENV_ENS_API, - } - SwarmApiFlag = cli.StringFlag{ - Name: "bzzapi", - Usage: "Swarm HTTP endpoint", - Value: "http://127.0.0.1:8500", - } - SwarmRecursiveUploadFlag = cli.BoolFlag{ - Name: "recursive", - Usage: "Upload directories recursively", - } - SwarmWantManifestFlag = cli.BoolTFlag{ - Name: "manifest", - Usage: "Automatic manifest upload", - } - SwarmUploadDefaultPath = cli.StringFlag{ - Name: "defaultpath", - Usage: "path to file served for empty url path (none)", - } - SwarmUpFromStdinFlag = cli.BoolFlag{ - Name: "stdin", - Usage: "reads data to be uploaded from stdin", - } - SwarmUploadMimeType = cli.StringFlag{ - Name: "mime", - Usage: "force mime type", - } - CorsStringFlag = cli.StringFlag{ - Name: "corsdomain", - Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", - EnvVar: SWARM_ENV_CORS, - } - - // the following flags are deprecated and should be removed in the future - DeprecatedEthAPIFlag = cli.StringFlag{ - Name: "ethapi", - Usage: "DEPRECATED: please use --ens-api and --swap-api", - } - DeprecatedEnsAddrFlag = cli.StringFlag{ - Name: "ens-addr", - Usage: "DEPRECATED: ENS contract address, please use --ens-api with contract address according to its format", - } -) - -// declare a few constant error messages, useful for later error check comparisons in test -var ( - SWARM_ERR_NO_BZZACCOUNT = "bzzaccount option is required but not set; check your config file, command line or environment variables" - SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set" -) - -var defaultNodeConfig = node.DefaultConfig - -// This init function sets defaults so cmd/swarm can run alongside geth. -func init() { - defaultNodeConfig.Name = clientIdentifier - defaultNodeConfig.Version = params.VersionWithCommit(gitCommit) - defaultNodeConfig.P2P.ListenAddr = ":30399" - defaultNodeConfig.IPCPath = "bzzd.ipc" - // Set flag defaults for --help display. - utils.ListenPortFlag.Value = 30399 -} - -var app = utils.NewApp(gitCommit, "Ethereum Swarm") - -// This init function creates the cli.App. -func init() { - app.Action = bzzd - app.HideVersion = true // we have a command to print the version - app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" - app.Commands = []cli.Command{ - { - Action: version, - Name: "version", - Usage: "Print version numbers", - ArgsUsage: " ", - Description: ` -The output of this command is supposed to be machine-readable. -`, - }, - { - Action: upload, - Name: "up", - Usage: "upload a file or directory to swarm using the HTTP API", - ArgsUsage: " ", - Description: ` -"upload a file or directory to swarm using the HTTP API and prints the root hash", -`, - }, - { - Action: list, - Name: "ls", - Usage: "list files and directories contained in a manifest", - ArgsUsage: " []", - Description: ` -Lists files and directories contained in a manifest. -`, - }, - { - Action: hash, - Name: "hash", - Usage: "print the swarm hash of a file or directory", - ArgsUsage: " ", - Description: ` -Prints the swarm hash of file or directory. -`, - }, - { - Name: "manifest", - Usage: "update a MANIFEST", - ArgsUsage: "manifest COMMAND", - Description: ` -Updates a MANIFEST by adding/removing/updating the hash of a path. -`, - Subcommands: []cli.Command{ - { - Action: add, - Name: "add", - Usage: "add a new path to the manifest", - ArgsUsage: " []", - Description: ` -Adds a new path to the manifest -`, - }, - { - Action: update, - Name: "update", - Usage: "update the hash for an already existing path in the manifest", - ArgsUsage: " []", - Description: ` -Update the hash for an already existing path in the manifest -`, - }, - { - Action: remove, - Name: "remove", - Usage: "removes a path from the manifest", - ArgsUsage: " ", - Description: ` -Removes a path from the manifest -`, - }, - }, - }, - { - Name: "db", - Usage: "manage the local chunk database", - ArgsUsage: "db COMMAND", - Description: ` -Manage the local chunk database. -`, - Subcommands: []cli.Command{ - { - Action: dbExport, - Name: "export", - Usage: "export a local chunk database as a tar archive (use - to send to stdout)", - ArgsUsage: " ", - Description: ` -Export a local chunk database as a tar archive (use - to send to stdout). - - swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar - -The export may be quite large, consider piping the output through the Unix -pv(1) tool to get a progress bar: - - swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar -`, - }, - { - Action: dbImport, - Name: "import", - Usage: "import chunks from a tar archive into a local chunk database (use - to read from stdin)", - ArgsUsage: " ", - Description: ` -Import chunks from a tar archive into a local chunk database (use - to read from stdin). - - swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar - -The import may be quite large, consider piping the input through the Unix -pv(1) tool to get a progress bar: - - pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks - -`, - }, - { - Action: dbClean, - Name: "clean", - Usage: "remove corrupt entries from a local chunk database", - ArgsUsage: "", - Description: ` -Remove corrupt entries from a local chunk database. -`, - }, - }, - }, - { - Action: func(ctx *cli.Context) { - utils.Fatalf("ERROR: 'swarm cleandb' has been removed, please use 'swarm db clean'.") - }, - Name: "cleandb", - Usage: "DEPRECATED: use 'swarm db clean'", - ArgsUsage: " ", - Description: ` -DEPRECATED: use 'swarm db clean'. -`, - }, - // See config.go - DumpConfigCommand, - } - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Flags = []cli.Flag{ - utils.IdentityFlag, - utils.DataDirFlag, - utils.BootnodesFlag, - utils.KeyStoreDirFlag, - utils.ListenPortFlag, - utils.NoDiscoverFlag, - utils.DiscoveryV5Flag, - utils.NetrestrictFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - utils.MaxPeersFlag, - utils.NATFlag, - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.PasswordFileFlag, - // bzzd-specific flags - CorsStringFlag, - EnsAPIFlag, - SwarmTomlConfigPathFlag, - SwarmConfigPathFlag, - SwarmSwapEnabledFlag, - SwarmSwapAPIFlag, - SwarmSyncEnabledFlag, - SwarmListenAddrFlag, - SwarmPortFlag, - SwarmAccountFlag, - SwarmNetworkIdFlag, - ChequebookAddrFlag, - // upload flags - SwarmApiFlag, - SwarmRecursiveUploadFlag, - SwarmWantManifestFlag, - SwarmUploadDefaultPath, - SwarmUpFromStdinFlag, - SwarmUploadMimeType, - //deprecated flags - DeprecatedEthAPIFlag, - DeprecatedEnsAddrFlag, - } - app.Flags = append(app.Flags, debug.Flags...) - app.Flags = append(app.Flags, swarmmetrics.Flags...) - app.Before = func(ctx *cli.Context) error { - runtime.GOMAXPROCS(runtime.NumCPU()) - if err := debug.Setup(ctx); err != nil { - return err - } - swarmmetrics.Setup(ctx) - return nil - } - app.After = func(ctx *cli.Context) error { - debug.Exit() - return nil - } -} - -func main() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func version(ctx *cli.Context) error { - fmt.Println(strings.Title(clientIdentifier)) - fmt.Println("Version:", params.Version) - if gitCommit != "" { - fmt.Println("Git Commit:", gitCommit) - } - fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name)) - fmt.Println("Go Version:", runtime.Version()) - fmt.Println("OS:", runtime.GOOS) - fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) - fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) - return nil -} - -func bzzd(ctx *cli.Context) error { - //build a valid bzzapi.Config from all available sources: - //default config, file config, command line and env vars - bzzconfig, err := buildConfig(ctx) - if err != nil { - utils.Fatalf("unable to configure swarm: %v", err) - } - - cfg := defaultNodeConfig - //XDC only supports --datadir via command line - //in order to be consistent within swarm, if we pass --datadir via environment variable - //or via config file, we get the same directory for XDC and swarm - if _, err := os.Stat(bzzconfig.Path); err == nil { - cfg.DataDir = bzzconfig.Path - } - //setup the ethereum node - utils.SetNodeConfig(ctx, &cfg) - stack, err := node.New(&cfg) - if err != nil { - utils.Fatalf("can't create node: %v", err) - } - //a few steps need to be done after the config phase is completed, - //due to overriding behavior - initSwarmNode(bzzconfig, stack, ctx) - //register BZZ as node.Service in the ethereum node - registerBzzService(bzzconfig, ctx, stack) - //start the node - utils.StartNode(stack) - - go func() { - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) - defer signal.Stop(sigc) - <-sigc - log.Info("Got sigterm, shutting swarm down...") - stack.Stop() - }() - - // Add bootnodes as initial peers. - if bzzconfig.BootNodes != "" { - bootnodes := strings.Split(bzzconfig.BootNodes, ",") - injectBootnodes(stack.Server(), bootnodes) - } else { - if bzzconfig.NetworkId == 3 { - injectBootnodes(stack.Server(), testbetBootNodes) - } - } - - stack.Wait() - return nil -} - -func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) { - - //define the swarm service boot function - boot := func(ctx *node.ServiceContext) (node.Service, error) { - var swapClient *ethclient.Client - var err error - if bzzconfig.SwapApi != "" { - log.Info("connecting to SWAP API", "url", bzzconfig.SwapApi) - swapClient, err = ethclient.Dial(bzzconfig.SwapApi) - if err != nil { - return nil, fmt.Errorf("error connecting to SWAP API %s: %s", bzzconfig.SwapApi, err) - } - } - - return swarm.NewSwarm(ctx, swapClient, bzzconfig) - } - //register within the ethereum node - if err := stack.Register(boot); err != nil { - utils.Fatalf("Failed to register the Swarm service: %v", err) - } -} - -func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { - //an account is mandatory - if bzzaccount == "" { - utils.Fatalf(SWARM_ERR_NO_BZZACCOUNT) - } - // Try to load the arg as a hex key file. - if key, err := crypto.LoadECDSA(bzzaccount); err == nil { - log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey)) - return key - } - // Otherwise try getting it from the keystore. - am := stack.AccountManager() - ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - - return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx)) -} - -func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey { - var a accounts.Account - var err error - if common.IsHexAddress(account) { - a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)}) - } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 { - if accounts := ks.Accounts(); len(accounts) > ix { - a = accounts[ix] - } else { - err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts)) - } - } else { - utils.Fatalf("Can't find swarm account key %s", account) - } - if err != nil { - utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account) - } - keyjson, err := os.ReadFile(a.URL.Path) - if err != nil { - utils.Fatalf("Can't load swarm account key: %v", err) - } - for i := 0; i < 3; i++ { - password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords) - key, err := keystore.DecryptKey(keyjson, password) - if err == nil { - return key.PrivateKey - } - } - utils.Fatalf("Can't decrypt swarm account key") - return nil -} - -// getPassPhrase retrieves the password associated with bzz account, either by fetching -// from a list of pre-loaded passwords, or by requesting it interactively from user. -func getPassPhrase(prompt string, i int, passwords []string) string { - // non-interactive - if len(passwords) > 0 { - if i < len(passwords) { - return passwords[i] - } - return passwords[len(passwords)-1] - } - - // fallback to interactive mode - if prompt != "" { - fmt.Println(prompt) - } - password, err := console.Stdin.PromptPassword("Passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase: %v", err) - } - return password -} - -func injectBootnodes(srv *p2p.Server, nodes []string) { - for _, url := range nodes { - n, err := discover.ParseNode(url) - if err != nil { - log.Error("Invalid swarm bootnode", "err", err) - continue - } - srv.AddPeer(n) - } -} diff --git a/cmd/swarm/manifest.go b/cmd/swarm/manifest.go deleted file mode 100644 index 8be0a08644..0000000000 --- a/cmd/swarm/manifest.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command MANIFEST update -package main - -import ( - "encoding/json" - "fmt" - "mime" - "path/filepath" - "strings" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - "github.com/XinFinOrg/XDPoSChain/swarm/api" - swarm "github.com/XinFinOrg/XDPoSChain/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -const bzzManifestJSON = "application/bzz-manifest+json" - -func add(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 3 { - utils.Fatalf("Need at least three arguments []") - } - - var ( - mhash = args[0] - path = args[1] - hash = args[2] - - ctype string - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - mroot api.Manifest - ) - - if len(args) > 3 { - ctype = args[3] - } else { - ctype = mime.TypeByExtension(filepath.Ext(path)) - } - - newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype) - fmt.Println(newManifest) - - if !wantManifest { - // Print the manifest. This is the only output to stdout. - mrootJSON, _ := json.MarshalIndent(mroot, "", " ") - fmt.Println(string(mrootJSON)) - return - } -} - -func update(ctx *cli.Context) { - - args := ctx.Args() - if len(args) < 3 { - utils.Fatalf("Need at least three arguments ") - } - - var ( - mhash = args[0] - path = args[1] - hash = args[2] - - ctype string - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - mroot api.Manifest - ) - if len(args) > 3 { - ctype = args[3] - } else { - ctype = mime.TypeByExtension(filepath.Ext(path)) - } - - newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype) - fmt.Println(newManifest) - - if !wantManifest { - // Print the manifest. This is the only output to stdout. - mrootJSON, _ := json.MarshalIndent(mroot, "", " ") - fmt.Println(string(mrootJSON)) - return - } -} - -func remove(ctx *cli.Context) { - args := ctx.Args() - if len(args) < 2 { - utils.Fatalf("Need at least two arguments ") - } - - var ( - mhash = args[0] - path = args[1] - - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - mroot api.Manifest - ) - - newManifest := removeEntryFromManifest(ctx, mhash, path) - fmt.Println(newManifest) - - if !wantManifest { - // Print the manifest. This is the only output to stdout. - mrootJSON, _ := json.MarshalIndent(mroot, "", " ") - fmt.Println(string(mrootJSON)) - return - } -} - -func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string { - - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - longestPathEntry = api.ManifestEntry{} - ) - - mroot, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - //TODO: check if the "hash" to add is valid and present in swarm - _, err = client.DownloadManifest(hash) - if err != nil { - utils.Fatalf("Hash to add is not present: %v", err) - } - - // See if we path is in this Manifest or do we have to dig deeper - for _, entry := range mroot.Entries { - if path == entry.Path { - utils.Fatalf("Path %s already present, not adding anything", path) - } else { - if entry.ContentType == bzzManifestJSON { - prfxlen := strings.HasPrefix(path, entry.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = entry - } - } - } - } - - if longestPathEntry.Path != "" { - // Load the child Manifest add the entry there - newPath := path[len(longestPathEntry.Path):] - newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if longestPathEntry.Path == entry.Path { - entry.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, entry) - } - mroot = newMRoot - } else { - // Add the entry in the leaf Manifest - newEntry := api.ManifestEntry{ - Hash: hash, - Path: path, - ContentType: ctype, - } - mroot.Entries = append(mroot.Entries, newEntry) - } - - newManifestHash, err := client.UploadManifest(mroot) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash - -} - -func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string { - - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - newEntry = api.ManifestEntry{} - longestPathEntry = api.ManifestEntry{} - ) - - mroot, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - //TODO: check if the "hash" with which to update is valid and present in swarm - - // See if we path is in this Manifest or do we have to dig deeper - for _, entry := range mroot.Entries { - if path == entry.Path { - newEntry = entry - } else { - if entry.ContentType == bzzManifestJSON { - prfxlen := strings.HasPrefix(path, entry.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = entry - } - } - } - } - - if longestPathEntry.Path == "" && newEntry.Path == "" { - utils.Fatalf("Path %s not present in the Manifest, not setting anything", path) - } - - if longestPathEntry.Path != "" { - // Load the child Manifest add the entry there - newPath := path[len(longestPathEntry.Path):] - newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if longestPathEntry.Path == entry.Path { - entry.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, entry) - - } - mroot = newMRoot - } - - if newEntry.Path != "" { - // Replace the hash for leaf Manifest - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if newEntry.Path == entry.Path { - myEntry := api.ManifestEntry{ - Hash: hash, - Path: entry.Path, - ContentType: ctype, - } - newMRoot.Entries = append(newMRoot.Entries, myEntry) - } else { - newMRoot.Entries = append(newMRoot.Entries, entry) - } - } - mroot = newMRoot - } - - newManifestHash, err := client.UploadManifest(mroot) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash -} - -func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string { - - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - client = swarm.NewClient(bzzapi) - entryToRemove = api.ManifestEntry{} - longestPathEntry = api.ManifestEntry{} - ) - - mroot, err := client.DownloadManifest(mhash) - if err != nil { - utils.Fatalf("Manifest download failed: %v", err) - } - - // See if we path is in this Manifest or do we have to dig deeper - for _, entry := range mroot.Entries { - if path == entry.Path { - entryToRemove = entry - } else { - if entry.ContentType == bzzManifestJSON { - prfxlen := strings.HasPrefix(path, entry.Path) - if prfxlen && len(path) > len(longestPathEntry.Path) { - longestPathEntry = entry - } - } - } - } - - if longestPathEntry.Path == "" && entryToRemove.Path == "" { - utils.Fatalf("Path %s not present in the Manifest, not removing anything", path) - } - - if longestPathEntry.Path != "" { - // Load the child Manifest remove the entry there - newPath := path[len(longestPathEntry.Path):] - newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath) - - // Replace the hash for parent Manifests - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if longestPathEntry.Path == entry.Path { - entry.Hash = newHash - } - newMRoot.Entries = append(newMRoot.Entries, entry) - } - mroot = newMRoot - } - - if entryToRemove.Path != "" { - // remove the entry in this Manifest - newMRoot := &api.Manifest{} - for _, entry := range mroot.Entries { - if entryToRemove.Path != entry.Path { - newMRoot.Entries = append(newMRoot.Entries, entry) - } - } - mroot = newMRoot - } - - newManifestHash, err := client.UploadManifest(mroot) - if err != nil { - utils.Fatalf("Manifest upload failed: %v", err) - } - return newManifestHash -} diff --git a/cmd/swarm/run_test.go b/cmd/swarm/run_test.go deleted file mode 100644 index 539ef5827c..0000000000 --- a/cmd/swarm/run_test.go +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "net" - "os" - "path/filepath" - "runtime" - "testing" - "time" - - "github.com/XinFinOrg/XDPoSChain/accounts" - "github.com/XinFinOrg/XDPoSChain/accounts/keystore" - "github.com/XinFinOrg/XDPoSChain/internal/cmdtest" - "github.com/XinFinOrg/XDPoSChain/node" - "github.com/XinFinOrg/XDPoSChain/p2p" - "github.com/XinFinOrg/XDPoSChain/rpc" - "github.com/XinFinOrg/XDPoSChain/swarm" - "github.com/docker/docker/pkg/reexec" -) - -func init() { - // Run the app if we've been exec'd as "swarm-test" in runSwarm. - reexec.Register("swarm-test", func() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Exit(0) - }) -} - -func TestMain(m *testing.M) { - // check if we have been reexec'd - if reexec.Init() { - return - } - os.Exit(m.Run()) -} - -func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { - tt := cmdtest.NewTestCmd(t, nil) - - // Boot "swarm". This actually runs the test binary but the TestMain - // function will prevent any tests from running. - tt.Run("swarm-test", args...) - - return tt -} - -type testCluster struct { - Nodes []*testNode - TmpDir string -} - -// newTestCluster starts a test swarm cluster of the given size. -// -// A temporary directory is created and each node gets a data directory inside -// it. -// -// Each node listens on 127.0.0.1 with random ports for both the HTTP and p2p -// ports (assigned by first listening on 127.0.0.1:0 and then passing the ports -// as flags). -// -// When starting more than one node, they are connected together using the -// admin SetPeer RPC method. -func newTestCluster(t *testing.T, size int) *testCluster { - cluster := &testCluster{} - defer func() { - if t.Failed() { - cluster.Shutdown() - } - }() - - tmpdir, err := os.MkdirTemp("", "swarm-test") - if err != nil { - t.Fatal(err) - } - cluster.TmpDir = tmpdir - - // start the nodes - cluster.Nodes = make([]*testNode, 0, size) - for i := 0; i < size; i++ { - dir := filepath.Join(cluster.TmpDir, fmt.Sprintf("swarm%02d", i)) - if err := os.Mkdir(dir, 0700); err != nil { - t.Fatal(err) - } - - node := newTestNode(t, dir) - node.Name = fmt.Sprintf("swarm%02d", i) - - cluster.Nodes = append(cluster.Nodes, node) - } - - if size == 1 { - return cluster - } - - // connect the nodes together - for _, node := range cluster.Nodes { - if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { - t.Fatal(err) - } - } - - // wait until all nodes have the correct number of peers -outer: - for _, node := range cluster.Nodes { - var peers []*p2p.PeerInfo - for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(50 * time.Millisecond) { - if err := node.Client.Call(&peers, "admin_peers"); err != nil { - t.Fatal(err) - } - if len(peers) == len(cluster.Nodes)-1 { - continue outer - } - } - t.Fatalf("%s only has %d / %d peers", node.Name, len(peers), len(cluster.Nodes)-1) - } - - return cluster -} - -func (c *testCluster) Shutdown() { - for _, node := range c.Nodes { - node.Shutdown() - } - os.RemoveAll(c.TmpDir) -} - -type testNode struct { - Name string - Addr string - URL string - Enode string - Dir string - Client *rpc.Client - Cmd *cmdtest.TestCmd -} - -const testPassphrase = "swarm-test-passphrase" - -func getTestAccount(t *testing.T, dir string) (conf *node.Config, account accounts.Account) { - // create key - conf = &node.Config{ - DataDir: dir, - IPCPath: "bzzd.ipc", - NoUSB: true, - } - n, err := node.New(conf) - if err != nil { - t.Fatal(err) - } - account, err = n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore).NewAccount(testPassphrase) - if err != nil { - t.Fatal(err) - } - - // use a unique IPCPath when running tests on Windows - if runtime.GOOS == "windows" { - conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", account.Address.String()) - } - - return conf, account -} - -func newTestNode(t *testing.T, dir string) *testNode { - - conf, account := getTestAccount(t, dir) - node := &testNode{Dir: dir} - - // assign ports - httpPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - p2pPort, err := assignTCPPort() - if err != nil { - t.Fatal(err) - } - - // start the node - node.Cmd = runSwarm(t, - "--port", p2pPort, - "--nodiscover", - "--datadir", dir, - "--ipcpath", conf.IPCPath, - "--ens-api", "", - "--bzzaccount", account.Address.String(), - "--bzznetworkid", "321", - "--bzzport", httpPort, - "--verbosity", "6", - ) - node.Cmd.InputLine(testPassphrase) - defer func() { - if t.Failed() { - node.Shutdown() - } - }() - - // wait for the node to start - for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { - node.Client, err = rpc.Dial(conf.IPCEndpoint()) - if err == nil { - break - } - } - if node.Client == nil { - t.Fatal(err) - } - - // load info - var info swarm.Info - if err := node.Client.Call(&info, "bzz_info"); err != nil { - t.Fatal(err) - } - node.Addr = net.JoinHostPort("127.0.0.1", info.Port) - node.URL = "http://" + node.Addr - - var nodeInfo p2p.NodeInfo - if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { - t.Fatal(err) - } - node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort) - - return node -} - -func (n *testNode) Shutdown() { - if n.Cmd != nil { - n.Cmd.Kill() - } -} - -func assignTCPPort() (string, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return "", err - } - l.Close() - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return "", err - } - return port, nil -} diff --git a/cmd/swarm/upload.go b/cmd/swarm/upload.go deleted file mode 100644 index 212d58f950..0000000000 --- a/cmd/swarm/upload.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Command bzzup uploads files to the swarm HTTP API. -package main - -import ( - "errors" - "fmt" - "io" - "mime" - "net/http" - "os" - "os/user" - "path" - "path/filepath" - "strings" - - "github.com/XinFinOrg/XDPoSChain/cmd/utils" - swarm "github.com/XinFinOrg/XDPoSChain/swarm/api/client" - "gopkg.in/urfave/cli.v1" -) - -func upload(ctx *cli.Context) { - - args := ctx.Args() - var ( - bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") - recursive = ctx.GlobalBool(SwarmRecursiveUploadFlag.Name) - wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name) - defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name) - fromStdin = ctx.GlobalBool(SwarmUpFromStdinFlag.Name) - mimeType = ctx.GlobalString(SwarmUploadMimeType.Name) - client = swarm.NewClient(bzzapi) - file string - ) - - if len(args) != 1 { - if fromStdin { - tmp, err := os.CreateTemp("", "swarm-stdin") - if err != nil { - utils.Fatalf("error create tempfile: %s", err) - } - defer os.Remove(tmp.Name()) - n, err := io.Copy(tmp, os.Stdin) - if err != nil { - utils.Fatalf("error copying stdin to tempfile: %s", err) - } else if n == 0 { - utils.Fatalf("error reading from stdin: zero length") - } - file = tmp.Name() - } else { - utils.Fatalf("Need filename as the first and only argument") - } - } else { - file = expandPath(args[0]) - } - - if !wantManifest { - f, err := swarm.Open(file) - if err != nil { - utils.Fatalf("Error opening file: %s", err) - } - defer f.Close() - hash, err := client.UploadRaw(f, f.Size) - if err != nil { - utils.Fatalf("Upload failed: %s", err) - } - fmt.Println(hash) - return - } - - stat, err := os.Stat(file) - if err != nil { - utils.Fatalf("Error opening file: %s", err) - } - - // define a function which either uploads a directory or single file - // based on the type of the file being uploaded - var doUpload func() (hash string, err error) - if stat.IsDir() { - doUpload = func() (string, error) { - if !recursive { - return "", errors.New("Argument is a directory and recursive upload is disabled") - } - return client.UploadDirectory(file, defaultPath, "") - } - } else { - doUpload = func() (string, error) { - f, err := swarm.Open(file) - if err != nil { - return "", fmt.Errorf("error opening file: %s", err) - } - defer f.Close() - if mimeType == "" { - mimeType = detectMimeType(file) - } - f.ContentType = mimeType - return client.Upload(f, "") - } - } - hash, err := doUpload() - if err != nil { - utils.Fatalf("Upload failed: %s", err) - } - fmt.Println(hash) -} - -// Expands a file path -// 1. replace tilde with users home dir -// 2. expands embedded environment variables -// 3. cleans the path, e.g. /a/b/../c -> /a/c -// Note, it has limitations, e.g. ~someuser/tmp will not be expanded -func expandPath(p string) string { - if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { - if home := homeDir(); home != "" { - p = home + p[1:] - } - } - return path.Clean(os.ExpandEnv(p)) -} - -func homeDir() string { - if home := os.Getenv("HOME"); home != "" { - return home - } - if usr, err := user.Current(); err == nil { - return usr.HomeDir - } - return "" -} - -func detectMimeType(file string) string { - if ext := filepath.Ext(file); ext != "" { - return mime.TypeByExtension(ext) - } - f, err := os.Open(file) - if err != nil { - return "" - } - defer f.Close() - buf := make([]byte, 512) - if n, _ := f.Read(buf); n > 0 { - return http.DetectContentType(buf) - } - return "" -} diff --git a/cmd/swarm/upload_test.go b/cmd/swarm/upload_test.go deleted file mode 100644 index c7d1eeb053..0000000000 --- a/cmd/swarm/upload_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "io" - "net/http" - "os" - "testing" -) - -// TestCLISwarmUp tests that running 'swarm up' makes the resulting file -// available from all nodes via the HTTP API -func TestCLISwarmUp(t *testing.T) { - // start 3 node cluster - t.Log("starting 3 node cluster") - cluster := newTestCluster(t, 3) - defer cluster.Shutdown() - - // create a tmp file - tmp, err := os.CreateTemp("", "swarm-test") - assertNil(t, err) - defer tmp.Close() - defer os.Remove(tmp.Name()) - _, err = io.WriteString(tmp, "data") - assertNil(t, err) - - // upload the file with 'swarm up' and expect a hash - t.Log("uploading file with 'swarm up'") - up := runSwarm(t, "--bzzapi", cluster.Nodes[0].URL, "up", tmp.Name()) - _, matches := up.ExpectRegexp(`[a-f\d]{64}`) - up.ExpectExit() - hash := matches[0] - t.Logf("file uploaded with hash %s", hash) - - // get the file from the HTTP API of each node - for _, node := range cluster.Nodes { - t.Logf("getting file from %s", node.Name) - res, err := http.Get(node.URL + "/bzz:/" + hash) - assertNil(t, err) - assertHTTPResponse(t, res, http.StatusOK, "data") - } -} - -func assertNil(t *testing.T, err error) { - if err != nil { - t.Fatal(err) - } -} - -func assertHTTPResponse(t *testing.T, res *http.Response, expectedStatus int, expectedBody string) { - defer res.Body.Close() - if res.StatusCode != expectedStatus { - t.Fatalf("expected HTTP status %d, got %s", expectedStatus, res.Status) - } - data, err := io.ReadAll(res.Body) - assertNil(t, err) - if string(data) != expectedBody { - t.Fatalf("expected HTTP body %q, got %q", expectedBody, data) - } -} diff --git a/contracts/chequebook/api.go b/contracts/chequebook/api.go deleted file mode 100644 index 1503caa699..0000000000 --- a/contracts/chequebook/api.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chequebook - -import ( - "errors" - "math/big" - - "github.com/XinFinOrg/XDPoSChain/common" -) - -const Version = "1.0" - -var errNoChequebook = errors.New("no chequebook") - -type Api struct { - chequebookf func() *Chequebook -} - -func NewApi(ch func() *Chequebook) *Api { - return &Api{ch} -} - -func (self *Api) Balance() (string, error) { - ch := self.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Balance().String(), nil -} - -func (self *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) { - ch := self.chequebookf() - if ch == nil { - return nil, errNoChequebook - } - return ch.Issue(beneficiary, amount) -} - -func (self *Api) Cash(cheque *Cheque) (txhash string, err error) { - ch := self.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Cash(cheque) -} - -func (self *Api) Deposit(amount *big.Int) (txhash string, err error) { - ch := self.chequebookf() - if ch == nil { - return "", errNoChequebook - } - return ch.Deposit(amount) -} diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go deleted file mode 100644 index 8917d6ab5a..0000000000 --- a/contracts/chequebook/cheque.go +++ /dev/null @@ -1,640 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// Package chequebook package wraps the 'chequebook' Ethereum smart contract. -// -// The functions in this package allow using chequebook for -// issuing, receiving, verifying cheques in ether; (auto)cashing cheques in ether -// as well as (auto)depositing ether to the chequebook contract. -package chequebook - -//go:generate abigen --sol contract/chequebook.sol --exc contract/mortal.sol:mortal,contract/owned.sol:owned --pkg contract --out contract/chequebook.go -//go:generate go run ./gencode.go - -import ( - "bytes" - "context" - "crypto/ecdsa" - "encoding/json" - "fmt" - "math/big" - "os" - "sync" - "time" - - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" - "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/common/hexutil" - "github.com/XinFinOrg/XDPoSChain/contracts/chequebook/contract" - "github.com/XinFinOrg/XDPoSChain/core/types" - "github.com/XinFinOrg/XDPoSChain/crypto" - "github.com/XinFinOrg/XDPoSChain/log" - "github.com/XinFinOrg/XDPoSChain/swarm/services/swap/swap" -) - -// TODO(zelig): watch peer solvency and notify of bouncing cheques -// TODO(zelig): enable paying with cheque by signing off - -// Some functionality requires interacting with the blockchain: -// * setting current balance on peer's chequebook -// * sending the transaction to cash the cheque -// * depositing ether to the chequebook -// * watching incoming ether - -var ( - gasToCash = uint64(2000000) // gas cost of a cash transaction using chequebook - // gasToDeploy = uint64(3000000) -) - -// Backend wraps all methods required for chequebook operation. -type Backend interface { - bind.ContractBackend - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - BalanceAt(ctx context.Context, address common.Address, blockNum *big.Int) (*big.Int, error) -} - -// Cheque represents a payment promise to a single beneficiary. -type Cheque struct { - Contract common.Address // address of chequebook, needed to avoid cross-contract submission - Beneficiary common.Address - Amount *big.Int // cumulative amount of all funds sent - Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey) -} - -func (self *Cheque) String() string { - return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", self.Contract.Hex(), self.Beneficiary.Hex(), self.Amount, self.Sig) -} - -type Params struct { - ContractCode, ContractAbi string -} - -var ContractParams = &Params{contract.ChequebookBin, contract.ChequebookABI} - -// Chequebook can create and sign cheques from a single contract to multiple beneficiaries. -// It is the outgoing payment handler for peer to peer micropayments. -type Chequebook struct { - path string // path to chequebook file - prvKey *ecdsa.PrivateKey // private key to sign cheque with - lock sync.Mutex // - backend Backend // blockchain API - quit chan bool // when closed causes autodeposit to stop - owner common.Address // owner address (derived from pubkey) - contract *contract.Chequebook // abigen binding - session *contract.ChequebookSession // abigen binding with Tx Opts - - // persisted fields - balance *big.Int // not synced with blockchain - contractAddr common.Address // contract address - sent map[common.Address]*big.Int //tallies for beneficiaries - - txhash string // tx hash of last deposit tx - threshold *big.Int // threshold that triggers autodeposit if not nil - buffer *big.Int // buffer to keep on top of balance for fork protection - - log log.Logger // contextual logger with the contract address embedded -} - -func (self *Chequebook) String() string { - return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", self.contractAddr.Hex(), self.owner.Hex(), self.balance, self.prvKey.PublicKey) -} - -// NewChequebook creates a new Chequebook. -func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) { - balance := new(big.Int) - sent := make(map[common.Address]*big.Int) - - chbook, err := contract.NewChequebook(contractAddr, backend) - if err != nil { - return nil, err - } - transactOpts := bind.NewKeyedTransactor(prvKey) - session := &contract.ChequebookSession{ - Contract: chbook, - TransactOpts: *transactOpts, - } - - self = &Chequebook{ - prvKey: prvKey, - balance: balance, - contractAddr: contractAddr, - sent: sent, - path: path, - backend: backend, - owner: transactOpts.From, - contract: chbook, - session: session, - log: log.New("contract", contractAddr), - } - - if (contractAddr != common.Address{}) { - self.setBalanceFromBlockChain() - self.log.Trace("New chequebook initialised", "owner", self.owner, "balance", self.balance) - } - return -} - -func (self *Chequebook) setBalanceFromBlockChain() { - balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil) - if err != nil { - log.Error("Failed to retrieve chequebook balance", "err", err) - } else { - self.balance.Set(balance) - } -} - -// LoadChequebook loads a chequebook from disk (file path). -func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (self *Chequebook, err error) { - var data []byte - data, err = os.ReadFile(path) - if err != nil { - return - } - self, _ = NewChequebook(path, common.Address{}, prvKey, backend) - - err = json.Unmarshal(data, self) - if err != nil { - return nil, err - } - if checkBalance { - self.setBalanceFromBlockChain() - } - log.Trace("Loaded chequebook from disk", "path", path) - - return -} - -// chequebookFile is the JSON representation of a chequebook. -type chequebookFile struct { - Balance string - Contract string - Owner string - Sent map[string]string -} - -// UnmarshalJSON deserialises a chequebook. -func (self *Chequebook) UnmarshalJSON(data []byte) error { - var file chequebookFile - err := json.Unmarshal(data, &file) - if err != nil { - return err - } - _, ok := self.balance.SetString(file.Balance, 10) - if !ok { - return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance) - } - self.contractAddr = common.HexToAddress(file.Contract) - for addr, sent := range file.Sent { - self.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10) - if !ok { - return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent) - } - } - return nil -} - -// MarshalJSON serialises a chequebook. -func (self *Chequebook) MarshalJSON() ([]byte, error) { - var file = &chequebookFile{ - Balance: self.balance.String(), - Contract: self.contractAddr.Hex(), - Owner: self.owner.Hex(), - Sent: make(map[string]string), - } - for addr, sent := range self.sent { - file.Sent[addr.Hex()] = sent.String() - } - return json.Marshal(file) -} - -// Save persists the chequebook on disk, remembering balance, contract address and -// cumulative amount of funds sent for each beneficiary. -func (self *Chequebook) Save() (err error) { - data, err := json.MarshalIndent(self, "", " ") - if err != nil { - return err - } - self.log.Trace("Saving chequebook to disk", self.path) - - return os.WriteFile(self.path, data, os.ModePerm) -} - -// Stop quits the autodeposit go routine to terminate -func (self *Chequebook) Stop() { - defer self.lock.Unlock() - self.lock.Lock() - if self.quit != nil { - close(self.quit) - self.quit = nil - } -} - -// Issue creates a cheque signed by the chequebook owner's private key. The -// signer commits to a contract (one that they own), a beneficiary and amount. -func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) { - defer self.lock.Unlock() - self.lock.Lock() - - if amount.Sign() <= 0 { - return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) - } - if self.balance.Cmp(amount) < 0 { - err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance) - } else { - var sig []byte - sent, found := self.sent[beneficiary] - if !found { - sent = new(big.Int) - self.sent[beneficiary] = sent - } - sum := new(big.Int).Set(sent) - sum.Add(sum, amount) - - sig, err = crypto.Sign(sigHash(self.contractAddr, beneficiary, sum), self.prvKey) - if err == nil { - ch = &Cheque{ - Contract: self.contractAddr, - Beneficiary: beneficiary, - Amount: sum, - Sig: sig, - } - sent.Set(sum) - self.balance.Sub(self.balance, amount) // subtract amount from balance - } - } - - // auto deposit if threshold is set and balance is less then threshold - // note this is called even if issuing cheque fails - // so we reattempt depositing - if self.threshold != nil { - if self.balance.Cmp(self.threshold) < 0 { - send := new(big.Int).Sub(self.buffer, self.balance) - self.deposit(send) - } - } - - return -} - -// Cash is a convenience method to cash any cheque. -func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) { - return ch.Cash(self.session) -} - -// data to sign: contract address, beneficiary, cumulative amount of funds ever sent -func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte { - bigamount := sum.Bytes() - if len(bigamount) > 32 { - return nil - } - var amount32 [32]byte - copy(amount32[32-len(bigamount):32], bigamount) - input := append(contract.Bytes(), beneficiary.Bytes()...) - input = append(input, amount32[:]...) - return crypto.Keccak256(input) -} - -// Balance returns the current balance of the chequebook. -func (self *Chequebook) Balance() *big.Int { - defer self.lock.Unlock() - self.lock.Lock() - return new(big.Int).Set(self.balance) -} - -// Owner returns the owner account of the chequebook. -func (self *Chequebook) Owner() common.Address { - return self.owner -} - -// Address returns the on-chain contract address of the chequebook. -func (self *Chequebook) Address() common.Address { - return self.contractAddr -} - -// Deposit deposits money to the chequebook account. -func (self *Chequebook) Deposit(amount *big.Int) (string, error) { - defer self.lock.Unlock() - self.lock.Lock() - return self.deposit(amount) -} - -// deposit deposits amount to the chequebook account. -// The caller must hold self.lock. -func (self *Chequebook) deposit(amount *big.Int) (string, error) { - // since the amount is variable here, we do not use sessions - depositTransactor := bind.NewKeyedTransactor(self.prvKey) - depositTransactor.Value = amount - chbookRaw := &contract.ChequebookRaw{Contract: self.contract} - tx, err := chbookRaw.Transfer(depositTransactor) - if err != nil { - self.log.Warn("Failed to fund chequebook", "amount", amount, "balance", self.balance, "target", self.buffer, "err", err) - return "", err - } - // assume that transaction is actually successful, we add the amount to balance right away - self.balance.Add(self.balance, amount) - self.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", self.balance, "target", self.buffer) - return tx.Hash().Hex(), nil -} - -// AutoDeposit (re)sets interval time and amount which triggers sending funds to the -// chequebook. Contract backend needs to be set if threshold is not less than buffer, then -// deposit will be triggered on every new cheque issued. -func (self *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - defer self.lock.Unlock() - self.lock.Lock() - self.threshold = threshold - self.buffer = buffer - self.autoDeposit(interval) -} - -// autoDeposit starts a goroutine that periodically sends funds to the chequebook -// contract caller holds the lock the go routine terminates if Chequebook.quit is closed. -func (self *Chequebook) autoDeposit(interval time.Duration) { - if self.quit != nil { - close(self.quit) - self.quit = nil - } - // if threshold >= balance autodeposit after every cheque issued - if interval == time.Duration(0) || self.threshold != nil && self.buffer != nil && self.threshold.Cmp(self.buffer) >= 0 { - return - } - - ticker := time.NewTicker(interval) - self.quit = make(chan bool) - quit := self.quit - - go func() { - for { - select { - case <-quit: - return - case <-ticker.C: - self.lock.Lock() - if self.balance.Cmp(self.buffer) < 0 { - amount := new(big.Int).Sub(self.buffer, self.balance) - txhash, err := self.deposit(amount) - if err == nil { - self.txhash = txhash - } - } - self.lock.Unlock() - } - } - }() -} - -// Outbox can issue cheques from a single contract to a single beneficiary. -type Outbox struct { - chequeBook *Chequebook - beneficiary common.Address -} - -// NewOutbox creates an outbox. -func NewOutbox(chbook *Chequebook, beneficiary common.Address) *Outbox { - return &Outbox{chbook, beneficiary} -} - -// Issue creates cheque. -func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) { - return self.chequeBook.Issue(self.beneficiary, amount) -} - -// AutoDeposit enables auto-deposits on the underlying chequebook. -func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { - self.chequeBook.AutoDeposit(interval, threshold, buffer) -} - -// Stop helps satisfy the swap.OutPayment interface. -func (self *Outbox) Stop() {} - -// String implements fmt.Stringer. -func (self *Outbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.chequeBook.Address().Hex(), self.beneficiary.Hex(), self.chequeBook.Balance()) -} - -// Inbox can deposit, verify and cash cheques from a single contract to a single -// beneficiary. It is the incoming payment handler for peer to peer micropayments. -type Inbox struct { - lock sync.Mutex - contract common.Address // peer's chequebook contract - beneficiary common.Address // local peer's receiving address - sender common.Address // local peer's address to send cashing tx from - signer *ecdsa.PublicKey // peer's public key - txhash string // tx hash of last cashing tx - session *contract.ChequebookSession // abi contract backend with tx opts - quit chan bool // when closed causes autocash to stop - maxUncashed *big.Int // threshold that triggers autocashing - cashed *big.Int // cumulative amount cashed - cheque *Cheque // last cheque, nil if none yet received - log log.Logger // contextual logger with the contract address embedded -} - -// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated -// from blockchain when first cheque is received. -func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (self *Inbox, err error) { - if signer == nil { - return nil, fmt.Errorf("signer is null") - } - chbook, err := contract.NewChequebook(contractAddr, abigen) - if err != nil { - return nil, err - } - transactOpts := bind.NewKeyedTransactor(prvKey) - transactOpts.GasLimit = gasToCash - session := &contract.ChequebookSession{ - Contract: chbook, - TransactOpts: *transactOpts, - } - sender := transactOpts.From - - self = &Inbox{ - contract: contractAddr, - beneficiary: beneficiary, - sender: sender, - signer: signer, - session: session, - cashed: new(big.Int).Set(common.Big0), - log: log.New("contract", contractAddr), - } - self.log.Trace("New chequebook inbox initialized", "beneficiary", self.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer))) - return -} - -func (self *Inbox) String() string { - return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.contract.Hex(), self.beneficiary.Hex(), self.cheque.Amount) -} - -// Stop quits the autocash goroutine. -func (self *Inbox) Stop() { - defer self.lock.Unlock() - self.lock.Lock() - if self.quit != nil { - close(self.quit) - self.quit = nil - } -} - -// Cash attempts to cash the current cheque. -func (self *Inbox) Cash() (txhash string, err error) { - if self.cheque != nil { - txhash, err = self.cheque.Cash(self.session) - self.log.Trace("Cashing in chequebook cheque", "amount", self.cheque.Amount, "beneficiary", self.beneficiary) - self.cashed = self.cheque.Amount - } - return -} - -// AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed -// cheque if maxUncashed is set to 0, then autocash on receipt. -func (self *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) { - defer self.lock.Unlock() - self.lock.Lock() - self.maxUncashed = maxUncashed - self.autoCash(cashInterval) -} - -// autoCash starts a loop that periodically clears the last cheque -// if the peer is trusted. Clearing period could be 24h or a week. -// The caller must hold self.lock. -func (self *Inbox) autoCash(cashInterval time.Duration) { - if self.quit != nil { - close(self.quit) - self.quit = nil - } - // if maxUncashed is set to 0, then autocash on receipt - if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Sign() == 0 { - return - } - - ticker := time.NewTicker(cashInterval) - self.quit = make(chan bool) - quit := self.quit - - go func() { - for { - select { - case <-quit: - return - case <-ticker.C: - self.lock.Lock() - if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 { - txhash, err := self.Cash() - if err == nil { - self.txhash = txhash - } - } - self.lock.Unlock() - } - } - }() -} - -// Receive is called to deposit the latest cheque to the incoming Inbox. -// The given promise must be a *Cheque. -func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) { - ch := promise.(*Cheque) - - defer self.lock.Unlock() - self.lock.Lock() - - var sum *big.Int - if self.cheque == nil { - // the sum is checked against the blockchain once a cheque is received - tally, err := self.session.Sent(self.beneficiary) - if err != nil { - return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err) - } - sum = tally - } else { - sum = self.cheque.Amount - } - - amount, err := ch.Verify(self.signer, self.contract, self.beneficiary, sum) - var uncashed *big.Int - if err == nil { - self.cheque = ch - - if self.maxUncashed != nil { - uncashed = new(big.Int).Sub(ch.Amount, self.cashed) - if self.maxUncashed.Cmp(uncashed) < 0 { - self.Cash() - } - } - self.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed) - } - - return amount, err -} - -// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature. -func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) { - log.Trace("Verifying chequebook cheque", "cheque", self, "sum", sum) - if sum == nil { - return nil, fmt.Errorf("invalid amount") - } - - if self.Beneficiary != beneficiary { - return nil, fmt.Errorf("beneficiary mismatch: %v != %v", self.Beneficiary.Hex(), beneficiary.Hex()) - } - if self.Contract != contract { - return nil, fmt.Errorf("contract mismatch: %v != %v", self.Contract.Hex(), contract.Hex()) - } - - amount := new(big.Int).Set(self.Amount) - if sum != nil { - amount.Sub(amount, sum) - if amount.Sign() <= 0 { - return nil, fmt.Errorf("incorrect amount: %v <= 0", amount) - } - } - - pubKey, err := crypto.SigToPub(sigHash(self.Contract, beneficiary, self.Amount), self.Sig) - if err != nil { - return nil, fmt.Errorf("invalid signature: %v", err) - } - if !bytes.Equal(crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) { - return nil, fmt.Errorf("signer mismatch: %x != %x", crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) - } - return amount, nil -} - -// v/r/s representation of signature -func sig2vrs(sig []byte) (v byte, r, s [32]byte) { - v = sig[64] + 27 - copy(r[:], sig[:32]) - copy(s[:], sig[32:64]) - return -} - -// Cash cashes the cheque by sending an Ethereum transaction. -func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) { - v, r, s := sig2vrs(self.Sig) - tx, err := session.Cash(self.Beneficiary, self.Amount, v, r, s) - if err != nil { - return "", err - } - return tx.Hash().Hex(), nil -} - -// ValidateCode checks that the on-chain code at address matches the expected chequebook -// contract code. This is used to detect suicided chequebooks. -func ValidateCode(ctx context.Context, b Backend, address common.Address) (ok bool, err error) { - code, err := b.CodeAt(ctx, address, nil) - if err != nil { - return false, err - } - return bytes.Equal(code, common.FromHex(contract.ContractDeployedCode)), nil -} diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go deleted file mode 100644 index ee1704b7ba..0000000000 --- a/contracts/chequebook/cheque_test.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package chequebook - -import ( - "crypto/ecdsa" - "math/big" - "os" - "path/filepath" - "testing" - "time" - - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends" - "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/contracts/chequebook/contract" - "github.com/XinFinOrg/XDPoSChain/core" - "github.com/XinFinOrg/XDPoSChain/crypto" - "github.com/XinFinOrg/XDPoSChain/params" -) - -var ( - key0, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - key1, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") - key2, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") - addr0 = crypto.PubkeyToAddress(key0.PublicKey) - addr1 = crypto.PubkeyToAddress(key1.PublicKey) - addr2 = crypto.PubkeyToAddress(key2.PublicKey) -) - -func newTestBackend() *backends.SimulatedBackend { - return backends.NewXDCSimulatedBackend(core.GenesisAlloc{ - addr0: {Balance: big.NewInt(1000000000)}, - addr1: {Balance: big.NewInt(1000000000)}, - addr2: {Balance: big.NewInt(1000000000)}, - }, 10000000, params.TestXDPoSMockChainConfig) -} - -func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) { - deployTransactor := bind.NewKeyedTransactor(prvKey) - deployTransactor.Value = amount - addr, _, _, err := contract.DeployChequebook(deployTransactor, backend) - if err != nil { - return common.Address{}, err - } - backend.Commit() - return addr, nil -} - -func TestIssueAndReceive(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - addr0, err := deploy(key0, big.NewInt(0), backend) - if err != nil { - t.Fatalf("deploy contract: expected no error, got %v", err) - } - chbook, err := NewChequebook(path, addr0, key0, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - amount := common.Big1 - - if _, err = chbook.Issue(addr1, amount); err == nil { - t.Fatalf("expected insufficient funds error, got none") - } - - chbook.balance = new(big.Int).Set(common.Big1) - if chbook.Balance().Cmp(common.Big1) != 0 { - t.Fatalf("expected: %v, got %v", "0", chbook.Balance()) - } - - ch, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if chbook.Balance().Sign() != 0 { - t.Errorf("expected: %v, got %v", "0", chbook.Balance()) - } - - chbox, err := NewInbox(key1, addr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err := chbox.Receive(ch) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if received.Cmp(big.NewInt(43)) != 0 { - t.Errorf("expected: %v, got %v", "43", received) - } - -} - -func TestCheckbookFile(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - chbook, err := NewChequebook(path, addr0, key0, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - chbook.balance = new(big.Int).Set(common.Big1) - - chbook.Save() - - chbook, err = LoadChequebook(path, key0, backend, false) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if chbook.Balance().Cmp(common.Big1) != 0 { - t.Errorf("expected: %v, got %v", "0", chbook.Balance()) - } - - var ch *Cheque - if ch, err = chbook.Issue(addr1, common.Big1); err != nil { - t.Fatalf("expected no error, got %v", err) - } - if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 { - t.Errorf("expected: %v, got %v", "0", ch.Amount) - } - - err = chbook.Save() - if err != nil { - t.Fatalf("expected no error, got %v", err) - } -} - -func TestVerifyErrors(t *testing.T) { - path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") - backend := newTestBackend() - contr0, err := deploy(key0, common.Big2, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - chbook0, err := NewChequebook(path0, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json") - contr1, _ := deploy(key1, common.Big2, backend) - chbook1, err := NewChequebook(path1, contr1, key1, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - chbook0.sent[addr1] = new(big.Int).SetUint64(42) - chbook0.balance = new(big.Int).Set(common.Big2) - chbook1.balance = new(big.Int).Set(common.Big1) - amount := common.Big1 - ch0, err := chbook0.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err := chbox.Receive(ch0) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if received.Cmp(big.NewInt(43)) != 0 { - t.Errorf("expected: %v, got %v", "43", received) - } - - ch1, err := chbook0.Issue(addr2, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - received, err = chbox.Receive(ch1) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected receiver error, got none and value %v", received) - } - - ch2, err := chbook1.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - received, err = chbox.Receive(ch2) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected sender error, got none and value %v", received) - } - - _, err = chbook1.Issue(addr1, new(big.Int).SetInt64(-1)) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected incorrect amount error, got none") - } - - received, err = chbox.Receive(ch0) - t.Logf("correct error: %v", err) - if err == nil { - t.Fatalf("expected incorrect amount error, got none and value %v", received) - } - -} - -func TestDeposit(t *testing.T) { - path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") - backend := newTestBackend() - contr0, _ := deploy(key0, new(big.Int), backend) - - chbook, err := NewChequebook(path0, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - balance := new(big.Int).SetUint64(42) - chbook.Deposit(balance) - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - amount := common.Big1 - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - exp := new(big.Int).SetUint64(41) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - // autodeposit on each issue - chbook.AutoDeposit(0, balance, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - // autodeposit off - chbook.AutoDeposit(0, common.Big0, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - exp = new(big.Int).SetUint64(40) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - // autodeposit every 200ms if new cheque issued - interval := 200 * time.Millisecond - chbook.AutoDeposit(interval, common.Big1, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - exp = new(big.Int).SetUint64(38) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - time.Sleep(3 * interval) - backend.Commit() - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - exp = new(big.Int).SetUint64(40) - chbook.AutoDeposit(4*interval, exp, balance) - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(3 * interval) - backend.Commit() - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - - _, err = chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(1 * interval) - backend.Commit() - - if chbook.Balance().Cmp(balance) != 0 { - t.Fatalf("expected balance %v, got %v", balance, chbook.Balance()) - } - - chbook.AutoDeposit(1*interval, common.Big0, balance) - chbook.Stop() - - _, err = chbook.Issue(addr1, common.Big1) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbook.Issue(addr1, common.Big2) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - time.Sleep(1 * interval) - backend.Commit() - - exp = new(big.Int).SetUint64(39) - if chbook.Balance().Cmp(exp) != 0 { - t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) - } - -} - -func TestCash(t *testing.T) { - path := filepath.Join(os.TempDir(), "chequebook-test.json") - backend := newTestBackend() - contr0, _ := deploy(key0, common.Big2, backend) - - chbook, err := NewChequebook(path, contr0, key0, backend) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - chbook.sent[addr1] = new(big.Int).SetUint64(42) - amount := common.Big1 - chbook.balance = new(big.Int).Set(common.Big1) - ch, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - // cashing latest cheque - if _, err = chbox.Receive(ch); err != nil { - t.Fatalf("expected no error, got %v", err) - } - if _, err = ch.Cash(chbook.session); err != nil { - t.Fatal("Cash failed:", err) - } - backend.Commit() - - chbook.balance = new(big.Int).Set(common.Big3) - ch0, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - ch1, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - interval := 10 * time.Millisecond - // setting autocash with interval of 10ms - chbox.AutoCash(interval, nil) - _, err = chbox.Receive(ch0) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - _, err = chbox.Receive(ch1) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - // after 3x interval time and 2 cheques received, exactly one cashing tx is sent - time.Sleep(4 * interval) - backend.Commit() - - // after stopping autocash no more tx are sent - ch2, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - chbox.Stop() - _, err = chbox.Receive(ch2) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - time.Sleep(2 * interval) - backend.Commit() - - // autocash below 1 - chbook.balance = big.NewInt(2) - chbox.AutoCash(0, common.Big1) - - ch3, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - ch4, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbox.Receive(ch3) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - _, err = chbox.Receive(ch4) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - // autochash on receipt when maxUncashed is 0 - chbook.balance = new(big.Int).Set(common.Big2) - chbox.AutoCash(0, common.Big0) - - ch5, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - ch6, err := chbook.Issue(addr1, amount) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - - _, err = chbox.Receive(ch5) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - - _, err = chbox.Receive(ch6) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - backend.Commit() - -} diff --git a/contracts/chequebook/contract/chequebook.go b/contracts/chequebook/contract/chequebook.go deleted file mode 100644 index cee0c2f3da..0000000000 --- a/contracts/chequebook/contract/chequebook.go +++ /dev/null @@ -1,367 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contract - -import ( - "math/big" - "strings" - - ethereum "github.com/XinFinOrg/XDPoSChain" - "github.com/XinFinOrg/XDPoSChain/accounts/abi" - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" - "github.com/XinFinOrg/XDPoSChain/common" - "github.com/XinFinOrg/XDPoSChain/core/types" - "github.com/XinFinOrg/XDPoSChain/event" -) - -// ChequebookABI is the input ABI used to generate the binding from. -const ChequebookABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"kill\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"sent\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"beneficiary\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"sig_v\",\"type\":\"uint8\"},{\"name\":\"sig_r\",\"type\":\"bytes32\"},{\"name\":\"sig_s\",\"type\":\"bytes32\"}],\"name\":\"cash\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"deadbeat\",\"type\":\"address\"}],\"name\":\"Overdraft\",\"type\":\"event\"}]" - -// ChequebookBin is the compiled bytecode used for deploying new contracts. -const ChequebookBin = `0x606060405260008054600160a060020a033316600160a060020a03199091161790556102ec806100306000396000f3006060604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166341c0e1b581146100585780637bf786f81461006b578063fbf788d61461009c575b005b341561006357600080fd5b6100566100ca565b341561007657600080fd5b61008a600160a060020a03600435166100f1565b60405190815260200160405180910390f35b34156100a757600080fd5b610056600160a060020a036004351660243560ff60443516606435608435610103565b60005433600160a060020a03908116911614156100ef57600054600160a060020a0316ff5b565b60016020526000908152604090205481565b600160a060020a0385166000908152600160205260408120548190861161012957600080fd5b3087876040516c01000000000000000000000000600160a060020a03948516810282529290931690910260148301526028820152604801604051809103902091506001828686866040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f115156101cf57600080fd5b505060206040510351600054600160a060020a039081169116146101f257600080fd5b50600160a060020a03808716600090815260016020526040902054860390301631811161026257600160a060020a0387166000818152600160205260409081902088905582156108fc0290839051600060405180830381858888f19350505050151561025d57600080fd5b6102b7565b6000547f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f97890600160a060020a0316604051600160a060020a03909116815260200160405180910390a186600160a060020a0316ff5b505050505050505600a165627a7a72305820533e856fc37e3d64d1706bcc7dfb6b1d490c8d566ea498d9d01ec08965a896ca0029` - -// DeployChequebook deploys a new Ethereum contract, binding an instance of Chequebook to it. -func DeployChequebook(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Chequebook, error) { - parsed, err := abi.JSON(strings.NewReader(ChequebookABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ChequebookBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}, ChequebookFilterer: ChequebookFilterer{contract: contract}}, nil -} - -// Chequebook is an auto generated Go binding around an Ethereum contract. -type Chequebook struct { - ChequebookCaller // Read-only binding to the contract - ChequebookTransactor // Write-only binding to the contract - ChequebookFilterer // Log filterer for contract events -} - -// ChequebookCaller is an auto generated read-only Go binding around an Ethereum contract. -type ChequebookCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ChequebookTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ChequebookFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ChequebookSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ChequebookSession struct { - Contract *Chequebook // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ChequebookCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ChequebookCallerSession struct { - Contract *ChequebookCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ChequebookTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ChequebookTransactorSession struct { - Contract *ChequebookTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ChequebookRaw is an auto generated low-level Go binding around an Ethereum contract. -type ChequebookRaw struct { - Contract *Chequebook // Generic contract binding to access the raw methods on -} - -// ChequebookCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ChequebookCallerRaw struct { - Contract *ChequebookCaller // Generic read-only contract binding to access the raw methods on -} - -// ChequebookTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ChequebookTransactorRaw struct { - Contract *ChequebookTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewChequebook creates a new instance of Chequebook, bound to a specific deployed contract. -func NewChequebook(address common.Address, backend bind.ContractBackend) (*Chequebook, error) { - contract, err := bindChequebook(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}, ChequebookFilterer: ChequebookFilterer{contract: contract}}, nil -} - -// NewChequebookCaller creates a new read-only instance of Chequebook, bound to a specific deployed contract. -func NewChequebookCaller(address common.Address, caller bind.ContractCaller) (*ChequebookCaller, error) { - contract, err := bindChequebook(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ChequebookCaller{contract: contract}, nil -} - -// NewChequebookTransactor creates a new write-only instance of Chequebook, bound to a specific deployed contract. -func NewChequebookTransactor(address common.Address, transactor bind.ContractTransactor) (*ChequebookTransactor, error) { - contract, err := bindChequebook(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ChequebookTransactor{contract: contract}, nil -} - -// NewChequebookFilterer creates a new log filterer instance of Chequebook, bound to a specific deployed contract. -func NewChequebookFilterer(address common.Address, filterer bind.ContractFilterer) (*ChequebookFilterer, error) { - contract, err := bindChequebook(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ChequebookFilterer{contract: contract}, nil -} - -// bindChequebook binds a generic wrapper to an already deployed contract. -func bindChequebook(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ChequebookABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Chequebook *ChequebookRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Chequebook.Contract.ChequebookCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Chequebook *ChequebookRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.Contract.ChequebookTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Chequebook *ChequebookRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Chequebook.Contract.ChequebookTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Chequebook *ChequebookCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Chequebook.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Chequebook *ChequebookTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Chequebook *ChequebookTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Chequebook.Contract.contract.Transact(opts, method, params...) -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookCaller) Sent(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _Chequebook.contract.Call(opts, out, "sent", arg0) - return *ret0, err -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookSession) Sent(arg0 common.Address) (*big.Int, error) { - return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0) -} - -// Sent is a free data retrieval call binding the contract method 0x7bf786f8. -// -// Solidity: function sent( address) constant returns(uint256) -func (_Chequebook *ChequebookCallerSession) Sent(arg0 common.Address) (*big.Int, error) { - return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactor) Cash(opts *bind.TransactOpts, beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.contract.Transact(opts, "cash", beneficiary, amount, sig_v, sig_r, sig_s) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s) -} - -// Cash is a paid mutator transaction binding the contract method 0xfbf788d6. -// -// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns() -func (_Chequebook *ChequebookTransactorSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) { - return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s) -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookTransactor) Kill(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Chequebook.contract.Transact(opts, "kill") -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookSession) Kill() (*types.Transaction, error) { - return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts) -} - -// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5. -// -// Solidity: function kill() returns() -func (_Chequebook *ChequebookTransactorSession) Kill() (*types.Transaction, error) { - return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts) -} - -// ChequebookOverdraftIterator is returned from FilterOverdraft and is used to iterate over the raw logs and unpacked data for Overdraft events raised by the Chequebook contract. -type ChequebookOverdraftIterator struct { - Event *ChequebookOverdraft // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ChequebookOverdraftIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ChequebookOverdraft) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ChequebookOverdraft) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error retruned any retrieval or parsing error occurred during filtering. -func (it *ChequebookOverdraftIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ChequebookOverdraftIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ChequebookOverdraft represents a Overdraft event raised by the Chequebook contract. -type ChequebookOverdraft struct { - Deadbeat common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOverdraft is a free log retrieval operation binding the contract event 0x2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f978. -// -// Solidity: event Overdraft(deadbeat address) -func (_Chequebook *ChequebookFilterer) FilterOverdraft(opts *bind.FilterOpts) (*ChequebookOverdraftIterator, error) { - - logs, sub, err := _Chequebook.contract.FilterLogs(opts, "Overdraft") - if err != nil { - return nil, err - } - return &ChequebookOverdraftIterator{contract: _Chequebook.contract, event: "Overdraft", logs: logs, sub: sub}, nil -} - -// WatchOverdraft is a free log subscription operation binding the contract event 0x2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f978. -// -// Solidity: event Overdraft(deadbeat address) -func (_Chequebook *ChequebookFilterer) WatchOverdraft(opts *bind.WatchOpts, sink chan<- *ChequebookOverdraft) (event.Subscription, error) { - - logs, sub, err := _Chequebook.contract.WatchLogs(opts, "Overdraft") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ChequebookOverdraft) - if err := _Chequebook.contract.UnpackLog(event, "Overdraft", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/contracts/chequebook/contract/chequebook.sol b/contracts/chequebook/contract/chequebook.sol deleted file mode 100644 index c386cceed8..0000000000 --- a/contracts/chequebook/contract/chequebook.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.4.18; - -import "./mortal.sol"; - -/// @title Chequebook for Ethereum micropayments -/// @author Daniel A. Nagy -contract chequebook is mortal { - // Cumulative paid amount in wei to each beneficiary - mapping (address => uint256) public sent; - - /// @notice Overdraft event - event Overdraft(address deadbeat); - - // Allow sending ether to the chequebook. - function() public payable { } - - /// @notice Cash cheque - /// - /// @param beneficiary beneficiary address - /// @param amount cumulative amount in wei - /// @param sig_v signature parameter v - /// @param sig_r signature parameter r - /// @param sig_s signature parameter s - /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount - function cash(address beneficiary, uint256 amount, uint8 sig_v, bytes32 sig_r, bytes32 sig_s) public { - // Check if the cheque is old. - // Only cheques that are more recent than the last cashed one are considered. - require(amount > sent[beneficiary]); - // Check the digital signature of the cheque. - bytes32 hash = keccak256(address(this), beneficiary, amount); - require(owner == ecrecover(hash, sig_v, sig_r, sig_s)); - // Attempt sending the difference between the cumulative amount on the cheque - // and the cumulative amount on the last cashed cheque to beneficiary. - uint256 diff = amount - sent[beneficiary]; - if (diff <= this.balance) { - // update the cumulative amount before sending - sent[beneficiary] = amount; - beneficiary.transfer(diff); - } else { - // Upon failure, punish owner for writing a bounced cheque. - // owner.sendToDebtorsPrison(); - Overdraft(owner); - // Compensate beneficiary. - selfdestruct(beneficiary); - } - } -} diff --git a/contracts/chequebook/contract/code.go b/contracts/chequebook/contract/code.go deleted file mode 100644 index d837a9d601..0000000000 --- a/contracts/chequebook/contract/code.go +++ /dev/null @@ -1,5 +0,0 @@ -package contract - -// ContractDeployedCode is used to detect suicides. This constant needs to be -// updated when the contract code is changed. -const ContractDeployedCode = "0x6060604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166341c0e1b581146100585780637bf786f81461006b578063fbf788d61461009c575b005b341561006357600080fd5b6100566100ca565b341561007657600080fd5b61008a600160a060020a03600435166100f1565b60405190815260200160405180910390f35b34156100a757600080fd5b610056600160a060020a036004351660243560ff60443516606435608435610103565b60005433600160a060020a03908116911614156100ef57600054600160a060020a0316ff5b565b60016020526000908152604090205481565b600160a060020a0385166000908152600160205260408120548190861161012957600080fd5b3087876040516c01000000000000000000000000600160a060020a03948516810282529290931690910260148301526028820152604801604051809103902091506001828686866040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f115156101cf57600080fd5b505060206040510351600054600160a060020a039081169116146101f257600080fd5b50600160a060020a03808716600090815260016020526040902054860390301631811161026257600160a060020a0387166000818152600160205260409081902088905582156108fc0290839051600060405180830381858888f19350505050151561025d57600080fd5b6102b7565b6000547f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f97890600160a060020a0316604051600160a060020a03909116815260200160405180910390a186600160a060020a0316ff5b505050505050505600a165627a7a72305820533e856fc37e3d64d1706bcc7dfb6b1d490c8d566ea498d9d01ec08965a896ca0029" diff --git a/contracts/chequebook/contract/mortal.sol b/contracts/chequebook/contract/mortal.sol deleted file mode 100644 index c43f1e4f79..0000000000 --- a/contracts/chequebook/contract/mortal.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.4.0; - -import "./owned.sol"; - -contract mortal is owned { - function kill() public { - if (msg.sender == owner) - selfdestruct(owner); - } -} diff --git a/contracts/chequebook/contract/owned.sol b/contracts/chequebook/contract/owned.sol deleted file mode 100644 index ee9860d343..0000000000 --- a/contracts/chequebook/contract/owned.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.0; - -contract owned { - address owner; - - modifier onlyowner() { - if (msg.sender == owner) { - _; - } - } - - function owned() public { - owner = msg.sender; - } -} diff --git a/contracts/chequebook/gencode.go b/contracts/chequebook/gencode.go deleted file mode 100644 index 49590f6b93..0000000000 --- a/contracts/chequebook/gencode.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -//go:build none -// +build none - -// This program generates contract/code.go, which contains the chequebook code -// after deployment. -package main - -import ( - "fmt" - "math/big" - "os" - - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" - "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends" - "github.com/XinFinOrg/XDPoSChain/contracts/chequebook/contract" - "github.com/XinFinOrg/XDPoSChain/core" - "github.com/XinFinOrg/XDPoSChain/crypto" -) - -var ( - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAlloc = core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(500000000000)}, - } -) - -func main() { - backend := backends.NewSimulatedBackend(testAlloc) - auth := bind.NewKeyedTransactor(testKey) - - // Deploy the contract, get the code. - addr, _, _, err := contract.DeployChequebook(auth, backend) - if err != nil { - panic(err) - } - backend.Commit() - code, err := backend.CodeAt(nil, addr, nil) - if err != nil { - panic(err) - } - if len(code) == 0 { - panic("empty code") - } - - // Write the output file. - content := fmt.Sprintf(`package contract - -// ContractDeployedCode is used to detect suicides. This constant needs to be -// updated when the contract code is changed. -const ContractDeployedCode = "%#x" -`, code) - if err := os.WriteFile("contract/code.go", []byte(content), 0644); err != nil { - panic(err) - } -} diff --git a/swarm/README.md b/swarm/README.md new file mode 100644 index 0000000000..f33af5095e --- /dev/null +++ b/swarm/README.md @@ -0,0 +1,7 @@ +# Swarm + +https://www.ethswarm.org/ + +Swarm is a distributed storage platform and content distribution service, a native base layer service of the ethereum web3 stack. The primary objective of Swarm is to provide a decentralized and redundant store for dapp code and data as well as block chain and state data. Swarm is also set out to provide various base layer services for web3, including node-to-node messaging, media streaming, decentralised database services and scalable state-channel infrastructure for decentralised service economies. + +**Note**: The codebase has been moved to [ethersphere/bee](https://github.com/ethersphere/bee) \ No newline at end of file