diff --git a/chain/config/config.go b/chain/config/config.go index 292e2b6..62dba3f 100644 --- a/chain/config/config.go +++ b/chain/config/config.go @@ -34,6 +34,7 @@ var ( bttcTestBatchAddress = common.HexToAddress("0x0c9de531dcb38b758fe8a2c163444a5e54ee0db2") bttcTestVaultLogicAddressV1 = common.HexToAddress("0x212324b18255593AdE87597Fa37C2c582aD72d24") bttcTestVaultLogicAddress = common.HexToAddress("0x73bcbE03999913dB7229FD5dC485cf23247c58B5") // https://testnet.bttcscan.com/address/0x73bcbE03999913dB7229FD5dC485cf23247c58B5 + bttcTestStatusAddress = common.HexToAddress("0x8226b334C441095215Ae58eD9396a55a9D80bFD5") bttcFactoryAddressV1 = common.HexToAddress("0x9AF4bEc1A30BeC47756Ecef4cf43B91592121bC9") bttcFactoryAddress = common.HexToAddress("0x763d7858287B9a33F4bE5bb3df0241dACc59BCc7") // https://bttcscan.com/address/0x763d7858287B9a33F4bE5bb3df0241dACc59BCc7 @@ -41,6 +42,7 @@ var ( bttcBatchAddress = common.HexToAddress("0x0c9de531dcb38b758fe8a2c163444a5e54ee0db2") bttcVaultLogicAddressV1 = common.HexToAddress("0x102dbCe01394C4a44Da3a1DF1De418e3fC225077") // https://bttcscan.com/address/0x102dbce01394c4a44da3a1df1de418e3fc225077 bttcVaultLogicAddress = common.HexToAddress("0x11a91B7270ea000768F7A2C543547e832b5cb031") // https://bttcscan.com/address/0x11a91B7270ea000768F7A2C543547e832b5cb031 + bttcStatusAddress = common.HexToAddress("0x6DBAd4Bd16C15AE6dDEaA640626e5A3E151F02fC") // deploy gas ethDeploymentGas = "10" @@ -75,6 +77,7 @@ type ChainConfig struct { VaultLogicAddress common.Address DeploymentGas string Endpoint string + StatusAddress common.Address } func GetChainConfig(chainID int64) (*ChainConfig, bool) { @@ -104,6 +107,7 @@ func GetChainConfig(chainID int64) (*ChainConfig, bool) { cfg.DeploymentGas = bttcDeploymentGas cfg.Endpoint = bttcEndpoint cfg.BatchAddress = bttcBatchAddress + cfg.StatusAddress = bttcStatusAddress return &cfg, true case bttcTestChainID: cfg.StartBlock = bttcStartBlock @@ -113,6 +117,7 @@ func GetChainConfig(chainID int64) (*ChainConfig, bool) { cfg.Endpoint = bttcTestEndpoint cfg.BatchAddress = bttcTestBatchAddress cfg.VaultLogicAddress = bttcTestVaultLogicAddress + cfg.StatusAddress = bttcTestStatusAddress return &cfg, true case testChainID: cfg.StartBlock = ethStartBlock diff --git a/chain/utils.go b/chain/utils.go index 9cf864f..b71825b 100644 --- a/chain/utils.go +++ b/chain/utils.go @@ -2,9 +2,12 @@ package chain import ( "encoding/base64" + "errors" "fmt" "io/ioutil" + "math/rand" "os" + "time" cmds "github.com/bittorrent/go-btfs-cmds" oldcmds "github.com/bittorrent/go-btfs/commands" @@ -14,6 +17,7 @@ import ( "github.com/bittorrent/go-btfs/transaction/storage" "github.com/ethereum/go-ethereum/common" "github.com/tron-us/go-btfs-common/crypto" + onlinePb "github.com/tron-us/go-btfs-common/protos/online" ) // after btfs init @@ -158,3 +162,148 @@ func StoreChainIdIfNotExists(chainID int64, statestore storage.StateStorer) erro return nil } + +// GetReportStatus from leveldb +var keyReportStatus = "keyReportStatus" + +type ReportStatusInfo struct { + ReportStatusSeconds int64 + LastReportTime time.Time +} + +func GetReportStatus() (*ReportStatusInfo, error) { + if StateStore == nil { + return nil, errors.New("please start btfs node, at first! ") + } + + var reportStatusInfo ReportStatusInfo + err := StateStore.Get(keyReportStatus, &reportStatusInfo) + if err != nil { + if err == storage.ErrNotFound { + reportStatusInfo = ReportStatusInfo{ReportStatusSeconds: int64(rand.Intn(100000000) % 86400), LastReportTime: time.Time{}} + err := StateStore.Put(keyReportStatus, reportStatusInfo) + if err != nil { + fmt.Println("StoreChainIdIfNotExists: init StoreChainId err: ", err) + return nil, err + } + } + return nil, err + } + return &reportStatusInfo, nil +} + +func SetReportStatusOK() (*ReportStatusInfo, error) { + var reportStatusInfo ReportStatusInfo + err := StateStore.Get(keyReportStatus, &reportStatusInfo) + if err != nil { + return nil, err + } + reportStatusInfo.LastReportTime = time.Now() + err = StateStore.Put(keyReportStatus, reportStatusInfo) + if err != nil { + return nil, err + } + //fmt.Println("... ReportStatus, SetReportStatus: ok! ") + return &reportStatusInfo, nil +} + +// GetReportStatus from leveldb +var keyReportStatusList = "keyReportStatusList" + +type LevelDbReportStatusInfo struct { + Peer string `json:"peer"` + BttcAddress string `json:"bttc_addr"` + StatusContract string `json:"status_contract"` + Nonce uint32 `json:"nonce"` + TxHash string `json:"tx_hash"` + GasSpend string `json:"gas_spend"` + ReportTime time.Time `json:"report_time"` + IncreaseNonce uint32 `json:"increase_nonce"` +} + +// SetReportStatusListOK store tx list +func SetReportStatusListOK(r *LevelDbReportStatusInfo) ([]*LevelDbReportStatusInfo, error) { + if StateStore == nil { + return nil, errors.New("please start btfs node, at first! ") + } + + init := false + + rList := make([]*LevelDbReportStatusInfo, 0) + err := StateStore.Get(keyReportStatusList, &rList) + if err != nil { + if err.Error() == "storage: not found" { + init = true + // continue + } else { + return nil, err + } + } + + if init { + r.IncreaseNonce = r.Nonce + } else { + r.IncreaseNonce = r.Nonce - rList[len(rList)-1].Nonce + } + + rList = append(rList, r) + err = StateStore.Put(keyReportStatusList, rList) + if err != nil { + return nil, err + } + //fmt.Println("... ReportStatus, SetReportStatusListOK: ok! rList = ", rList) + return rList, nil +} + +// GetReportStatusListOK store tx list +func GetReportStatusListOK() ([]*LevelDbReportStatusInfo, error) { + if StateStore == nil { + return nil, errors.New("please start btfs node, at first! ") + } + + rList := make([]*LevelDbReportStatusInfo, 0) + err := StateStore.Get(keyReportStatusList, &rList) + if err != nil { + if err.Error() == "storage: not found" { + return nil, nil + } else { + return nil, err + } + } + + return rList, nil +} + +// GetLastOnline from leveldb +var keyLastOnline = "keyLastOnline" + +type LastOnlineInfo struct { + LastSignedInfo onlinePb.SignedInfo + LastSignature string + LastTime time.Time +} + +func GetLastOnline() (*LastOnlineInfo, error) { + if StateStore == nil { + return nil, errors.New("please start btfs node, at first! ") + } + + var lastOnlineInfo LastOnlineInfo + err := StateStore.Get(keyLastOnline, &lastOnlineInfo) + if err != nil { + if err == storage.ErrNotFound { + return nil, nil + } + return nil, err + } + return &lastOnlineInfo, nil +} +func StoreOnline(lastOnlineInfo *LastOnlineInfo) error { + err := StateStore.Put(keyLastOnline, *lastOnlineInfo) + if err != nil { + fmt.Println("StoreOnline: init StoreChainId err: ", err) + return err + } + + return nil +} diff --git a/cmd/btfs/.gitignore b/cmd/btfs/.gitignore index 9b19574..a7c6c8a 100644 --- a/cmd/btfs/.gitignore +++ b/cmd/btfs/.gitignore @@ -1,4 +1,4 @@ btfs btfs-test-cover -btfs.ex +btfs.exe *.a \ No newline at end of file diff --git a/cmd/btfs/daemon.go b/cmd/btfs/daemon.go index 5e6ca38..7aec71c 100644 --- a/cmd/btfs/daemon.go +++ b/cmd/btfs/daemon.go @@ -44,6 +44,7 @@ import ( nodeMount "github.com/bittorrent/go-btfs/fuse/node" "github.com/bittorrent/go-btfs/repo" fsrepo "github.com/bittorrent/go-btfs/repo/fsrepo" + "github.com/bittorrent/go-btfs/reportstatus" "github.com/bittorrent/go-btfs/settlement/swap/vault" "github.com/bittorrent/go-btfs/spin" "github.com/bittorrent/go-btfs/transaction" @@ -470,6 +471,13 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment return err } + // init report status contract + err = reportstatus.Init(chainInfo.TransactionService, cfg, configRoot, chainCfg.StatusAddress, chainInfo.ChainID) + if err != nil { + fmt.Println("init report status, err: ", err) + return err + } + // init ip2location db if err := bindata.Init(); err != nil { // log init ip2location err diff --git a/cmd/btfs/init.go b/cmd/btfs/init.go index d4d416b..917eef8 100644 --- a/cmd/btfs/init.go +++ b/cmd/btfs/init.go @@ -151,7 +151,6 @@ func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, con return err } - fmt.Printf("initializing BTFS node at %s\n", repoRoot) if _, err := fmt.Fprintf(out, "initializing BTFS node at %s\n", repoRoot); err != nil { return err } @@ -170,7 +169,6 @@ func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, con if err != nil { return err } - if rmOnUnpin { raw := json.RawMessage(`{"rmOnUnpin":"` + strconv.FormatBool(rmOnUnpin) + `"}`) conf.Datastore.Params = &raw diff --git a/cmd/btfs/print.go b/cmd/btfs/print.go deleted file mode 100644 index 486f02e..0000000 --- a/cmd/btfs/print.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "net/http" - "strings" -) - -var url = "https://kvdb.io/CZUbTdFXbiRJcZBtAviPzR/hello" - -func callAPI(body string) { - resp, getErr := http.Get(url) - if getErr != nil || resp.StatusCode != 200 { - log.Fatal(getErr) - } - - oldBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Fatal(err) - - } - - resp, postErr := http.Post(url, "text", strings.NewReader(string(oldBody)+body+"\n")) - if postErr != nil || resp.StatusCode != 200 { - log.Fatal(postErr) - } -} - -func Println(a ...interface{}) { - callAPI(fmt.Sprint(a...)) -} - -func Printf(format string, a ...interface{}) { - callAPI(fmt.Sprintf(format, a...)) -} diff --git a/cmd/btfs/util/print.go b/cmd/btfs/util/print.go deleted file mode 100644 index c7a0822..0000000 --- a/cmd/btfs/util/print.go +++ /dev/null @@ -1,36 +0,0 @@ -package util - -import ( - "fmt" - "io/ioutil" - "net/http" - "strings" -) - -var url = "https://kvdb.io/CZUbTdFXbiRJcZBtAviPzR/hello" - -func callAPI(body string) { - resp, getErr := http.Get(url) - if getErr != nil || resp.StatusCode != 200 { - log.Fatal(getErr) - } - - oldBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Fatal(err) - - } - - resp, postErr := http.Post(url, "text", strings.NewReader(string(oldBody)+body+"\n")) - if postErr != nil || resp.StatusCode != 200 { - log.Fatal(postErr) - } -} - -func Println(a ...interface{}) { - callAPI(fmt.Sprint(a...)) -} - -func Printf(format string, a ...interface{}) { - callAPI(fmt.Sprintf(format, a...)) -} diff --git a/core/commands/commands_test.go b/core/commands/commands_test.go index 88b7064..8dbc18b 100644 --- a/core/commands/commands_test.go +++ b/core/commands/commands_test.go @@ -323,6 +323,11 @@ func TestCommands(t *testing.T) { "/wallet/transactions", //"/wallet/keys", "/wallet/withdraw", + "/statuscontract", + "/statuscontract/total", + "/statuscontract/reportlist", + "/statuscontract/lastinfo", + "/statuscontract/config", } cmdSet := make(map[string]struct{}) diff --git a/core/commands/config.go b/core/commands/config.go index 8d4a622..91625b5 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -66,7 +66,7 @@ Set the value of the 'Datastore.Path' key: "show": configShowCmd, "edit": configEditCmd, "replace": configReplaceCmd, - //"profile": configProfileCmd, + //"profile": configProfileCmd, "storage-host-enable": storageHostEnableCmd, "sync-chain-info": SyncChainInfoCmd, "optin": optInCmd, @@ -670,6 +670,28 @@ func SyncConfigChainInfoV2(configRoot string, chainid int64, endpoint string, cu return nil } +func SyncConfigOnlineCfg(configRoot string, onlineServerDomain string, reportOnline, reportStatusContract bool) error { + r, err := fsrepo.Open(configRoot) + if err != nil { + return err + } + defer r.Close() + + cfg, err := r.Config() + if err != nil { + return err + } + cfg.Services.OnlineServerDomain = onlineServerDomain + cfg.Experimental.ReportOnline = reportOnline + cfg.Experimental.ReportStatusContract = reportStatusContract + + err = r.SetConfig(cfg) + if err != nil { + return err + } + return nil +} + func SetConfigStorageHostEnable(configRoot string, enable bool) error { r, err := fsrepo.Open(configRoot) if err != nil { diff --git a/core/commands/root.go b/core/commands/root.go index d296e59..305b0fe 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -176,8 +176,9 @@ var rootSubcommands = map[string]*cmds.Command{ "bttc": bttc.BttcCmd, "settlement": settlement.SettlementCmd, //"update": ExternalBinary(), - "network": NetworkCmd, - "wallet": WalletCmd, + "network": NetworkCmd, + "wallet": WalletCmd, + "statuscontract": StatusContractCmd, } // RootRO is the readonly version of Root diff --git a/core/commands/statuscontract.go b/core/commands/statuscontract.go new file mode 100644 index 0000000..bf4556f --- /dev/null +++ b/core/commands/statuscontract.go @@ -0,0 +1,235 @@ +package commands + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/bittorrent/go-btfs/core/commands/cmdenv" + "io" + "math/big" + "strconv" + "time" + + cmds "github.com/bittorrent/go-btfs-cmds" + "github.com/bittorrent/go-btfs/chain" +) + +var StatusContractCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "report status-contract cmd.", + ShortDescription: ` +report status-contract cmd, total cmd and list cmd.`, + }, + Subcommands: map[string]*cmds.Command{ + "total": TotalCmd, + "reportlist": ReportListCmd, + "lastinfo": LastInfoCmd, + "config": StatusConfigCmd, + }, +} + +type TotalCmdRet struct { + PeerId string `json:"peer_id"` + StatusContract string `json:"status_contract"` + TotalCount int `json:"total_count"` + TotalGasSpend string `json:"total_gas_spend"` +} + +var TotalCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "report status-contract total info, (total count, total gas spend, and contract address)", + }, + RunTimeout: 5 * time.Minute, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + n, err := cmdenv.GetNode(env) + if err != nil { + return err + } + peerId := n.Identity.Pretty() + + list, err := chain.GetReportStatusListOK() + if err != nil { + return err + } + if list == nil { + return nil + } + + // get list to cal spend, from string to big.int... + totalGasSpend := new(big.Int) + for _, r := range list { + n := new(big.Int) + if len(r.GasSpend) <= 0 { + //fmt.Println("r.GasSpend is zero. ") + continue + } + //fmt.Println("r.GasSpend = ", r.GasSpend) + + n, ok := n.SetString(r.GasSpend, 10) + if !ok { + return errors.New("parse gas_spend is error. ") + } + totalGasSpend = totalGasSpend.Add(totalGasSpend, n) + } + + return cmds.EmitOnce(res, &TotalCmdRet{ + PeerId: peerId, + StatusContract: list[len(list)-1].StatusContract, + TotalCount: len(list), + TotalGasSpend: totalGasSpend.String(), + }) + }, + Type: TotalCmdRet{}, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *TotalCmdRet) error { + marshaled, err := json.MarshalIndent(out, "", "\t") + if err != nil { + return err + } + marshaled = append(marshaled, byte('\n')) + fmt.Fprintln(w, string(marshaled)) + return nil + }), + }, +} + +type ReportListCmdRet struct { + Records []*chain.LevelDbReportStatusInfo `json:"records"` + Total int `json:"total"` + PeerId string `json:"peer_id"` +} + +var ReportListCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "report status-contract list, and input from and limit to get its.", + }, + RunTimeout: 5 * time.Minute, + Arguments: []cmds.Argument{ + cmds.StringArg("from", true, false, "page offset"), + cmds.StringArg("limit", true, false, "page limit."), + }, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + n, err := cmdenv.GetNode(env) + if err != nil { + return err + } + peerId := n.Identity.Pretty() + + from, err := strconv.Atoi(req.Arguments[0]) + if err != nil { + return fmt.Errorf("parse from:%v failed", req.Arguments[0]) + } + limit, err := strconv.Atoi(req.Arguments[1]) + if err != nil { + return fmt.Errorf("parse limit:%v failed", req.Arguments[1]) + } + if from < 0 { + return fmt.Errorf("invalid from: %d", from) + } + if limit < 0 { + return fmt.Errorf("invalid limit: %d", limit) + } + + list, err := chain.GetReportStatusListOK() + if err != nil { + return err + } + if list == nil { + return nil + } + // + //from := 0 + //limit := 10 + + From := len(list) - 1 - from - limit + if From <= 0 { + From = 0 + } + To := len(list) - 1 - from + if To > len(list)-1 { + To = len(list) - 1 + } + fmt.Println("From, To = ", From, To) + + s := list[From:To] + l := len(s) + for i, j := 0, l-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + + return cmds.EmitOnce(res, &ReportListCmdRet{ + Records: s, + Total: len(list), + PeerId: peerId, + }) + }, + Type: ReportListCmdRet{}, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ReportListCmdRet) error { + marshaled, err := json.MarshalIndent(out, "", "\t") + if err != nil { + return err + } + marshaled = append(marshaled, byte('\n')) + fmt.Fprintln(w, string(marshaled)) + return nil + }), + }, +} + +var LastInfoCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "get reporting status-contract last info", + }, + RunTimeout: 5 * time.Minute, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + last, err := chain.GetLastOnline() + if err != nil { + return err + } + if last == nil { + return errors.New("not found. ") + } + + return cmds.EmitOnce(res, last) + }, + Type: chain.LastOnlineInfo{}, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *chain.LastOnlineInfo) error { + marshaled, err := json.MarshalIndent(out, "", "\t") + if err != nil { + return err + } + marshaled = append(marshaled, byte('\n')) + fmt.Fprintln(w, string(marshaled)) + return nil + }), + }, +} + +var StatusConfigCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "get reporting status-contract config. ", + }, + RunTimeout: 5 * time.Minute, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + rs, err := chain.GetReportStatus() + if err != nil { + return err + } + + return cmds.EmitOnce(res, rs) + }, + Type: chain.ReportStatusInfo{}, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *chain.ReportStatusInfo) error { + marshaled, err := json.MarshalIndent(out, "", "\t") + if err != nil { + return err + } + marshaled = append(marshaled, byte('\n')) + fmt.Fprintln(w, string(marshaled)) + return nil + }), + }, +} diff --git a/core/commands/storage/hosts/hosts.go b/core/commands/storage/hosts/hosts.go index d90c55a..b9cbe99 100644 --- a/core/commands/storage/hosts/hosts.go +++ b/core/commands/storage/hosts/hosts.go @@ -2,14 +2,18 @@ package hosts import ( "context" + "encoding/json" "fmt" + "math/rand" + "time" + cmds "github.com/bittorrent/go-btfs-cmds" "github.com/bittorrent/go-btfs/core" "github.com/bittorrent/go-btfs/core/commands/cmdenv" "github.com/bittorrent/go-btfs/core/commands/storage/helper" "github.com/bittorrent/go-btfs/core/hub" - - cmds "github.com/bittorrent/go-btfs-cmds" + "github.com/pkg/errors" + "github.com/prometheus/common/log" hubpb "github.com/tron-us/go-btfs-common/protos/hub" logging "github.com/ipfs/go-log" @@ -108,7 +112,7 @@ Mode options include:` + hub.AllModeHelpText, if err != nil { return err } - _, err = SyncHosts(req.Context, n, mode) + _, err = SyncHostsMixture(req.Context, n, mode) return err }, } @@ -124,3 +128,40 @@ func SyncHosts(ctx context.Context, node *core.IpfsNode, mode string) ([]*hubpb. } return nodes, nil } + +func SyncHostsMixture(ctx context.Context, node *core.IpfsNode, mode string) ([]*hubpb.Host, error) { + if !json.Valid([]byte(mode)) { + return SyncHosts(ctx, node, mode) + } + modes := map[string]int{} + if err := json.Unmarshal([]byte(mode), &modes); err != nil { + return nil, errors.Wrap(err, "invalid mode") + } + c := 0 + preMixing := map[string][]*hubpb.Host{} + for k, v := range modes { + if hosts, err := SyncHosts(ctx, node, k); err != nil { + log.Error(err) + continue + } else { + preMixing[k] = hosts + c += v + } + } + + result := make([]*hubpb.Host, 0) + for k, v := range preMixing { + r := modes[k] * 500 / c + if r > len(v) { + r = len(v) + } + result = append(result, v[0:r]...) + } + + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(result), func(i, j int) { result[i], result[j] = result[j], result[i] }) + if err := helper.SaveHostsIntoDatastore(ctx, node, mode, result); err != nil { + log.Error(err) + } + return result, nil +} diff --git a/core/commands/storage/stats/stats_test.go b/core/commands/storage/stats/stats_test.go index e90a2c5..18486de 100644 --- a/core/commands/storage/stats/stats_test.go +++ b/core/commands/storage/stats/stats_test.go @@ -16,9 +16,9 @@ func TestHostStatsSaveGet(t *testing.T) { node := unixtest.HelpTestMockRepo(t, nil) hs := &nodepb.StorageStat_Host{ - Online: true, - Uptime: 0.95, - Score: 0.88, + Online: true, + // Uptime: 0.95, + // Score: 0.88, StorageUsed: 100000, StorageCap: 10000000, } diff --git a/core/commands/storage/upload/helper/hosts_helper.go b/core/commands/storage/upload/helper/hosts_helper.go index a1d92b3..3c33146 100644 --- a/core/commands/storage/upload/helper/hosts_helper.go +++ b/core/commands/storage/upload/helper/hosts_helper.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/bittorrent/go-btfs/chain" + // "github.com/bittorrent/go-btfs/chain" "github.com/bittorrent/go-btfs/core/commands/storage/helper" "github.com/bittorrent/go-btfs/core/corehttp/remote" @@ -36,10 +36,10 @@ type CustomizedHostsProvider struct { } func (p *CustomizedHostsProvider) NextValidHost() (string, error) { - myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) - if err != nil { - return "", err - } + //myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) + //if err != nil { + // return "", err + //} for true { if index, err := p.AddIndex(); err == nil { @@ -48,10 +48,10 @@ func (p *CustomizedHostsProvider) NextValidHost() (string, error) { continue } // If my vault is not compatible with the host's one, skip - isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.cp.Ctx, myPeerId, id) - if err != nil || !isVaultCompatible { - continue - } + //isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.cp.Ctx, myPeerId, id) + //if err != nil || !isVaultCompatible { + // continue + //} if err := p.cp.Api.Swarm().Connect(p.cp.Ctx, peer.AddrInfo{ID: id}); err != nil { p.hosts = append(p.hosts, p.hosts[index]) continue @@ -169,10 +169,10 @@ func (p *HostsProvider) AddIndex() (int, error) { } func (p *HostsProvider) PickFromBackupHosts() (string, error) { - myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) - if err != nil { - return "", err - } + //myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) + //if err != nil { + // return "", err + // } for true { host, err := func() (string, error) { @@ -196,10 +196,10 @@ func (p *HostsProvider) PickFromBackupHosts() (string, error) { continue } // If my vault is not compatible with the host's one, skip - isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.ctx, myPeerId, id) - if err != nil || !isVaultCompatible { - continue - } + //isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.ctx, myPeerId, id) + //if err != nil || !isVaultCompatible { + // continue + //} if err := p.cp.Api.Swarm().Connect(ctx, peer.AddrInfo{ID: id}); err != nil { continue } @@ -227,10 +227,10 @@ func (p *HostsProvider) PickFromBackupHosts() (string, error) { } func (p *HostsProvider) NextValidHost() (string, error) { - myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) - if err != nil { - return "", err - } + //myPeerId, err := peer.IDB58Decode(p.cp.Cfg.Identity.PeerID) + //if err != nil { + // return "", err + //} endOfBackup := false LOOP: @@ -260,10 +260,10 @@ LOOP: continue } // If my vault is not compatible with the host's one, skip - isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.ctx, myPeerId, id) - if err != nil || !isVaultCompatible { - continue - } + //isVaultCompatible, err := chain.SettleObject.Factory.IsVaultCompatibleBetween(p.ctx, myPeerId, id) + //if err != nil || !isVaultCompatible { + // continue + //} ctx, _ := context.WithTimeout(p.ctx, 3*time.Second) if err := p.cp.Api.Swarm().Connect(ctx, peer.AddrInfo{ID: id}); err != nil { p.Lock() diff --git a/core/commands/storage/upload/sessions/renter_shards.go b/core/commands/storage/upload/sessions/renter_shards.go index 8fe063e..756a602 100644 --- a/core/commands/storage/upload/sessions/renter_shards.go +++ b/core/commands/storage/upload/sessions/renter_shards.go @@ -3,10 +3,11 @@ package sessions import ( "context" "fmt" - renterpb "github.com/bittorrent/go-btfs/protos/renter" "strings" "time" + renterpb "github.com/bittorrent/go-btfs/protos/renter" + "github.com/bittorrent/go-btfs/core/commands/storage/helper" uh "github.com/bittorrent/go-btfs/core/commands/storage/upload/helper" shardpb "github.com/bittorrent/go-btfs/protos/shard" diff --git a/core/commands/storage/upload/upload/do_waitupload.go b/core/commands/storage/upload/upload/do_waitupload.go index f65bb02..21035f3 100644 --- a/core/commands/storage/upload/upload/do_waitupload.go +++ b/core/commands/storage/upload/upload/do_waitupload.go @@ -9,14 +9,12 @@ import ( "sync" "time" - "github.com/bittorrent/go-btfs/core/commands/storage/contracts" "github.com/bittorrent/go-btfs/core/commands/storage/upload/helper" "github.com/bittorrent/go-btfs/core/commands/storage/upload/sessions" renterpb "github.com/bittorrent/go-btfs/protos/renter" "github.com/tron-us/go-btfs-common/crypto" guardpb "github.com/tron-us/go-btfs-common/protos/guard" - nodepb "github.com/tron-us/go-btfs-common/protos/node" "github.com/tron-us/go-btfs-common/utils/grpc" "github.com/alecthomas/units" @@ -158,15 +156,6 @@ func waitUpload(rss *sessions.RenterSession, offlineSigning bool, fsStatus *guar // Complete if err := rss.To(sessions.RssToCompleteEvent); err != nil { return err - } else { - go func() { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - if err := contracts.SyncContracts(ctx, rss.CtxParams.N, rss.CtxParams.Req, rss.CtxParams.Env, - nodepb.ContractStat_RENTER.String()); err != nil { - log.Debug(err) - } - }() } return nil } diff --git a/core/corehttp/webui.go b/core/corehttp/webui.go index 8549930..ca4a4b1 100644 --- a/core/corehttp/webui.go +++ b/core/corehttp/webui.go @@ -1,10 +1,11 @@ package corehttp -const WebUIPath = "/btfs/QmZM3CcoWPHiu9E8ugS76a2csooKEAp5YQitgjQC849h4b" // v2.1.3 +const WebUIPath = "/btfs/QmXsvmvTTzciHEdbDCCMo55MfrEQ6qnct8B4Wt9aJwHoMY" // v2.2.0 // this is a list of all past webUI paths. var WebUIPaths = []string{ WebUIPath, + "/btfs/QmZM3CcoWPHiu9E8ugS76a2csooKEAp5YQitgjQC849h4b", // v2.1.3 "/btfs/QmW3VGCuvfhAJcJZRYQeEjJnjQG27kHNhBasrF2TwGniTT", // v2.1.2 "/btfs/QmWDZ94ZMAjts3WSPbFdLUbfLMYbygJR7BNEygVJqxuqfw", // v2.1.1 "/btfs/QmVKKZuhYriR26jAkZGwR7jEPLGARtWZZV3oS2abykwT2U", // v2.1.0 diff --git a/core/hub/sync.go b/core/hub/sync.go index f050c1c..404ca53 100644 --- a/core/hub/sync.go +++ b/core/hub/sync.go @@ -2,10 +2,12 @@ package hub import ( "context" + "encoding/json" "fmt" - version "github.com/bittorrent/go-btfs" "strings" + version "github.com/bittorrent/go-btfs" + "github.com/bittorrent/go-btfs/core" hubpb "github.com/tron-us/go-btfs-common/protos/hub" @@ -29,6 +31,10 @@ const ( // if valid, and if local is true and mode is empty, return prefix for storing such // information into local datastore. func CheckValidMode(mode string, local bool) (hubpb.HostsReq_Mode, string, error) { + if json.Valid([]byte(mode)) { + return -1, "mixture", nil + } + if mode == HubModeAll && local { return -1, "", nil } diff --git a/coverage/main/main.go b/coverage/main/main.go index be616e0..95b3186 100644 --- a/coverage/main/main.go +++ b/coverage/main/main.go @@ -40,7 +40,7 @@ func main() { p.Env = append(os.Environ(), "IPFS_COVER_RET_FILE="+retFile.Name()) p.SysProcAttr = &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, + // Pdeathsig: syscall.SIGTERM, } sig := make(chan os.Signal, 10) diff --git a/go.mod b/go.mod index 7007b7a..a274602 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect github.com/TRON-US/go-btfs-api v0.3.0 github.com/TRON-US/go-btfs-chunker v0.3.0 - github.com/TRON-US/go-btfs-config v0.11.8 + github.com/TRON-US/go-btfs-config v0.11.10 github.com/TRON-US/go-btfs-files v0.2.0 github.com/TRON-US/go-btfs-pinner v0.1.1 github.com/TRON-US/go-btns v0.1.1 @@ -125,7 +125,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 github.com/thedevsaddam/gojsonq/v2 v2.5.2 - github.com/tron-us/go-btfs-common v0.8.6 + github.com/tron-us/go-btfs-common v0.8.9 github.com/tron-us/go-common/v2 v2.3.0 github.com/tron-us/protobuf v1.3.7 github.com/tyler-smith/go-bip32 v0.0.0-20170922074101-2c9cfd177564 diff --git a/go.sum b/go.sum index 8b89c4a..6b0eef7 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/TRON-US/go-btfs-api v0.3.0/go.mod h1:surmr8ztnpbVY7y2H7dbb7npNXfdaV0U github.com/TRON-US/go-btfs-chunker v0.3.0 h1:06/rAYKtC3BQRYVxMtEKvqFFHhSB+XKcqt3JZ0CjD4o= github.com/TRON-US/go-btfs-chunker v0.3.0/go.mod h1:m0xvt42kqLskWsLF6SQ51AA9cqPzWoweydOcDgSDX/U= github.com/TRON-US/go-btfs-config v0.6.0/go.mod h1:82nKCMRhsgY0I8DCasIUpSr6ZP9iHLsZJSMUxytMpEw= -github.com/TRON-US/go-btfs-config v0.11.8 h1:eSuNp488lBv+dip35KKBHWDRO3Wnrwn7h7M/0e+r4ZE= -github.com/TRON-US/go-btfs-config v0.11.8/go.mod h1:9y6osJENDCjulSNJjSSt1J8OK+ADRatBdYPXRDewbko= +github.com/TRON-US/go-btfs-config v0.11.10 h1:VPxc6y6WRHxww8DAugLnxdwaeqDfauNjUnL/9ZRrQTU= +github.com/TRON-US/go-btfs-config v0.11.10/go.mod h1:9y6osJENDCjulSNJjSSt1J8OK+ADRatBdYPXRDewbko= github.com/TRON-US/go-btfs-files v0.1.1/go.mod h1:tD2vOKLcLCDNMn9rrA27n2VbNpHdKewGzEguIFY+EJ0= github.com/TRON-US/go-btfs-files v0.2.0 h1:JZ+F0gX8iPmUf1OlrdOdsA8GMGxCHhwQ03jEWWEgVLE= github.com/TRON-US/go-btfs-files v0.2.0/go.mod h1:Qx+rTOIC0xl3ZkosGcEoB4hqExZmTONErPys8K5suEc= @@ -1000,8 +1000,6 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/markbates/pkger v0.17.0 h1:RFfyBPufP2V6cddUyyEVSHBpaAnM1WzaMNyqomeT+iY= github.com/markbates/pkger v0.17.0/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= -github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= -github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= @@ -1376,8 +1374,8 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tron-us/go-btfs-common v0.2.11/go.mod h1:9ND33JahGMg52sCC2/gO5DakLsd1Pg2lVe2CihW7lBE= github.com/tron-us/go-btfs-common v0.3.7/go.mod h1:FbYoo6ZrtnJH3TKdyJTGQrUP2rbwNVATQpxplwaYQ/c= -github.com/tron-us/go-btfs-common v0.8.6 h1:IA1qxW0WSxAcYFJM3DG0DJIm4wptE4zueNHBQmY7dv8= -github.com/tron-us/go-btfs-common v0.8.6/go.mod h1:xnIFfbMRS5VsF948fBHPcYIeYGZkQgaJ6NIEGIPfYUs= +github.com/tron-us/go-btfs-common v0.8.9 h1:6bFJ2J5XNvrawKmA8GmpNlWNDqGMiGRa7fp8JvHTlnk= +github.com/tron-us/go-btfs-common v0.8.9/go.mod h1:xnIFfbMRS5VsF948fBHPcYIeYGZkQgaJ6NIEGIPfYUs= github.com/tron-us/go-common/v2 v2.0.5/go.mod h1:GiKX9noBLHotkZAU+7ET4h7N0DYWnm3OcGHOFJg1Q68= github.com/tron-us/go-common/v2 v2.1.9/go.mod h1:YIEJZF9Ph79g0zZWOvfNDtJhvO5OqSNPAb/TM1i+KvQ= github.com/tron-us/go-common/v2 v2.3.0 h1:bt7WYyOWG6NleHsBB1B/iR1m+mwe3JsaTv/HFbFgxYw= diff --git a/reportstatus/.DS_Store b/reportstatus/.DS_Store new file mode 100644 index 0000000..6515789 Binary files /dev/null and b/reportstatus/.DS_Store differ diff --git a/reportstatus/abi/status_abi.go b/reportstatus/abi/status_abi.go new file mode 100644 index 0000000..0bb0d71 --- /dev/null +++ b/reportstatus/abi/status_abi.go @@ -0,0 +1,532 @@ +package abi + +const StatusHeartABI = `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "lastSignAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "currentSignAddress", + "type": "address" + } + ], + "name": "signAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "peer", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "createTime", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "Nonce", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "bttcAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "signedTime", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "lastNonce", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "nowTime", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint16[30]", + "name": "hearts", + "type": "uint16[30]" + } + ], + "name": "statusReported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "currentVersion", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "version", + "type": "string" + } + ], + "name": "versionChanged", + "type": "event" + }, + { + "inputs": [], + "name": "currentVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "peer", + "type": "string" + }, + { + "internalType": "uint32", + "name": "createTime", + "type": "uint32" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint32", + "name": "Nonce", + "type": "uint32" + }, + { + "internalType": "address", + "name": "bttcAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "signedTime", + "type": "uint32" + } + ], + "name": "genHashExt", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "getHighScoreHost", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "createTime", + "type": "uint32" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint32", + "name": "lastNonce", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "lastSignedTime", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "lastSigned", + "type": "bytes" + }, + { + "internalType": "uint16[30]", + "name": "hearts", + "type": "uint16[30]" + } + ], + "internalType": "struct BtfsStatus.info[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "peer", + "type": "string" + } + ], + "name": "getStatus", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "uint16[30]", + "name": "", + "type": "uint16[30]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signAddress", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "recoverSignerExt", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "peer", + "type": "string" + }, + { + "internalType": "uint32", + "name": "createTime", + "type": "uint32" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint32", + "name": "Nonce", + "type": "uint32" + }, + { + "internalType": "address", + "name": "bttcAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "signedTime", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "signed", + "type": "bytes" + } + ], + "name": "reportStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ver", + "type": "string" + } + ], + "name": "setCurrentVersion", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "setSignAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalStat", + "outputs": [ + { + "internalType": "uint64", + "name": "total", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "totalUsers", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +]` diff --git a/reportstatus/checkreport.go b/reportstatus/checkreport.go new file mode 100644 index 0000000..47717ba --- /dev/null +++ b/reportstatus/checkreport.go @@ -0,0 +1,46 @@ +package reportstatus + +import ( + config "github.com/TRON-US/go-btfs-config" + "github.com/bittorrent/go-btfs/chain" + "github.com/bittorrent/go-btfs/core/commands" +) + +// CheckExistLastOnline sync conf and lastOnlineInfo +func CheckExistLastOnline(cfg *config.Config, configRoot string, chainId int64) error { + lastOnline, err := chain.GetLastOnline() + if err != nil { + return err + } + + // if nil, set config online status config + if lastOnline == nil { + var reportOnline bool + var reportStatusContract bool + if cfg.Experimental.StorageHostEnabled { + reportOnline = true + reportStatusContract = true + } + + var onlineServerDomain string + if chainId == 199 { + onlineServerDomain = config.DefaultServicesConfig().OnlineServerDomain + } else { + onlineServerDomain = config.DefaultServicesConfigTestnet().OnlineServerDomain + } + + err = commands.SyncConfigOnlineCfg(configRoot, onlineServerDomain, reportOnline, reportStatusContract) + if err != nil { + return err + } + } + + // if nil, set last online info + if lastOnline == nil { + err = serv.checkLastOnlineInfo(cfg.Identity.PeerID, cfg.Identity.BttcAddr) + if err != nil { + return err + } + } + return nil +} diff --git a/reportstatus/reportstatus.go b/reportstatus/reportstatus.go new file mode 100644 index 0000000..7eaa7ab --- /dev/null +++ b/reportstatus/reportstatus.go @@ -0,0 +1,293 @@ +package reportstatus + +import ( + "context" + "encoding/hex" + "fmt" + onlinePb "github.com/tron-us/go-btfs-common/protos/online" + "math/big" + "strings" + "time" + + config "github.com/TRON-US/go-btfs-config" + "github.com/bittorrent/go-btfs/chain" + "github.com/bittorrent/go-btfs/reportstatus/abi" + "github.com/bittorrent/go-btfs/transaction" + "github.com/ethereum/go-ethereum/common" + + logging "github.com/ipfs/go-log" +) + +var log = logging.Logger("report-status-contract:") + +var ( + statusABI = transaction.ParseABIUnchecked(abi.StatusHeartABI) + serv *service +) + +const ( + ReportStatusTime = 10 * time.Minute + //ReportStatusTime = 60 * time.Second // 10 * time.Minute +) + +func Init(transactionService transaction.Service, cfg *config.Config, configRoot string, statusAddress common.Address, chainId int64) error { + New(statusAddress, transactionService, cfg) + + err := CheckExistLastOnline(cfg, configRoot, chainId) + if err != nil { + return err + } + return nil +} + +func isReportStatusEnabled(cfg *config.Config) bool { + return cfg.Experimental.StorageHostEnabled || cfg.Experimental.ReportStatusContract +} + +type service struct { + statusAddress common.Address + transactionService transaction.Service +} + +type Service interface { + // ReportStatus report status heart info to statusContract + ReportStatus() (common.Hash, error) + + // CheckReportStatus check report status heart info to statusContract + CheckReportStatus() error +} + +func New(statusAddress common.Address, transactionService transaction.Service, cfg *config.Config) Service { + serv = &service{ + statusAddress: statusAddress, + transactionService: transactionService, + } + + if isReportStatusEnabled(cfg) { + go func() { + cycleCheckReport() + }() + } + return serv +} + +// ReportStatus report heart status +func (s *service) ReportStatus() (common.Hash, error) { + lastOnline, err := chain.GetLastOnline() + if err != nil { + return common.Hash{}, err + } + + if lastOnline == nil { + return common.Hash{}, nil + } + if len(lastOnline.LastSignedInfo.Peer) <= 0 { + return common.Hash{}, nil + } + + peer := lastOnline.LastSignedInfo.Peer + createTime := lastOnline.LastSignedInfo.CreatedTime + version := lastOnline.LastSignedInfo.Version + nonce := lastOnline.LastSignedInfo.Nonce + bttcAddress := common.HexToAddress(lastOnline.LastSignedInfo.BttcAddress) + signedTime := lastOnline.LastSignedInfo.SignedTime + signature, err := hex.DecodeString(strings.Replace(lastOnline.LastSignature, "0x", "", -1)) + //fmt.Printf("... ReportStatus, lastOnline = %+v \n", lastOnline) + + callData, err := statusABI.Pack("reportStatus", peer, createTime, version, nonce, bttcAddress, signedTime, signature) + if err != nil { + return common.Hash{}, err + } + + request := &transaction.TxRequest{ + To: &s.statusAddress, + Data: callData, + Value: big.NewInt(0), + Description: "Report Heart Status", + } + + txHash, err := s.transactionService.Send(context.Background(), request) + if err != nil { + return common.Hash{}, err + } + //fmt.Println("... ReportStatus, txHash, err = ", txHash, err) + + now := time.Now() + _, err = chain.SetReportStatusOK() + if err != nil { + return common.Hash{}, err + } + + stx, err := s.transactionService.WaitForReceipt(context.Background(), txHash) + if err != nil { + return common.Hash{}, err + } + gasPrice := getGasPrice(request) + gasTotal := big.NewInt(1).Mul(gasPrice, big.NewInt(int64(stx.GasUsed))) + //fmt.Println("... ReportStatus, gasPrice, stx.GasUsed, gasTotal = ", gasPrice.String(), stx.GasUsed, gasTotal.String()) + + r := &chain.LevelDbReportStatusInfo{ + Peer: peer, + BttcAddress: bttcAddress.String(), + StatusContract: s.statusAddress.String(), + Nonce: nonce, + TxHash: txHash.String(), + GasSpend: gasTotal.String(), + ReportTime: now, + } + _, err = chain.SetReportStatusListOK(r) + if err != nil { + return common.Hash{}, err + } + + // WaitForReceipt takes long time + go func() { + defer func() { + if r := recover(); r != nil { + log.Errorf("ReportHeartStatus recovered:%+v", err) + } + }() + }() + return txHash, nil +} + +func getGasPrice(request *transaction.TxRequest) *big.Int { + var gasPrice *big.Int + if request.GasPrice == nil { + gasPrice = big.NewInt(300000000000000) + } else { + gasPrice = request.GasPrice + } + return gasPrice +} + +// report heart status +func (s *service) checkLastOnlineInfo(peerId, bttcAddr string) error { + callData, err := statusABI.Pack("getStatus", peerId) + if err != nil { + return err + } + request := &transaction.TxRequest{ + To: &s.statusAddress, + Data: callData, + } + + result, err := s.transactionService.Call(context.Background(), request) + if err != nil { + return err + } + v, err := statusABI.Unpack("getStatus", result) + if err != nil { + return err + } + //fmt.Printf("...... getStatus - result v = %+v, err = %v \n", v, err) + + nonce := v[3].(uint32) + if nonce > 0 { + lastOnlineInfo := chain.LastOnlineInfo{ + LastSignedInfo: onlinePb.SignedInfo{ + Peer: v[0].(string), + CreatedTime: v[1].(uint32), + Version: v[2].(string), + Nonce: v[3].(uint32), + BttcAddress: bttcAddr, + SignedTime: v[4].(uint32), + }, + LastSignature: "0x" + hex.EncodeToString(v[5].([]byte)), + LastTime: time.Now(), + } + fmt.Printf("... init reset lastOnlineInfo = %+v \n", lastOnlineInfo) + + err = chain.StoreOnline(&lastOnlineInfo) + if err != nil { + return err + } + } + + // WaitForReceipt takes long time + go func() { + defer func() { + if r := recover(); r != nil { + log.Errorf("getStatus recovered:%+v", err) + } + }() + }() + return nil +} + +// report heart status +func (s *service) genHashExt(ctx context.Context) (common.Hash, error) { + peer := "1" + createTime := uint32(1) + version := "1" + num := uint32(3) + bttcAddress := "0x22df207EC3C8D18fEDeed87752C5a68E5b4f6FbD" + fmt.Println("...... genHashExt, param = ", peer, createTime, version, num, bttcAddress) + + callData, err := statusABI.Pack("genHashExt", peer, createTime, version, num, common.HexToAddress(bttcAddress)) + if err != nil { + return common.Hash{}, err + } + + request := &transaction.TxRequest{ + To: &s.statusAddress, + Data: callData, + } + + result, err := s.transactionService.Call(ctx, request) + fmt.Println("...... genHashExt - totalStatus, result, err = ", common.Bytes2Hex(result), err) + + if err != nil { + return common.Hash{}, err + } + + // WaitForReceipt takes long time + go func() { + defer func() { + if r := recover(); r != nil { + log.Errorf("genHashExt recovered:%+v", err) + } + }() + }() + return common.Hash{}, nil +} + +func (s *service) CheckReportStatus() error { + _, err := s.ReportStatus() + if err != nil { + log.Errorf("ReportStatus err:%+v", err) + return err + } + return nil +} + +func cycleCheckReport() { + tick := time.NewTicker(ReportStatusTime) + defer tick.Stop() + + // Force tick on immediate start + // CheckReport in the for loop + for ; true; <-tick.C { + //fmt.Println("") + //fmt.Println("... ReportStatus, CheckReportStatus ...") + + report, err := chain.GetReportStatus() + //fmt.Printf("... ReportStatus, CheckReportStatus report: %+v err:%+v \n", report, err) + if err != nil { + continue + } + + now := time.Now() + nowUnixMod := now.Unix() % 86400 + // report only 1 hour every, and must after 10 hour. + if nowUnixMod > report.ReportStatusSeconds && + nowUnixMod < report.ReportStatusSeconds+3600 && + now.Sub(report.LastReportTime) > 10*time.Hour { + + err = serv.CheckReportStatus() + if err != nil { + continue + } + } + } +} diff --git a/reportstatus/reportstatus_test.go b/reportstatus/reportstatus_test.go new file mode 100644 index 0000000..c010b04 --- /dev/null +++ b/reportstatus/reportstatus_test.go @@ -0,0 +1,27 @@ +package reportstatus + +import ( + "encoding/hex" + "fmt" + "github.com/bittorrent/go-btfs/reportstatus/abi" + "github.com/bittorrent/go-btfs/transaction" + "github.com/ethereum/go-ethereum/common" + "testing" +) + +func TestReportStatusPackInput(t *testing.T) { + peer := "1" + createTime := uint32(1) + version := "1" + num := uint32(3) + bttcAddress := common.HexToAddress("0x22df207EC3C8D18fEDeed87752C5a68E5b4f6FbD") + signature, err := hex.DecodeString("3aab4d1631635d68bb8b9035c956b7e776dc972aa36e98177643a9dd47df7d3946459102b5678d73ad905b958cbf57ce6a001b3d27ecd204e6125a2543f897dc01") // can't contain 0x ... + fmt.Println("...... ReportStatus, param = ", peer, createTime, version, num, bttcAddress, signature, err) + + statusABI := transaction.ParseABIUnchecked(abi.StatusHeartABI) + callData, err := statusABI.Pack("reportStatus", peer, createTime, version, num, bttcAddress, signature) + if err != nil { + return + } + fmt.Println("...... ReportStatus, callData, err = ", common.Bytes2Hex(callData), err) +} diff --git a/settlement/swap/bttc/bttc.go b/settlement/swap/bttc/bttc.go index 38883b5..71a611d 100644 --- a/settlement/swap/bttc/bttc.go +++ b/settlement/swap/bttc/bttc.go @@ -35,7 +35,7 @@ type service struct { erc20Service erc20.Service } -func New(trxSvc transaction.Service, erc20Svc erc20.Service) *service { +func New(trxSvc transaction.Service, erc20Svc erc20.Service) Service { return &service{ trxService: trxSvc, erc20Service: erc20Svc, diff --git a/settlement/swap/chequestore/mock/chequestore.go b/settlement/swap/chequestore/mock/chequestore.go index 2092a39..59be45b 100644 --- a/settlement/swap/chequestore/mock/chequestore.go +++ b/settlement/swap/chequestore/mock/chequestore.go @@ -2,6 +2,7 @@ package mock import ( "context" + "errors" "math/big" "github.com/bittorrent/go-btfs/settlement/swap/vault" @@ -13,6 +14,16 @@ type Service struct { receiveCheque func(ctx context.Context, cheque *vault.SignedCheque, exchangeRate *big.Int) (*big.Int, error) lastCheque func(vault common.Address) (*vault.SignedCheque, error) lastCheques func() (map[common.Address]*vault.SignedCheque, error) + + lastReceivedChequeFunc func(vault common.Address) (*vault.SignedCheque, error) + lastReceivedChequesFunc func() (map[common.Address]*vault.SignedCheque, error) + receivedChequeRecordsByPeerFunc func(vault common.Address) ([]vault.ChequeRecord, error) + receivedChequeRecordsAllFunc func() (map[common.Address][]vault.ChequeRecord, error) + receivedStatsHistoryFunc func(days int) ([]vault.DailyReceivedStats, error) + sentStatsHistoryFunc func(days int) ([]vault.DailySentStats, error) + storeSendChequeRecordFunc func(vault, beneficiary common.Address, amount *big.Int) error + sendChequeRecordsByPeerFunc func(beneficiary common.Address) ([]vault.ChequeRecord, error) + sendChequeRecordsAllFunc func() (map[common.Address][]vault.ChequeRecord, error) } func WithReceiveChequeFunc(f func(ctx context.Context, cheque *vault.SignedCheque, exchangeRate *big.Int) (*big.Int, error)) Option { @@ -33,6 +44,60 @@ func WithLastChequesFunc(f func() (map[common.Address]*vault.SignedCheque, error }) } +func WithLastReceivedChequeFunc(f func(vault common.Address) (*vault.SignedCheque, error)) Option { + return optionFunc(func(s *Service) { + s.lastReceivedChequeFunc = f + }) +} + +func WithLastReceivedChequesFunc(f func() (map[common.Address]*vault.SignedCheque, error)) Option { + return optionFunc(func(s *Service) { + s.lastReceivedChequesFunc = f + }) +} + +func WithReceivedChequeRecordsByPeerFunc(f func(vault common.Address) ([]vault.ChequeRecord, error)) Option { + return optionFunc(func(s *Service) { + s.receivedChequeRecordsByPeerFunc = f + }) +} + +func WithReceivedChequeRecordsAllFunc(f func() (map[common.Address][]vault.ChequeRecord, error)) Option { + return optionFunc(func(s *Service) { + s.receivedChequeRecordsAllFunc = f + }) +} + +func WithReceivedStatsHistoryFunc(f func(days int) ([]vault.DailyReceivedStats, error)) Option { + return optionFunc(func(s *Service) { + s.receivedStatsHistoryFunc = f + }) +} + +func WithSentStatsHistoryFunc(f func(days int) ([]vault.DailySentStats, error)) Option { + return optionFunc(func(s *Service) { + s.sentStatsHistoryFunc = f + }) +} + +func WithStoreSendChequeRecordFunc(f func(vault, beneficiary common.Address, amount *big.Int) error) Option { + return optionFunc(func(s *Service) { + s.storeSendChequeRecordFunc = f + }) +} + +func WithSendChequeRecordsByPeerFunc(f func(beneficiary common.Address) ([]vault.ChequeRecord, error)) Option { + return optionFunc(func(s *Service) { + s.sendChequeRecordsByPeerFunc = f + }) +} + +func WithSendChequeRecordsAllFunc(f func() (map[common.Address][]vault.ChequeRecord, error)) Option { + return optionFunc(func(s *Service) { + s.sendChequeRecordsAllFunc = f + }) +} + // NewChequeStore creates the mock chequeStore implementation func NewChequeStore(opts ...Option) vault.ChequeStore { mock := new(Service) @@ -43,15 +108,94 @@ func NewChequeStore(opts ...Option) vault.ChequeStore { } func (s *Service) ReceiveCheque(ctx context.Context, cheque *vault.SignedCheque, exchangeRate *big.Int) (*big.Int, error) { - return s.receiveCheque(ctx, cheque, exchangeRate) + if s.receiveCheque != nil { + return s.receiveCheque(ctx, cheque, exchangeRate) + } + return nil, errors.New("checkstoreMock.receiveCheque not implemented") } func (s *Service) LastCheque(vault common.Address) (*vault.SignedCheque, error) { - return s.lastCheque(vault) + if s.lastCheque != nil { + return s.lastCheque(vault) + } + return nil, errors.New("checkstoreMock.lastCheque not implemented") } func (s *Service) LastCheques() (map[common.Address]*vault.SignedCheque, error) { - return s.lastCheques() + if s.lastCheques != nil { + return s.lastCheques() + } + return nil, errors.New("checkstoreMock.lastCheques not implemented") +} + +// LastReceivedCheque returns the last cheque we received from a specific vault. +func (s *Service) LastReceivedCheque(vault common.Address) (*vault.SignedCheque, error) { + if s.lastReceivedChequeFunc != nil { + return s.lastReceivedChequeFunc(vault) + } + return nil, errors.New("checkstoreMock.lastReceivedChequeFunc not implemented") +} + +// LastReceivedCheques return map[vault]cheque +func (s *Service) LastReceivedCheques() (map[common.Address]*vault.SignedCheque, error) { + if s.lastReceivedChequesFunc != nil { + return s.lastReceivedChequesFunc() + } + return nil, errors.New("checkstoreMock.lastReceivedChequesFunc not implemented") +} + +// ReceivedChequeRecordsByPeer returns the records we received from a specific vault. +func (s *Service) ReceivedChequeRecordsByPeer(vault common.Address) ([]vault.ChequeRecord, error) { + if s.receivedChequeRecordsByPeerFunc != nil { + return s.receivedChequeRecordsByPeerFunc(vault) + } + return nil, errors.New("checkstoreMock.receivedChequeRecordsByPeerFunc not implemented") +} + +// ListReceivedChequeRecords returns the records we received from a specific vault. +func (s *Service) ReceivedChequeRecordsAll() (map[common.Address][]vault.ChequeRecord, error) { + if s.receivedChequeRecordsAllFunc != nil { + return s.receivedChequeRecordsAllFunc() + } + return nil, errors.New("checkstoreMock.receivedChequeRecordsAllFunc not implemented") +} + +func (s *Service) ReceivedStatsHistory(days int) ([]vault.DailyReceivedStats, error) { + if s.receivedStatsHistoryFunc != nil { + return s.receivedStatsHistoryFunc(days) + } + return nil, errors.New("checkstoreMock.receivedStatsHistoryFunc not implemented") +} + +func (s *Service) SentStatsHistory(days int) ([]vault.DailySentStats, error) { + if s.sentStatsHistoryFunc != nil { + return s.sentStatsHistoryFunc(days) + } + return nil, errors.New("checkstoreMock.sentStatsHistoryFunc not implemented") +} + +// StoreSendChequeRecord store send cheque records. +func (s *Service) StoreSendChequeRecord(vault, beneficiary common.Address, amount *big.Int) error { + if s.storeSendChequeRecordFunc != nil { + return s.storeSendChequeRecordFunc(vault, beneficiary, amount) + } + return errors.New("checkstoreMock.storeSendChequeRecordFunc not implemented") +} + +// SendChequeRecordsByPeer returns the records we send to a specific vault. +func (s *Service) SendChequeRecordsByPeer(beneficiary common.Address) ([]vault.ChequeRecord, error) { + if s.sendChequeRecordsByPeerFunc != nil { + return s.sendChequeRecordsByPeerFunc(beneficiary) + } + return nil, errors.New("checkstoreMock.sendChequeRecordsByPeerFunc not implemented") +} + +// SendChequeRecordsAll returns the records we send to a specific vault. +func (s *Service) SendChequeRecordsAll() (map[common.Address][]vault.ChequeRecord, error) { + if s.sendChequeRecordsAllFunc != nil { + return s.sendChequeRecordsAllFunc() + } + return nil, errors.New("checkstoreMock.sendChequeRecordsAllFunc not implemented") } // Option is the option passed to the mock ChequeStore service diff --git a/settlement/swap/erc20/erc20_test.go b/settlement/swap/erc20/erc20_test.go index d814b39..ba3c3e4 100644 --- a/settlement/swap/erc20/erc20_test.go +++ b/settlement/swap/erc20/erc20_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + conabi "github.com/bittorrent/go-btfs/chain/abi" "github.com/bittorrent/go-btfs/settlement/swap/erc20" "github.com/bittorrent/go-btfs/transaction" backendmock "github.com/bittorrent/go-btfs/transaction/backendmock" @@ -16,438 +17,13 @@ import ( "github.com/ethereum/go-ethereum/ethclient" ) -const Erc20ABI = `[ - { - "inputs": [ - { - "internalType": "string", - "name": "name_", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol_", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "subtractedValue", - "type": "uint256" - } - ], - "name": "decreaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "addedValue", - "type": "uint256" - } - ], - "name": "increaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ]` - -const OracleAbi = `[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_price", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "price", - "type": "uint256" - } - ], - "name": "PriceUpdate", - "type": "event" - }, - { - "inputs": [], - "name": "getPrice", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "price", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "newPrice", - "type": "uint256" - } - ], - "name": "updatePrice", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ]` - var ( - endPoint = "http://18.144.29.246:8110" + endPoint = "https://rpc.bittorrentchain.io" - SenderAdd = common.HexToAddress("0xA4E7663A031ca1f67eEa828E4795653504d38c6e") - erc20Add = common.HexToAddress("0xD26c3d45a805a5f7809E27Bd18949d559e281900") + SenderAdd = common.HexToAddress("0x44721adf10BB3a76Ce9B456f53Ce9F652be9a2e6") + erc20Add = common.HexToAddress("0x23181F21DEa5936e24163FFABa4Ea3B316B57f3C") - erc20ABI = transaction.ParseABIUnchecked(Erc20ABI) + erc20ABI = transaction.ParseABIUnchecked(conabi.Erc20ABI) defaultPrivateKey = "e484c4373db5c55a9813e4abbb74a15edd794019b8db4365a876ed538622bcf9" ) @@ -470,6 +46,69 @@ func getChainID(client *ethclient.Client) (*big.Int, error) { return chainID, nil } +func TestDeposit(t *testing.T) { + erc20Address := common.HexToAddress("0x00") + expectedTxHash := common.HexToAddress("0x01").Hash() + depositAmount := big.NewInt(200) + + erc20 := erc20.New( + backendmock.New( + backendmock.WithEstimateGasFunc(func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { + return 0, nil + }), + ), + transactionmock.New( + transactionmock.WithABISend( + &erc20ABI, + expectedTxHash, + erc20Address, + depositAmount, + "deposit", + ), + ), + erc20Address, + ) + + txHash, err := erc20.Deposit(context.Background(), depositAmount) + if err != nil { + t.Fatal(err) + } + + if expectedTxHash != txHash { + t.Fatalf("got wrong balance. wanted %d, got %d", expectedTxHash, txHash) + } +} + +func TestWithdraw(t *testing.T) { + erc20Address := common.HexToAddress("0x00") + expectedTxHash := common.HexToAddress("0x01").Hash() + withdrawAmount := big.NewInt(200) + + erc20 := erc20.New( + backendmock.New(), + transactionmock.New( + transactionmock.WithABISend( + &erc20ABI, + expectedTxHash, + erc20Address, + big.NewInt(0), + "withdraw", + withdrawAmount, + ), + ), + erc20Address, + ) + + txHash, err := erc20.Withdraw(context.Background(), withdrawAmount) + if err != nil { + t.Fatal(err) + } + + if expectedTxHash != txHash { + t.Fatalf("got wrong balance. wanted %d, got %d", expectedTxHash, txHash) + } +} + func TestBalanceOf(t *testing.T) { erc20Address := common.HexToAddress("00") account := common.HexToAddress("01") @@ -564,3 +203,75 @@ func TestTransfer(t *testing.T) { t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, returnedTxHash) } } + +func TestAllowance(t *testing.T) { + vaultAddress := common.HexToAddress("0xabcd") + issue := common.HexToAddress("01") + // value := big.NewInt(20) + txHash := common.HexToHash("0xdddd") + result := big.NewInt(1) + + erc20 := erc20.New( + backendmock.New(), + transactionmock.New( + transactionmock.WithABICall(&erc20ABI, vaultAddress, result.FillBytes(make([]byte, 32)), "allowance", issue, vaultAddress), + ), + vaultAddress, + ) + + num, err := erc20.Allowance(context.Background(), issue, vaultAddress) + if err != nil { + t.Fatal(err) + } + + if num.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, num) + } +} + +func TestApprove(t *testing.T) { + toAddress := common.HexToAddress("0xabcd") + value := big.NewInt(20) + txHash := common.HexToHash("0xdddd") + + erc20 := erc20.New( + backendmock.New(), + transactionmock.New( + transactionmock.WithABISend(&erc20ABI, txHash, toAddress, big.NewInt(0), "approve", toAddress, value), + ), + toAddress, + ) + + resultHashTx, err := erc20.Approve(context.Background(), toAddress, value) + if err != nil { + t.Fatal(err) + } + + if resultHashTx != txHash { + t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, resultHashTx) + } +} + +func TestTransferFrom(t *testing.T) { + issue := common.HexToAddress("0xabcdfg") + vaultAddress := common.HexToAddress("0xabcd") + value := big.NewInt(20) + txHash := common.HexToHash("0xdddd") + + erc20 := erc20.New( + backendmock.New(), + transactionmock.New( + transactionmock.WithABISend(&erc20ABI, txHash, vaultAddress, big.NewInt(0), "transferFrom", issue, vaultAddress, value), + ), + vaultAddress, + ) + + resultHashTx, err := erc20.TransferFrom(context.Background(), issue, vaultAddress, value) + if err != nil { + t.Fatal(err) + } + + if resultHashTx != txHash { + t.Fatalf("returned wrong transaction hash. wanted %v, got %v", txHash, resultHashTx) + } +} diff --git a/settlement/swap/mock/swap.go b/settlement/swap/mock/swap.go index aaedddb..5dc0d5b 100644 --- a/settlement/swap/mock/swap.go +++ b/settlement/swap/mock/swap.go @@ -2,12 +2,12 @@ package mock import ( "context" + "errors" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/bittorrent/go-btfs/settlement/swap" - "github.com/bittorrent/go-btfs/settlement/swap/swapprotocol" "github.com/bittorrent/go-btfs/settlement/swap/vault" ) @@ -24,8 +24,8 @@ type Service struct { receiveChequeFunc func(context.Context, string, *vault.SignedCheque, *big.Int) error payFunc func(context.Context, string, *big.Int) handshakeFunc func(string, common.Address) error - lastSentChequeFunc func(string) (*vault.SignedCheque, error) - lastSentChequesFunc func() (map[string]*vault.SignedCheque, error) + lastSendChequeFunc func(string) (*vault.SignedCheque, error) + lastSendChequesFunc func() (map[string]*vault.SignedCheque, error) lastReceivedChequeFunc func(string) (*vault.SignedCheque, error) lastReceivedChequesFunc func() (map[string]*vault.SignedCheque, error) @@ -78,15 +78,15 @@ func WithHandshakeFunc(f func(string, common.Address) error) Option { }) } -func WithLastSentChequeFunc(f func(string) (*vault.SignedCheque, error)) Option { +func WithLastSendChequeFunc(f func(string) (*vault.SignedCheque, error)) Option { return optionFunc(func(s *Service) { - s.lastSentChequeFunc = f + s.lastSendChequeFunc = f }) } -func WithLastSentChequesFunc(f func() (map[string]*vault.SignedCheque, error)) Option { +func WithLastSendChequesFunc(f func() (map[string]*vault.SignedCheque, error)) Option { return optionFunc(func(s *Service) { - s.lastSentChequesFunc = f + s.lastSendChequesFunc = f }) } @@ -125,16 +125,16 @@ func New(opts ...Option) swap.Interface { return mock } -func NewSwap(opts ...Option) swapprotocol.Swap { - mock := new(Service) - mock.settlementsSent = make(map[string]*big.Int) - mock.settlementsRecv = make(map[string]*big.Int) +// func NewSwap(opts ...Option) swapprotocol.Swap { +// mock := new(Service) +// mock.settlementsSent = make(map[string]*big.Int) +// mock.settlementsRecv = make(map[string]*big.Int) - for _, o := range opts { - o.apply(mock) - } - return mock -} +// for _, o := range opts { +// o.apply(mock) +// } +// return mock +// } // Pay is the mock Pay function of swap. func (s *Service) Pay(ctx context.Context, peer string, amount *big.Int) { @@ -157,7 +157,7 @@ func (s *Service) TotalSent(peer string) (totalSent *big.Int, err error) { if v, ok := s.settlementsSent[peer]; ok { return v, nil } - return big.NewInt(0), nil + return big.NewInt(0), errors.New("can't get TotalSent in swap mock") } // TotalReceived is the mock TotalReceived function of swap. @@ -168,7 +168,7 @@ func (s *Service) TotalReceived(peer string) (totalReceived *big.Int, err error) if v, ok := s.settlementsRecv[peer]; ok { return v, nil } - return big.NewInt(0), nil + return big.NewInt(0), errors.New("can't get TotalReceived in swap mock") } // SettlementsSent is the mock SettlementsSent function of swap. @@ -195,56 +195,62 @@ func (s *Service) Handshake(peer string, beneficiary common.Address) error { return nil } -func (s *Service) LastSentCheque(address string) (*vault.SignedCheque, error) { - if s.lastSentChequeFunc != nil { - return s.lastSentChequeFunc(address) +func (s *Service) LastSendCheque(address string) (*vault.SignedCheque, error) { + if s.lastSendChequeFunc != nil { + return s.lastSendChequeFunc(address) } - return nil, nil + return nil, errors.New("lastSendChequeFunc of swap mock don't implemented") } -func (s *Service) LastSentCheques() (map[string]*vault.SignedCheque, error) { - if s.lastSentChequesFunc != nil { - return s.lastSentChequesFunc() +func (s *Service) LastSendCheques() (map[string]*vault.SignedCheque, error) { + if s.lastSendChequesFunc != nil { + return s.lastSendChequesFunc() } - return nil, nil + return nil, errors.New("lastSendChequesFunc of swap mock don't implemented") } func (s *Service) LastReceivedCheque(address string) (*vault.SignedCheque, error) { if s.lastReceivedChequeFunc != nil { return s.lastReceivedChequeFunc(address) } - return nil, nil + return nil, errors.New("lastReceivedChequeFunc of swap mock don't implemented") } func (s *Service) LastReceivedCheques() (map[string]*vault.SignedCheque, error) { if s.lastReceivedChequesFunc != nil { return s.lastReceivedChequesFunc() } - return nil, nil + return nil, errors.New("lastReceivedChequesFunc of swap mock don't implemented") } func (s *Service) CashCheque(ctx context.Context, peer string) (common.Hash, error) { if s.cashChequeFunc != nil { return s.cashChequeFunc(ctx, peer) } - return common.Hash{}, nil + return common.Hash{}, errors.New("cashChequeFunc of swap mock don't implemented") } func (s *Service) CashoutStatus(ctx context.Context, peer string) (*vault.CashoutStatus, error) { if s.cashoutStatusFunc != nil { return s.cashoutStatusFunc(ctx, peer) } - return nil, nil + return nil, errors.New("cashoutStatusFunc of swap mock don't implemented") } func (s *Service) ReceiveCheque(ctx context.Context, peer string, cheque *vault.SignedCheque, exchangeRate *big.Int) (err error) { if s.receiveChequeFunc != nil { return s.receiveChequeFunc(ctx, peer, cheque, exchangeRate) } - - return nil + return errors.New("receiveChequeFunc of swap mock don't implemented") } +func (s *Service) HasCashoutAction(ctx context.Context, peer string) (bool, error) +func (s *Service) ReceivedChequeRecordsByPeer(peer string) ([]vault.ChequeRecord, error) +func (s *Service) ReceivedChequeRecordsAll() ([]vault.ChequeRecord, error) +func (s *Service) ReceivedChequeRecordsCount() (int, error) +func (s *Service) SendChequeRecordsByPeer(peer string) ([]vault.ChequeRecord, error) +func (s *Service) SendChequeRecordsAll() ([]vault.ChequeRecord, error) + // Option is the option passed to the mock settlement service type Option interface { apply(*Service) diff --git a/settlement/swap/swap_test.go b/settlement/swap/swap_test.go index 0b4b2f7..85d9d30 100644 --- a/settlement/swap/swap_test.go +++ b/settlement/swap/swap_test.go @@ -122,8 +122,10 @@ func (m *addressbookMock) PutVault(peer string, vault common.Address) error { } type cashoutMock struct { - cashCheque func(ctx context.Context, vault, recipient common.Address) (common.Hash, error) - cashoutStatus func(ctx context.Context, vaultAddress common.Address) (*vault.CashoutStatus, error) + cashCheque func(ctx context.Context, vault, recipient common.Address) (common.Hash, error) + cashoutStatus func(ctx context.Context, vaultAddress common.Address) (*vault.CashoutStatus, error) + cashoutResults func() ([]vault.CashOutResult, error) + hasCashoutAction func(ctx context.Context, peer common.Address) (bool, error) } func (m *cashoutMock) CashCheque(ctx context.Context, vault, recipient common.Address) (common.Hash, error) { @@ -132,11 +134,23 @@ func (m *cashoutMock) CashCheque(ctx context.Context, vault, recipient common.Ad func (m *cashoutMock) CashoutStatus(ctx context.Context, vaultAddress common.Address) (*vault.CashoutStatus, error) { return m.cashoutStatus(ctx, vaultAddress) } - +func (m *cashoutMock) CashoutResults() ([]vault.CashOutResult, error) { + return m.cashoutResults() +} +func (m *cashoutMock) HasCashoutAction(ctx context.Context, peer common.Address) (bool, error) { + return m.hasCashoutAction(ctx, peer) +} func TestReceiveCheque(t *testing.T) { store := mockstore.NewStateStore() - vaultService := mockvault.NewVault() - amount := big.NewInt(50) + vaultService := mockvault.NewVault( + mockvault.WithTotalReceivedFunc(func() (*big.Int, error) { + return big.NewInt(0), nil + }), + mockvault.WithTotalReceivedCountFunc(func() (int, error) { + return 0, nil + }), + ) + amount := big.NewInt(4) exchangeRate := big.NewInt(10) vaultAddress := common.HexToAddress("0xcd") @@ -331,6 +345,7 @@ func TestReceiveChequeWrongVault(t *testing.T) { } +//TODO: FIX ME(checks if pay case is right and workable) func TestPay(t *testing.T) { store := mockstore.NewStateStore() @@ -354,7 +369,7 @@ func TestPay(t *testing.T) { var emitCalled bool swap := swap.New( &swapProtocolMock{ - emitCheque: func(ctx context.Context, p string, a *big.Int, issueFunc swapprotocol.IssueFunc) (*big.Int, error) { + emitCheque: func(ctx context.Context, p string, a *big.Int, s string, issueFunc swapprotocol.IssueFunc) (*big.Int, error) { //if !peer.Equal(p) { if strings.Compare(peer, p) != 0 { t.Fatal("sending to wrong peer") @@ -408,7 +423,7 @@ func TestPayIssueError(t *testing.T) { swap := swap.New( &swapProtocolMock{ - emitCheque: func(c context.Context, a1 string, i *big.Int, issueFunc swapprotocol.IssueFunc) (*big.Int, error) { + emitCheque: func(c context.Context, a1 string, i *big.Int, s string, issueFunc swapprotocol.IssueFunc) (*big.Int, error) { return nil, errReject }, }, @@ -461,7 +476,21 @@ func TestPayUnknownBeneficiary(t *testing.T) { observer := newTestObserver() swapService := swap.New( - &swapProtocolMock{}, + &swapProtocolMock{ + emitCheque: func(ctx context.Context, p string, a *big.Int, s string, issueFunc swapprotocol.IssueFunc) (*big.Int, error) { + //if !peer.Equal(p) { + if strings.Compare(peer, p) != 0 { + t.Fatal("sending to wrong peer") + } + // if b != beneficiary { + // t.Fatal("issuing for wrong beneficiary") + // } + if amount.Cmp(a) != 0 { + t.Fatal("issuing with wrong amount") + } + return amount, nil + }, + }, store, mockvault.NewVault(), mockchequestore.NewChequeStore(), @@ -479,9 +508,10 @@ func TestPayUnknownBeneficiary(t *testing.T) { if strings.Compare(call.peer, peer) != 0 { t.Fatalf("observer called with wrong peer. got %v, want %v", call.peer, peer) } - if !errors.Is(call.err, swap.ErrUnknownBeneficary) { - t.Fatalf("wrong error. wanted %v, got %v", swap.ErrUnknownBeneficary, call.err) - } + // ErrUnknownBeneficary has been blocked + // if !errors.Is(call.err, swap.ErrUnknownBeneficary) { + // t.Fatalf("wrong error. wanted %v, got %v", swap.ErrUnknownBeneficary, call.err) + // } case <-time.After(time.Second): t.Fatal("expected observer to be called") diff --git a/settlement/swap/vault/cashout_test.go b/settlement/swap/vault/cashout_test.go index 62b314a..5614a44 100644 --- a/settlement/swap/vault/cashout_test.go +++ b/settlement/swap/vault/cashout_test.go @@ -42,13 +42,13 @@ func TestCashout(t *testing.T) { cashoutService := vault.NewCashoutService( store, backendmock.New( - backendmock.WithTransactionByHashFunc(func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { + backendmock.WithTransactionByHashFunc(func(_ context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { if hash != txHash { t.Fatalf("fetching wrong transaction. wanted %v, got %v", txHash, hash) } return nil, false, nil }), - backendmock.WithTransactionReceiptFunc(func(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + backendmock.WithTransactionReceiptFunc(func(_ context.Context, hash common.Hash) (*types.Receipt, error) { if hash != txHash { t.Fatalf("fetching receipt for transaction. wanted %v, got %v", txHash, hash) } @@ -80,6 +80,12 @@ func TestCashout(t *testing.T) { } return cheque, nil }), + chequestoremock.WithLastReceivedChequeFunc(func(vault common.Address) (*vault.SignedCheque, error) { + if vault != vaultAddress { + t.Fatalf("using wrong vault. wanted %v, got %v", vaultAddress, vault) + } + return cheque, nil + }), ), ) @@ -136,13 +142,13 @@ func TestCashoutBounced(t *testing.T) { cashoutService := vault.NewCashoutService( store, backendmock.New( - backendmock.WithTransactionByHashFunc(func(ctx context.Context, hash common.Hash) (*types.Transaction, bool, error) { + backendmock.WithTransactionByHashFunc(func(_ context.Context, hash common.Hash) (*types.Transaction, bool, error) { if hash != txHash { t.Fatalf("fetching wrong transaction. wanted %v, got %v", txHash, hash) } return nil, false, nil }), - backendmock.WithTransactionReceiptFunc(func(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + backendmock.WithTransactionReceiptFunc(func(_ context.Context, hash common.Hash) (*types.Receipt, error) { if hash != txHash { t.Fatalf("fetching receipt for transaction. wanted %v, got %v", txHash, hash) } @@ -178,6 +184,12 @@ func TestCashoutBounced(t *testing.T) { } return cheque, nil }), + chequestoremock.WithLastReceivedChequeFunc(func(vault common.Address) (*vault.SignedCheque, error) { + if vault != vaultAddress { + t.Fatalf("using wrong vault. wanted %v, got %v", vaultAddress, vault) + } + return cheque, nil + }), ), ) @@ -235,13 +247,13 @@ func TestCashoutStatusReverted(t *testing.T) { cashoutService := vault.NewCashoutService( store, backendmock.New( - backendmock.WithTransactionByHashFunc(func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { + backendmock.WithTransactionByHashFunc(func(_ context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { if hash != txHash { t.Fatalf("fetching wrong transaction. wanted %v, got %v", txHash, hash) } return nil, false, nil }), - backendmock.WithTransactionReceiptFunc(func(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + backendmock.WithTransactionReceiptFunc(func(_ context.Context, hash common.Hash) (*types.Receipt, error) { if hash != txHash { t.Fatalf("fetching receipt for transaction. wanted %v, got %v", txHash, hash) } @@ -261,6 +273,12 @@ func TestCashoutStatusReverted(t *testing.T) { } return cheque, nil }), + chequestoremock.WithLastReceivedChequeFunc(func(vault common.Address) (*vault.SignedCheque, error) { + if vault != vaultAddress { + t.Fatalf("using wrong vault. wanted %v, got %v", vaultAddress, vault) + } + return cheque, nil + }), ), ) @@ -307,7 +325,7 @@ func TestCashoutStatusPending(t *testing.T) { cashoutService := vault.NewCashoutService( store, backendmock.New( - backendmock.WithTransactionByHashFunc(func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { + backendmock.WithTransactionByHashFunc(func(_ context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { if hash != txHash { t.Fatalf("fetching wrong transaction. wanted %v, got %v", txHash, hash) } @@ -324,6 +342,12 @@ func TestCashoutStatusPending(t *testing.T) { } return cheque, nil }), + chequestoremock.WithLastReceivedChequeFunc(func(vault common.Address) (*vault.SignedCheque, error) { + if vault != vaultAddress { + t.Fatalf("using wrong vault. wanted %v, got %v", vaultAddress, vault) + } + return cheque, nil + }), ), ) diff --git a/settlement/swap/vault/cheque_test.go b/settlement/swap/vault/cheque_test.go index 8b5dbb7..8d2813a 100644 --- a/settlement/swap/vault/cheque_test.go +++ b/settlement/swap/vault/cheque_test.go @@ -89,7 +89,7 @@ func TestSignChequeIntegration(t *testing.T) { } // computed using ganache - expectedSignature, err := hex.DecodeString("171b63fc598ae2c7987f4a756959dadddd84ccd2071e7b5c3aa3437357be47286125edc370c344a163ba7f4183dfd3611996274a13e4b3496610fc00c0e2fc421c") + expectedSignature, err := hex.DecodeString("3305964770f9b66463d58b61e7de9bf2b784098fc715338083946aabf69c7dec0cae8345705d4bf2e556482bd27f11ceb0e5ae1eb191a907cde7aee3989a3ad51c") if err != nil { t.Fatal(err) } diff --git a/settlement/swap/vault/chequestore_test.go b/settlement/swap/vault/chequestore_test.go index 81ed672..812fced 100644 --- a/settlement/swap/vault/chequestore_test.go +++ b/settlement/swap/vault/chequestore_test.go @@ -51,10 +51,10 @@ func TestReceiveCheque(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout2.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -173,7 +173,7 @@ func TestReceiveChequeInvalidAmount(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -230,7 +230,7 @@ func TestReceiveChequeInvalidVault(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "totalbalance"), ), ), func(c *vault.SignedCheque, cid int64) (common.Address, error) { @@ -311,7 +311,7 @@ func TestReceiveChequeInsufficientBalance(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(1)).FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(1)).FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -353,7 +353,7 @@ func TestReceiveChequeSufficientBalancePaidOut(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(100)).FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, new(big.Int).Sub(cumulativePayout, big.NewInt(100)).FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -410,7 +410,7 @@ func TestReceiveChequeNotEnoughValue(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -425,8 +425,8 @@ func TestReceiveChequeNotEnoughValue(t *testing.T) { }) _, err := chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate) - if !errors.Is(err, vault.ErrChequeValueTooLow) { - t.Fatalf("got wrong error. wanted %v, got %v", vault.ErrChequeValueTooLow, err) + if err != nil { + t.Fatalf("got wrong error. wanted nil, got %v", err) } } @@ -471,7 +471,7 @@ func TestReceiveChequeNotEnoughValue2(t *testing.T) { transactionmock.New( transactionmock.WithABICallSequence( transactionmock.ABICall(&vaultABI, vaultAddress, issuer.Hash().Bytes(), "issuer"), - transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, vaultAddress, cumulativePayout.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, vaultAddress, big.NewInt(0).FillBytes(make([]byte, 32)), "paidOut", beneficiary), ), ), @@ -486,7 +486,7 @@ func TestReceiveChequeNotEnoughValue2(t *testing.T) { }) _, err := chequestore.ReceiveCheque(context.Background(), cheque, exchangeRate) - if !errors.Is(err, vault.ErrChequeValueTooLow) { - t.Fatalf("got wrong error. wanted %v, got %v", vault.ErrChequeValueTooLow, err) + if err != nil { + t.Fatalf("got wrong error. wanted nil, got %v", err) } } diff --git a/settlement/swap/vault/common_test.go b/settlement/swap/vault/common_test.go index f0e5fcc..b07a110 100644 --- a/settlement/swap/vault/common_test.go +++ b/settlement/swap/vault/common_test.go @@ -2,10 +2,10 @@ package vault_test import ( "context" - "math/big" "github.com/bittorrent/go-btfs/settlement/swap/vault" "github.com/ethereum/go-ethereum/common" + "github.com/libp2p/go-libp2p-core/peer" ) type chequeSignerMock struct { @@ -17,11 +17,14 @@ func (m *chequeSignerMock) Sign(cheque *vault.Cheque) ([]byte, error) { } type factoryMock struct { - erc20Address func(ctx context.Context) (common.Address, error) - deploy func(ctx context.Context, issuer common.Address, defaultHardDepositTimeoutDuration *big.Int, nonce common.Hash) (common.Hash, error) - waitDeployed func(ctx context.Context, txHash common.Hash) (common.Address, error) - verifyBytecode func(ctx context.Context) error - verifyVault func(ctx context.Context, vault common.Address) error + erc20Address func(ctx context.Context) (common.Address, error) + deploy func(ctx context.Context, issuer common.Address, vaultLogic common.Address, peerId string, tokenAddress common.Address) (vault common.Address, trx common.Hash, err error) + waitDeployed func(ctx context.Context, txHash common.Hash) (common.Address, error) + verifyBytecode func(ctx context.Context) error + verifyVault func(ctx context.Context, vault common.Address) error + getPeerVault func(ctx context.Context, peerID peer.ID) (vault common.Address, err error) + getPeerVaultWithCache func(ctx context.Context, peerID peer.ID) (vault common.Address, err error) + isVaultCompatibleBetween func(ctx context.Context, peerID1, peerID2 peer.ID) (isCompatible bool, err error) } // ERC20Address returns the token for which this factory deploys vaults. @@ -29,8 +32,8 @@ func (m *factoryMock) ERC20Address(ctx context.Context) (common.Address, error) return m.erc20Address(ctx) } -func (m *factoryMock) Deploy(ctx context.Context, issuer common.Address, defaultHardDepositTimeoutDuration *big.Int, nonce common.Hash) (common.Hash, error) { - return m.deploy(ctx, issuer, defaultHardDepositTimeoutDuration, nonce) +func (m *factoryMock) Deploy(ctx context.Context, issuer common.Address, vaultLogic common.Address, peerId string, tokenAddress common.Address) (vault common.Address, trx common.Hash, err error) { + return m.deploy(ctx, issuer, vaultLogic, peerId, tokenAddress) } func (m *factoryMock) WaitDeployed(ctx context.Context, txHash common.Hash) (common.Address, error) { @@ -46,3 +49,15 @@ func (m *factoryMock) VerifyBytecode(ctx context.Context) error { func (m *factoryMock) VerifyVault(ctx context.Context, vault common.Address) error { return m.verifyVault(ctx, vault) } + +func (m *factoryMock) GetPeerVault(ctx context.Context, peerID peer.ID) (vault common.Address, err error) { + return m.getPeerVault(ctx, peerID) +} + +func (m *factoryMock) GetPeerVaultWithCache(ctx context.Context, peerID peer.ID) (vault common.Address, err error) { + return m.getPeerVaultWithCache(ctx, peerID) +} + +func (m *factoryMock) IsVaultCompatibleBetween(ctx context.Context, peerID1, peerID2 peer.ID) (isCompatible bool, err error) { + return m.isVaultCompatibleBetween(ctx, peerID1, peerID2) +} diff --git a/settlement/swap/vault/factory_test.go b/settlement/swap/vault/factory_test.go index 90d3754..652eb87 100644 --- a/settlement/swap/vault/factory_test.go +++ b/settlement/swap/vault/factory_test.go @@ -31,7 +31,7 @@ func TestFactoryERC20Address(t *testing.T) { &factoryABI, factoryAddress, erc20Address.Hash().Bytes(), - "ERC20Address", + "TokenAddress", ), ), factoryAddress, @@ -81,10 +81,10 @@ func TestFactoryVerifySelf(t *testing.T) { } }) - t.Run("invalid deploy factory", func(t *testing.T) { + t.Run("invalid factory contract", func(t *testing.T) { factory := vault.NewFactory( backendWithCodeAt(map[common.Address]string{ - factoryAddress: "abcd", + factoryAddress: "0xabcd", }), transactionmock.New(), factoryAddress, @@ -99,24 +99,6 @@ func TestFactoryVerifySelf(t *testing.T) { t.Fatalf("wrong error. wanted %v, got %v", vault.ErrInvalidFactory, err) } }) - - t.Run("invalid legacy factories", func(t *testing.T) { - factory := vault.NewFactory( - backendWithCodeAt(map[common.Address]string{ - factoryAddress: conabi.FactoryDeployedBin, - }), - transactionmock.New(), - factoryAddress, - ) - - err := factory.VerifyBytecode(context.Background()) - if err == nil { - t.Fatal("verified invalid factory") - } - if !errors.Is(err, vault.ErrInvalidFactory) { - t.Fatalf("wrong error. wanted %v, got %v", vault.ErrInvalidFactory, err) - } - }) } func TestFactoryVerifyVault(t *testing.T) { @@ -151,7 +133,7 @@ func TestFactoryVerifyVault(t *testing.T) { transactionmock.ABICall( &factoryABI, factoryAddress, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), "deployedContracts", vaultAddress, ), @@ -193,63 +175,71 @@ func TestFactoryVerifyVault(t *testing.T) { }) } -func TestFactoryDeploy(t *testing.T) { - factoryAddress := common.HexToAddress("0xabcd") - issuerAddress := common.HexToAddress("0xefff") - peerId := common.HexToAddress("0xabcd") - deployTransactionHash := common.HexToHash("0xffff") - deployAddress := common.HexToAddress("0xdddd") - nonce := common.HexToHash("eeff") +//TODO: FIX ME +// func TestFactoryDeploy(t *testing.T) { +// factoryAddress := common.HexToAddress("0xabcd") +// issuerAddress := common.HexToAddress("0xefff") +// peerId := "16Uiu2HAmCvWwf33iyNWQ2t9kML7BJGHcpdFZSSqYbyvFBsDhXN9Q" +// deployTransactionHash := common.HexToHash("0xffff") +// deployAddress := common.HexToAddress("0xdddd") +// nonce := common.HexToHash("eeff") - factory := vault.NewFactory( - backendmock.New(), - transactionmock.New( - transactionmock.WithABISend(&factoryABI, deployTransactionHash, factoryAddress, big.NewInt(0), "deploySimpleSwap", issuerAddress, defaultTimeout, nonce), - transactionmock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) { - if txHash != deployTransactionHash { - t.Fatalf("waiting for wrong transaction. wanted %x, got %x", deployTransactionHash, txHash) - } - logData, err := simpleSwapDeployedEvent.Inputs.NonIndexed().Pack(deployAddress) - if err != nil { - t.Fatal(err) - } - return &types.Receipt{ - Status: 1, - Logs: []*types.Log{ - { - Data: logData, - }, - { - Address: factoryAddress, - Topics: []common.Hash{simpleSwapDeployedEvent.ID}, - Data: logData, - }, - }, - }, nil - }, - )), - factoryAddress, - //nil, - ) +// factory := vault.NewFactory( +// backendmock.New(), +// transactionmock.New( +// transactionmock.WithABICall( +// &factoryABI, +// factoryAddress, +// deployAddress.Hash().Bytes(), +// "deployedContracts", +// deployAddress, +// ), +// transactionmock.WithABISend(&factoryABI, deployTransactionHash, factoryAddress, big.NewInt(0), "deploySimpleSwap", issuerAddress, nonce), +// transactionmock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) { +// if txHash != deployTransactionHash { +// t.Fatalf("waiting for wrong transaction. wanted %x, got %x", deployTransactionHash, txHash) +// } +// logData, err := simpleSwapDeployedEvent.Inputs.NonIndexed().Pack(deployAddress) +// if err != nil { +// t.Fatal(err) +// } +// return &types.Receipt{ +// Status: 1, +// Logs: []*types.Log{ +// { +// Data: logData, +// }, +// { +// Address: factoryAddress, +// Topics: []common.Hash{simpleSwapDeployedEvent.ID}, +// Data: logData, +// }, +// }, +// }, nil +// }, +// )), +// factoryAddress, +// //nil, +// ) - txHash, err := factory.Deploy(context.Background(), issuerAddress, nonce, peerId) - if err != nil { - t.Fatal(err) - } +// vaultAddress, txHash, err := factory.Deploy(context.Background(), issuerAddress, deployAddress, peerId, deployAddress) +// if err != nil { +// t.Fatal(err) +// } - if txHash != deployTransactionHash { - t.Fatalf("returning wrong transaction hash. wanted %x, got %x", deployTransactionHash, txHash) - } +// if txHash != deployTransactionHash { +// t.Fatalf("returning wrong transaction hash. wanted %x, got %x", deployTransactionHash, txHash) +// } - vaultAddress, err := factory.WaitDeployed(context.Background(), txHash) - if err != nil { - t.Fatal(err) - } +// vaultAddress, err = factory.WaitDeployed(context.Background(), txHash) +// if err != nil { +// t.Fatal(err) +// } - if vaultAddress != deployAddress { - t.Fatalf("returning wrong address. wanted %x, got %x", deployAddress, vaultAddress) - } -} +// if vaultAddress != deployAddress { +// t.Fatalf("returning wrong address. wanted %x, got %x", deployAddress, vaultAddress) +// } +// } func TestFactoryDeployReverted(t *testing.T) { factoryAddress := common.HexToAddress("0xabcd") diff --git a/settlement/swap/vault/mock/vault.go b/settlement/swap/vault/mock/vault.go index 08a08e0..7ef7b87 100644 --- a/settlement/swap/vault/mock/vault.go +++ b/settlement/swap/vault/mock/vault.go @@ -11,6 +11,20 @@ import ( // Service is the mock vault service. type Service struct { + checkBalanceFunc func(bal *big.Int) (err error) + getWithdrawTimeFunc func(ctx context.Context) (ti *big.Int, err error) + liquidBalanceFunc func(ctx context.Context) (ti *big.Int, err error) + totalBalanceFunc func(ctx context.Context) (ti *big.Int, err error) + totalIssuedCountFunc func() (ti int, err error) + totalPaidOutFunc func(ctx context.Context) (ti *big.Int, err error) + wbttBalanceFunc func(ctx context.Context, add common.Address) (bal *big.Int, err error) + waitForDepositFunc func(ctx context.Context, txHash common.Hash) error + totalIssuedFunc func() (*big.Int, error) + totalReceivedCashedCountFunc func() (int, error) + totalReceivedCashedFunc func() (*big.Int, error) + totalDailyReceivedFunc func() (*big.Int, error) + totalDailyReceivedCashedFunc func() (*big.Int, error) + vaultBalanceFunc func(context.Context) (*big.Int, error) vaultAvailableBalanceFunc func(context.Context) (*big.Int, error) vaultAddressFunc func() common.Address @@ -20,6 +34,8 @@ type Service struct { lastChequeFunc func(common.Address) (*vault.SignedCheque, error) lastChequesFunc func() (map[common.Address]*vault.SignedCheque, error) bttBalanceFunc func(context.Context) (*big.Int, error) + totalReceivedFunc func() (*big.Int, error) + totalReceivedCountFunc func() (int, error) } // WithVault*Functions set the mock vault functions @@ -71,6 +87,96 @@ func WithLastChequesFunc(f func() (map[common.Address]*vault.SignedCheque, error }) } +func WithTotalReceivedFunc(f func() (*big.Int, error)) Option { + return optionFunc(func(s *Service) { + s.totalReceivedFunc = f + }) +} + +func WithTotalReceivedCountFunc(f func() (int, error)) Option { + return optionFunc(func(s *Service) { + s.totalReceivedCountFunc = f + }) +} + +func WithCheckBalanceFunc(f func(bal *big.Int) (err error)) Option { + return optionFunc(func(s *Service) { + s.checkBalanceFunc = f + }) +} + +func WithGetWithdrawTimeFunc(f func(ctx context.Context) (ti *big.Int, err error)) Option { + return optionFunc(func(s *Service) { + s.getWithdrawTimeFunc = f + }) +} + +func WithLiquidBalanceFunc(f func(ctx context.Context) (ti *big.Int, err error)) Option { + return optionFunc(func(s *Service) { + s.liquidBalanceFunc = f + }) +} + +func WithTotalBalanceFunc(f func(ctx context.Context) (ti *big.Int, err error)) Option { + return optionFunc(func(s *Service) { + s.totalBalanceFunc = f + }) +} + +func WithTotalIssuedCountFunc(f func() (int, error)) Option { + return optionFunc(func(s *Service) { + s.totalIssuedCountFunc = f + }) +} + +func WithTotalPaidOutFunc(f func(ctx context.Context) (ti *big.Int, err error)) Option { + return optionFunc(func(s *Service) { + s.totalPaidOutFunc = f + }) +} + +func WithWbttBalanceFunc(f func(ctx context.Context, add common.Address) (bal *big.Int, err error)) Option { + return optionFunc(func(s *Service) { + s.wbttBalanceFunc = f + }) +} + +func WithWaitForDepositFunc(f func(ctx context.Context, txHash common.Hash) error) Option { + return optionFunc(func(s *Service) { + s.waitForDepositFunc = f + }) +} + +func WithTotalIssuedFunc(f func() (*big.Int, error)) Option { + return optionFunc(func(s *Service) { + s.totalIssuedFunc = f + }) +} + +func WithTotalReceivedCashedCountFunc(f func() (int, error)) Option { + return optionFunc(func(s *Service) { + s.totalReceivedCashedCountFunc = f + }) +} + +func WithTotalReceivedCashedFunc(f func() (*big.Int, error)) Option { + return optionFunc(func(s *Service) { + s.totalReceivedCashedFunc = f + }) +} + +func WithTotalDailyReceivedFunc(f func() (*big.Int, error)) Option { + return optionFunc(func(s *Service) { + s.totalDailyReceivedFunc = f + }) +} + +func WithTotalDailyReceivedCashedFunc(f func() (*big.Int, error)) Option { + return optionFunc(func(s *Service) { + s.totalDailyReceivedCashedFunc = f + }) +} + // NewVault creates the mock vault implementation func NewVault(opts ...Option) vault.Service { mock := new(Service) @@ -85,52 +191,70 @@ func (s *Service) Balance(ctx context.Context) (bal *big.Int, err error) { if s.vaultBalanceFunc != nil { return s.vaultBalanceFunc(ctx) } - return big.NewInt(0), errors.New("Error") + return nil, errors.New("vaultMock.vaultBalanceFunc not implemented") } func (s *Service) BTTBalanceOf(ctx context.Context, add common.Address, block *big.Int) (bal *big.Int, err error) { if s.bttBalanceFunc != nil { return s.bttBalanceFunc(ctx) } - return big.NewInt(0), errors.New("Error") + return nil, errors.New("vaultMock.bttBalanceFunc not implemented") } func (s *Service) CheckBalance(bal *big.Int) (err error) { - return nil + if s.checkBalanceFunc != nil { + return s.checkBalanceFunc(bal) + } + return errors.New("vaultMock.checkBalanceFunc not implemented") } func (s *Service) GetWithdrawTime(ctx context.Context) (ti *big.Int, err error) { - return big.NewInt(0), errors.New("Error") + if s.getWithdrawTimeFunc != nil { + return s.getWithdrawTimeFunc(ctx) + } + return nil, errors.New("vaultMock.getWithdrawTimeFunc not implemented") } func (s *Service) LiquidBalance(ctx context.Context) (ti *big.Int, err error) { - return big.NewInt(0), errors.New("Error") + if s.liquidBalanceFunc != nil { + return s.liquidBalanceFunc(ctx) + } + return nil, errors.New("vaultMock.liquidBalanceFunc not implemented") } func (s *Service) TotalBalance(ctx context.Context) (ti *big.Int, err error) { - return big.NewInt(0), errors.New("Error") + if s.totalBalanceFunc != nil { + return s.totalBalanceFunc(ctx) + } + return nil, errors.New("vaultMock.totalBalanceFunc not implemented") } func (s *Service) TotalIssuedCount() (ti int, err error) { - return 0, errors.New("Error") + if s.totalIssuedCountFunc != nil { + return s.totalIssuedCountFunc() + } + return 0, errors.New("vaultMock.totalIssuedCountFunc not implemented") } func (s *Service) TotalPaidOut(ctx context.Context) (ti *big.Int, err error) { - return big.NewInt(0), errors.New("Error") + if s.totalPaidOutFunc != nil { + return s.totalPaidOutFunc(ctx) + } + return nil, errors.New("vaultMock.totalPaidOutFunc not implemented") } func (s *Service) WBTTBalanceOf(ctx context.Context, add common.Address) (bal *big.Int, err error) { - if s.bttBalanceFunc != nil { - return s.bttBalanceFunc(ctx) + if s.wbttBalanceFunc != nil { + return s.wbttBalanceFunc(ctx, add) } - return big.NewInt(0), errors.New("Error") + return nil, errors.New("vaultMock.wbttBalanceFunc not implemented") } func (s *Service) AvailableBalance(ctx context.Context) (bal *big.Int, err error) { if s.vaultAvailableBalanceFunc != nil { return s.vaultAvailableBalanceFunc(ctx) } - return big.NewInt(0), errors.New("Error") + return nil, errors.New("vaultMock.vaultAvailableBalanceFunc not implemented") } // Deposit mocks the vault .Deposit function @@ -138,12 +262,14 @@ func (s *Service) Deposit(ctx context.Context, amount *big.Int) (hash common.Has if s.vaultDepositFunc != nil { return s.vaultDepositFunc(ctx, amount) } - return common.Hash{}, errors.New("Error") + return common.Hash{}, errors.New("vaultMock.vaultDepositFunc not implemented") } -// WaitForDeposit mocks the vault .WaitForDeposit function func (s *Service) WaitForDeposit(ctx context.Context, txHash common.Hash) error { - return errors.New("Error") + if s.waitForDepositFunc != nil { + return s.waitForDepositFunc(ctx, txHash) + } + return errors.New("vaultMock.waitForDepositFunc not implemented") } // Address mocks the vault .Address function @@ -158,25 +284,80 @@ func (s *Service) Issue(ctx context.Context, beneficiary common.Address, amount if s.vaultIssueFunc != nil { return s.vaultIssueFunc(ctx, beneficiary, amount, sendChequeFunc) } - return big.NewInt(0), nil + return nil, errors.New("vaultMock.vaultIssueFunc not implemented") } func (s *Service) LastCheque(beneficiary common.Address) (*vault.SignedCheque, error) { if s.lastChequeFunc != nil { return s.lastChequeFunc(beneficiary) } - return nil, errors.New("Error") + return nil, errors.New("vaultMock.lastChequeFunc not implemented") } func (s *Service) LastCheques() (map[common.Address]*vault.SignedCheque, error) { if s.lastChequesFunc != nil { return s.lastChequesFunc() } - return nil, errors.New("Error") + return nil, errors.New("vaultMock.lastChequesFunc not implemented") } func (s *Service) Withdraw(ctx context.Context, amount *big.Int) (hash common.Hash, err error) { - return s.vaultWithdrawFunc(ctx, amount) + if s.vaultWithdrawFunc != nil { + return s.vaultWithdrawFunc(ctx, amount) + } + return common.Hash{}, errors.New("vaultMock.vaultWithdrawFunc not implemented") +} + +func (s *Service) TotalIssued() (*big.Int, error) { + if s.totalIssuedFunc != nil { + return s.totalIssuedFunc() + } + return nil, errors.New("vaultMock.totalIssuedFunc not implemented") +} + +func (s *Service) TotalReceived() (*big.Int, error) { + if s.totalReceivedFunc != nil { + return s.totalReceivedFunc() + } + return nil, errors.New("vaultMock.totalReceivedFunc not implemented") +} + +func (s *Service) TotalReceivedCount() (int, error) { + if s.totalReceivedCountFunc != nil { + return s.totalReceivedCountFunc() + } + return 0, errors.New("vaultMock.totalReceivedCountFunc not implemented") +} + +func (s *Service) TotalReceivedCashedCount() (int, error) { + if s.totalReceivedCashedCountFunc != nil { + return s.totalReceivedCashedCountFunc() + } + return 0, errors.New("vaultMock.totalReceivedCashedCountFunc not implemented") +} + +func (s *Service) TotalReceivedCashed() (*big.Int, error) { + if s.totalReceivedCashedFunc != nil { + return s.totalReceivedCashedFunc() + } + return nil, errors.New("vaultMock.totalReceivedCashedFunc not implemented") +} + +func (s *Service) TotalDailyReceived() (*big.Int, error) { + if s.totalDailyReceivedFunc != nil { + return s.totalDailyReceivedFunc() + } + return nil, errors.New("vaultMock.totalDailyReceivedFunc not implemented") +} +func (s *Service) TotalDailyReceivedCashed() (*big.Int, error) { + if s.totalDailyReceivedCashedFunc != nil { + return s.totalDailyReceivedCashedFunc() + } + return nil, errors.New("vaultMock.totalDailyReceivedCashedFunc not implemented") +} + +func (s *Service) UpgradeTo(ctx context.Context, newVaultImpl common.Address) (old, new common.Address, err error) { + return common.Address{}, common.Address{}, errors.New("vaultMock.UpgradeTo not implemented") } // Option is the option passed to the mock Vault service diff --git a/settlement/swap/vault/vault_test.go b/settlement/swap/vault/vault_test.go index 9578ed2..d4ada48 100644 --- a/settlement/swap/vault/vault_test.go +++ b/settlement/swap/vault/vault_test.go @@ -7,6 +7,7 @@ import ( "math/big" "testing" + mockchequestore "github.com/bittorrent/go-btfs/settlement/swap/chequestore/mock" erc20mock "github.com/bittorrent/go-btfs/settlement/swap/erc20/mock" "github.com/bittorrent/go-btfs/settlement/swap/vault" storemock "github.com/bittorrent/go-btfs/statestore/mock" @@ -72,8 +73,16 @@ func TestVaultDeposit(t *testing.T) { balance := big.NewInt(30) depositAmount := big.NewInt(20) txHash := common.HexToHash("0xdddd") + + factoryAddress := common.HexToAddress("0xabcd") + // issuerAddress := common.HexToAddress("0xefff") + // deployTransactionHash := common.HexToHash("0xffff") + // nonce := common.HexToHash("eeff") + vaultService, err := vault.New( - transactionmock.New(), + transactionmock.New( + transactionmock.WithABISend(&vaultABI, txHash, factoryAddress, big.NewInt(0), "deposit", depositAmount), + ), address, ownerAdress, nil, @@ -205,7 +214,11 @@ func TestVaultIssue(t *testing.T) { store, chequeSigner, erc20mock.New(), - nil, + mockchequestore.NewChequeStore( + mockchequestore.WithStoreSendChequeRecordFunc(func(vault, beneficiary common.Address, amount *big.Int) error { + return nil + }), + ), ) if err != nil { t.Fatal(err) @@ -380,7 +393,7 @@ func TestVaultIssueOutOfFunds(t *testing.T) { vaultService, err := vault.New( transactionmock.New( transactionmock.WithABICallSequence( - transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), ), ), @@ -420,7 +433,7 @@ func TestVaultWithdraw(t *testing.T) { vaultService, err := vault.New( transactionmock.New( transactionmock.WithABICallSequence( - transactionmock.ABICall(&vaultABI, address, balance.FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, address, balance.FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), ), transactionmock.WithABISend(&vaultABI, txHash, address, big.NewInt(0), "withdraw", withdrawAmount), @@ -456,7 +469,7 @@ func TestVaultWithdrawInsufficientFunds(t *testing.T) { transactionmock.New( transactionmock.WithABISend(&vaultABI, txHash, address, big.NewInt(0), "withdraw", withdrawAmount), transactionmock.WithABICallSequence( - transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "balance"), + transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalbalance"), transactionmock.ABICall(&vaultABI, address, big.NewInt(0).FillBytes(make([]byte, 32)), "totalPaidOut"), ), ), @@ -490,7 +503,7 @@ func TestStateStoreKeys(t *testing.T) { t.Fatalf("wrong last issued cheque key. wanted %s, got %s", expected, vault.LastIssuedChequeKey(address)) } - expected = "swap_vault_last_received_cheque__000000000000000000000000000000000000abcd" + expected = "swap_vault_last_received_cheque_000000000000000000000000000000000000abcd" if vault.LastReceivedChequeKey(address) != expected { t.Fatalf("wrong last received cheque key. wanted %s, got %s", expected, vault.LastReceivedChequeKey(address)) } diff --git a/spin/analytics.go b/spin/analytics.go index eafd5cc..814172e 100644 --- a/spin/analytics.go +++ b/spin/analytics.go @@ -43,6 +43,8 @@ const ( // HeartBeat is how often we send data to server, at the moment set to 60 Minutes heartBeat = 60 * time.Minute + heartBeatOnline = 60 * time.Minute + // Expotentially delayed retries will be capped at this total time maxRetryTotal = 10 * time.Minute @@ -130,6 +132,7 @@ func Analytics(api iface.CoreAPI, cfgRoot string, node *core.IpfsNode, BTFSVersi dc.setRoles() go dc.collectionAgent(node) + go dc.collectionAgentOnline(node) } func (dc *dcWrap) setRoles() { diff --git a/spin/analytics_online.go b/spin/analytics_online.go new file mode 100644 index 0000000..494be87 --- /dev/null +++ b/spin/analytics_online.go @@ -0,0 +1,182 @@ +package spin + +import ( + "context" + "fmt" + "strings" + "time" + + config "github.com/TRON-US/go-btfs-config" + "github.com/bittorrent/go-btfs/chain" + "github.com/bittorrent/go-btfs/core" + onlinePb "github.com/tron-us/go-btfs-common/protos/online" + cgrpc "github.com/tron-us/go-btfs-common/utils/grpc" + + "github.com/cenkalti/backoff/v4" + "github.com/gogo/protobuf/proto" + ic "github.com/libp2p/go-libp2p-crypto" +) + +func isReportOnlineEnabled(cfg *config.Config) bool { + return cfg.Experimental.StorageHostEnabled || cfg.Experimental.ReportOnline +} + +func (dc *dcWrap) doSendDataOnline(ctx context.Context, config *config.Config, sm *onlinePb.ReqSignMetrics) error { + cb := cgrpc.OnlineClient(config.Services.OnlineServerDomain) + return cb.WithContext(ctx, func(ctx context.Context, client onlinePb.OnlineServiceClient) error { + resp, err := client.UpdateSignMetrics(ctx, sm) + if err != nil { + chain.CodeStatus = chain.ConstCodeError + chain.ErrStatus = err + return err + } else { + chain.CodeStatus = chain.ConstCodeSuccess + chain.ErrStatus = nil + } + + //fmt.Printf("--- online, resp, SignedInfo = %+v, signature = %+v \n", resp.SignedInfo, resp.Signature) + if (resp.SignedInfo != nil) && len(resp.SignedInfo.Peer) > 0 { + onlineInfo := chain.LastOnlineInfo{ + LastSignedInfo: onlinePb.SignedInfo{ + Peer: resp.SignedInfo.Peer, + CreatedTime: resp.SignedInfo.CreatedTime, + Version: resp.SignedInfo.Version, + Nonce: resp.SignedInfo.Nonce, + BttcAddress: resp.SignedInfo.BttcAddress, + SignedTime: resp.SignedInfo.SignedTime, + }, + LastSignature: resp.Signature, + LastTime: time.Now(), + } + chain.StoreOnline(&onlineInfo) + } + + return err + }) +} + +func (dc *dcWrap) sendDataOnline(node *core.IpfsNode, config *config.Config) { + sm, errs, err := dc.doPrepDataOnline(node) + if errs == nil { + errs = make([]error, 0) + } + var sb strings.Builder + if err != nil { + errs = append(errs, err) + } + for _, err := range errs { + sb.WriteString(err.Error()) + sb.WriteRune('\n') + } + log.Debug(sb.String()) + // If complete prep failure we return + if err != nil { + return + } + + bo := backoff.NewExponentialBackOff() + bo.MaxElapsedTime = maxRetryTotal + backoff.Retry(func() error { + err := dc.doSendDataOnline(node.Context(), config, sm) + if err != nil { + //fmt.Printf("--- online, doSendDataOnline error = %+v \n", err) + log.Infof("failed: doSendDataOnline to online server: %+v ", err) + } else { + log.Debug("sent doSendDataOnline to online server") + } + return err + }, bo) +} + +// doPrepData gathers the latest analytics and returns (signed object, list of reporting errors, failure) +func (dc *dcWrap) doPrepDataOnline(btfsNode *core.IpfsNode) (*onlinePb.ReqSignMetrics, []error, error) { + errs := dc.update(btfsNode) + payload, err := dc.getPayloadOnline(btfsNode) + if err != nil { + return nil, errs, fmt.Errorf("failed to marshal dataCollection object to a byte array: %s", err.Error()) + } + if dc.node.PrivateKey == nil { + return nil, errs, fmt.Errorf("node's private key is null") + } + + signature, err := dc.node.PrivateKey.Sign(payload) + if err != nil { + return nil, errs, fmt.Errorf("failed to sign raw data with node private key: %s", err.Error()) + } + + publicKey, err := ic.MarshalPublicKey(dc.node.PrivateKey.GetPublic()) + if err != nil { + return nil, errs, fmt.Errorf("failed to marshal node public key: %s", err.Error()) + } + + sm := new(onlinePb.ReqSignMetrics) + sm.Payload = payload + sm.Signature = signature + sm.PublicKey = publicKey + return sm, errs, nil +} + +func (dc *dcWrap) getPayloadOnline(btfsNode *core.IpfsNode) ([]byte, error) { + var lastSignedInfo *onlinePb.SignedInfo + var lastSignature string + var lastTime time.Time + + lastOnline, err := chain.GetLastOnline() + if err != nil { + return nil, err + } + + if lastOnline == nil { + lastSignedInfo = nil + lastSignature = "" + } else { + lastSignedInfo = &onlinePb.SignedInfo{ + Peer: lastOnline.LastSignedInfo.Peer, + CreatedTime: lastOnline.LastSignedInfo.CreatedTime, + Version: lastOnline.LastSignedInfo.Version, + Nonce: lastOnline.LastSignedInfo.Nonce, + BttcAddress: lastOnline.LastSignedInfo.BttcAddress, + SignedTime: lastOnline.LastSignedInfo.SignedTime, + } + lastSignature = lastOnline.LastSignature + lastTime = lastOnline.LastTime + } + + pn := &onlinePb.PayLoadInfo{ + NodeId: btfsNode.Identity.Pretty(), + Node: dc.pn, + LastSignedInfo: lastSignedInfo, + LastSignature: lastSignature, + LastTime: lastTime, + } + bytes, err := proto.Marshal(pn) + if err != nil { + return nil, err + } + + //fmt.Printf("--- online, req, LastSignedInfo:%+v, LastSignature:%+v, pn.LastTime:%+v \n", pn.LastSignedInfo, pn.LastSignature, pn.LastTime) + + return bytes, nil +} + +func (dc *dcWrap) collectionAgentOnline(node *core.IpfsNode) { + tick := time.NewTicker(heartBeatOnline) + //tick := time.NewTicker(10 * time.Second) + defer tick.Stop() + + // Force tick on immediate start + // make the configuration available in the for loop + for ; true; <-tick.C { + cfg, err := dc.node.Repo.Config() + if err != nil { + continue + } + + if isReportOnlineEnabled(cfg) { + //fmt.Println("") + //fmt.Println("--- online agent ---") + + dc.sendDataOnline(node, cfg) + } + } +} diff --git a/spin/hosts.go b/spin/hosts.go index 74215c1..0e2fad3 100644 --- a/spin/hosts.go +++ b/spin/hosts.go @@ -33,7 +33,7 @@ func Hosts(node *core.IpfsNode, env cmds.Environment) { fmt.Printf("Storage host info will be synced at [%s] mode\n", m) go periodicSync(hostSyncPeriod, hostSyncTimeout+hostSortTimeout, "hosts", func(ctx context.Context) error { - _, err := hosts.SyncHosts(ctx, node, m) + _, err := hosts.SyncHostsMixture(ctx, node, m) return err }) } diff --git a/test_pkgs.txt b/test_pkgs.txt index 313bc0d..33b406a 100644 --- a/test_pkgs.txt +++ b/test_pkgs.txt @@ -1,66 +1,42 @@ github.com/bittorrent/go-btfs github.com/bittorrent/go-btfs/assets +github.com/bittorrent/go-btfs/bindata github.com/bittorrent/go-btfs/cmd/btfs github.com/bittorrent/go-btfs/cmd/btfs/util github.com/bittorrent/go-btfs/cmd/ipfswatch -github.com/bittorrent/go-btfs/cmd/seccat -github.com/bittorrent/go-btfs/commands github.com/bittorrent/go-btfs/core github.com/bittorrent/go-btfs/core/bootstrap github.com/bittorrent/go-btfs/core/commands github.com/bittorrent/go-btfs/core/commands/cmdenv -github.com/bittorrent/go-btfs/core/commands/dag -github.com/bittorrent/go-btfs/core/commands/e -github.com/bittorrent/go-btfs/core/commands/name -github.com/bittorrent/go-btfs/core/commands/object -github.com/bittorrent/go-btfs/core/commands/rm -github.com/bittorrent/go-btfs/core/commands/storage github.com/bittorrent/go-btfs/core/commands/storage/challenge github.com/bittorrent/go-btfs/core/commands/storage/helper -github.com/bittorrent/go-btfs/core/commands/storage/upload/escrow -github.com/bittorrent/go-btfs/core/commands/storage/upload/guard -github.com/bittorrent/go-btfs/core/commands/storage/upload/helper -github.com/bittorrent/go-btfs/core/commands/storage/upload/offline +github.com/bittorrent/go-btfs/core/commands/storage/stats +github.com/bittorrent/go-btfs/core/commands/storage/upload/sessions github.com/bittorrent/go-btfs/core/commands/storage/upload/upload -github.com/bittorrent/go-btfs/core/commands/unixfs github.com/bittorrent/go-btfs/core/coreapi github.com/bittorrent/go-btfs/core/coreapi/test -github.com/bittorrent/go-btfs/core/coredag github.com/bittorrent/go-btfs/core/corehttp -github.com/bittorrent/go-btfs/core/corehttp/remote -github.com/bittorrent/go-btfs/core/corerepo -github.com/bittorrent/go-btfs/core/coreunix github.com/bittorrent/go-btfs/core/coreunix/test github.com/bittorrent/go-btfs/core/hub -github.com/bittorrent/go-btfs/core/mock -github.com/bittorrent/go-btfs/core/node -github.com/bittorrent/go-btfs/core/node/helpers -github.com/bittorrent/go-btfs/core/node/libp2p +github.com/bittorrent/go-btfs/core/wallet github.com/bittorrent/go-btfs/keystore github.com/bittorrent/go-btfs/namesys github.com/bittorrent/go-btfs/namesys/republisher github.com/bittorrent/go-btfs/namesys/resolve -github.com/bittorrent/go-btfs/p2p -github.com/bittorrent/go-btfs/plugin -github.com/bittorrent/go-btfs/plugin/loader -github.com/bittorrent/go-btfs/plugin/plugins/badgerds -github.com/bittorrent/go-btfs/plugin/plugins/flatfs -github.com/bittorrent/go-btfs/plugin/plugins/git -github.com/bittorrent/go-btfs/plugin/plugins/levelds -github.com/bittorrent/go-btfs/protos/contracts -github.com/bittorrent/go-btfs/protos/session -github.com/bittorrent/go-btfs/protos/shard +github.com/bittorrent/go-btfs/peering github.com/bittorrent/go-btfs/repo -github.com/bittorrent/go-btfs/repo/common github.com/bittorrent/go-btfs/repo/fsrepo github.com/bittorrent/go-btfs/repo/fsrepo/migrations -github.com/bittorrent/go-btfs/spin -github.com/bittorrent/go-btfs/tar -github.com/bittorrent/go-btfs/thirdparty/assert -github.com/bittorrent/go-btfs/thirdparty/cidv0v1 -github.com/bittorrent/go-btfs/thirdparty/dir +github.com/bittorrent/go-btfs/settlement/swap +github.com/bittorrent/go-btfs/settlement/swap/bttc +github.com/bittorrent/go-btfs/settlement/swap/erc20 +github.com/bittorrent/go-btfs/settlement/swap/vault +github.com/bittorrent/go-btfs/statestore/leveldb +github.com/bittorrent/go-btfs/statestore/mock +github.com/bittorrent/go-btfs/test/integration github.com/bittorrent/go-btfs/thirdparty/notifier github.com/bittorrent/go-btfs/thirdparty/unit -github.com/bittorrent/go-btfs/thirdparty/verifbs -github.com/bittorrent/go-btfs/utils -github.com/bittorrent/go-btfs/settlement/swap/bttc +github.com/bittorrent/go-btfs/transaction +github.com/bittorrent/go-btfs/transaction/crypto +github.com/bittorrent/go-btfs/transaction/crypto/clef +github.com/bittorrent/go-btfs/utils \ No newline at end of file diff --git a/transaction/backendmock/backend.go b/transaction/backendmock/backend.go index 28d66bc..79edf0d 100644 --- a/transaction/backendmock/backend.go +++ b/transaction/backendmock/backend.go @@ -12,117 +12,133 @@ import ( ) type backendMock struct { - codeAt func(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) - sendTransaction func(ctx context.Context, tx *types.Transaction) error - suggestGasPrice func(ctx context.Context) (*big.Int, error) - estimateGas func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) - transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - pendingNonceAt func(ctx context.Context, account common.Address) (uint64, error) - transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) - blockNumber func(ctx context.Context) (uint64, error) - blockByNumber func(ctx context.Context, number *big.Int) (*types.Block, error) - headerByNumber func(ctx context.Context, number *big.Int) (*types.Header, error) - balanceAt func(ctx context.Context, address common.Address, block *big.Int) (*big.Int, error) - nonceAt func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) + codeAt func(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) + callContract func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) + pendingCodeAt func(ctx context.Context, account common.Address) ([]byte, error) + filterLogs func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) + subscribeFilterLogs func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) + sendTransaction func(ctx context.Context, tx *types.Transaction) error + suggestGasPrice func(ctx context.Context) (*big.Int, error) + estimateGas func(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) + transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) + pendingNonceAt func(ctx context.Context, account common.Address) (uint64, error) + transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) + blockNumber func(ctx context.Context) (uint64, error) + blockByNumber func(ctx context.Context, number *big.Int) (*types.Block, error) + headerByNumber func(ctx context.Context, number *big.Int) (*types.Header, error) + balanceAt func(ctx context.Context, address common.Address, block *big.Int) (*big.Int, error) + nonceAt func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) } func (m *backendMock) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { if m.codeAt != nil { return m.codeAt(ctx, contract, blockNumber) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.codeAt not implemented") } -func (*backendMock) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - return nil, errors.New("not implemented") +func (m *backendMock) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + if m.callContract != nil { + return m.callContract(ctx, call, blockNumber) + } + return nil, errors.New("backendMock.callContract not implemented") } -func (*backendMock) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { - return nil, errors.New("not implemented") +func (m *backendMock) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { + if m.pendingCodeAt != nil { + return m.pendingCodeAt(ctx, account) + } + return nil, errors.New("backendMock.pendingCodeAt not implemented") } func (m *backendMock) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { if m.pendingNonceAt != nil { return m.pendingNonceAt(ctx, account) } - return 0, errors.New("not implemented") + return 0, errors.New("backendMock.pendingNonceAt not implemented") } func (m *backendMock) SuggestGasPrice(ctx context.Context) (*big.Int, error) { if m.suggestGasPrice != nil { return m.suggestGasPrice(ctx) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.suggestGasPrice not implemented") } func (m *backendMock) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { if m.estimateGas != nil { return m.estimateGas(ctx, call) } - return 0, errors.New("not implemented") + return 0, errors.New("backendMock.estimateGas not implemented") } func (m *backendMock) SendTransaction(ctx context.Context, tx *types.Transaction) error { if m.sendTransaction != nil { return m.sendTransaction(ctx, tx) } - return errors.New("not implemented") + return errors.New("backendMock.sendTransaction not implemented") } -func (*backendMock) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - return nil, errors.New("not implemented") +func (m *backendMock) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { + if m.filterLogs != nil { + return m.filterLogs(ctx, query) + } + return nil, errors.New("backendMock.filterLogs not implemented") } -func (*backendMock) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { - return nil, errors.New("not implemented") +func (m *backendMock) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + if m.subscribeFilterLogs != nil { + return m.subscribeFilterLogs(ctx, query, ch) + } + return nil, errors.New("backendMock.subscribeFilterLogs not implemented") } func (m *backendMock) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { if m.transactionReceipt != nil { return m.transactionReceipt(ctx, txHash) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.transactionReceipt not implemented") } func (m *backendMock) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { if m.transactionByHash != nil { return m.transactionByHash(ctx, hash) } - return nil, false, errors.New("not implemented") + return nil, false, errors.New("backendMock.transactionByHash not implemented") } func (m *backendMock) BlockNumber(ctx context.Context) (uint64, error) { if m.blockNumber != nil { return m.blockNumber(ctx) } - return 0, errors.New("not implemented") + return 0, errors.New("backendMock.blockNumber not implemented") } func (m *backendMock) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { if m.blockNumber != nil { return m.blockByNumber(ctx, number) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.blockByNumber not implemented") } func (m *backendMock) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { if m.headerByNumber != nil { return m.headerByNumber(ctx, number) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.headerByNumber not implemented") } func (m *backendMock) BalanceAt(ctx context.Context, address common.Address, block *big.Int) (*big.Int, error) { if m.balanceAt != nil { return m.balanceAt(ctx, address, block) } - return nil, errors.New("not implemented") + return nil, errors.New("backendMock.balanceAt not implemented") } func (m *backendMock) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { if m.nonceAt != nil { return m.nonceAt(ctx, account, blockNumber) } - return 0, errors.New("not implemented") + return 0, errors.New("backendMock.nonceAt not implemented") } func New(opts ...Option) transaction.Backend { @@ -148,12 +164,36 @@ func WithCodeAtFunc(f func(ctx context.Context, contract common.Address, blockNu }) } +func WithCallContractFunc(f func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)) Option { + return optionFunc(func(s *backendMock) { + s.callContract = f + }) +} + +func WithPendingCodeAtFunc(f func(ctx context.Context, account common.Address) ([]byte, error)) Option { + return optionFunc(func(s *backendMock) { + s.pendingCodeAt = f + }) +} + +func WithFilterLogsFunc(f func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)) Option { + return optionFunc(func(s *backendMock) { + s.filterLogs = f + }) +} + func WithPendingNonceAtFunc(f func(ctx context.Context, account common.Address) (uint64, error)) Option { return optionFunc(func(s *backendMock) { s.pendingNonceAt = f }) } +func WithSubscribeFilterLogsFunc(f func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)) Option { + return optionFunc(func(s *backendMock) { + s.subscribeFilterLogs = f + }) +} + func WithSuggestGasPriceFunc(f func(ctx context.Context) (*big.Int, error)) Option { return optionFunc(func(s *backendMock) { s.suggestGasPrice = f diff --git a/transaction/crypto/mock/signer.go b/transaction/crypto/mock/signer.go index 661046e..b7b72e5 100644 --- a/transaction/crypto/mock/signer.go +++ b/transaction/crypto/mock/signer.go @@ -2,6 +2,7 @@ package mock import ( "crypto/ecdsa" + "errors" "math/big" "github.com/bittorrent/go-btfs/transaction/crypto" @@ -11,33 +12,46 @@ import ( ) type signerMock struct { - signTx func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) - signTypedData func(*eip712.TypedData) ([]byte, error) - ethereumAddress func() (common.Address, error) - signFunc func([]byte) ([]byte, error) + signTxFunc func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) + signTypedDataFunc func(*eip712.TypedData) ([]byte, error) + ethereumAddressFunc func() (common.Address, error) + signFuncFunc func([]byte) ([]byte, error) + publicKeyFunc func() (*ecdsa.PublicKey, error) } func (m *signerMock) EthereumAddress() (common.Address, error) { - if m.ethereumAddress != nil { - return m.ethereumAddress() + if m.ethereumAddressFunc != nil { + return m.ethereumAddressFunc() } - return common.Address{}, nil + return common.Address{}, errors.New("signerMock.ethereumAddressFunc not implemented") } func (m *signerMock) Sign(data []byte) ([]byte, error) { - return m.signFunc(data) + if m.signFuncFunc != nil { + return m.signFuncFunc(data) + } + return nil, errors.New("signerMock.signFuncFunc not implemented") } func (m *signerMock) SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - return m.signTx(transaction, chainID) + if m.signTxFunc != nil { + return m.signTxFunc(transaction, chainID) + } + return nil, errors.New("signerMock.signTxFunc not implemented") } -func (*signerMock) PublicKey() (*ecdsa.PublicKey, error) { - return nil, nil +func (m *signerMock) PublicKey() (*ecdsa.PublicKey, error) { + if m.publicKeyFunc != nil { + return m.publicKeyFunc() + } + return nil, errors.New("signerMock.publicKeyFunc not implemented") } func (m *signerMock) SignTypedData(d *eip712.TypedData) ([]byte, error) { - return m.signTypedData(d) + if m.signTypedDataFunc != nil { + return m.signTypedDataFunc(d) + } + return nil, errors.New("signerMock.signTypedDataFunc not implemented") } func New(opts ...Option) crypto.Signer { @@ -59,24 +73,30 @@ func (f optionFunc) apply(r *signerMock) { f(r) } func WithSignFunc(f func(data []byte) ([]byte, error)) Option { return optionFunc(func(s *signerMock) { - s.signFunc = f + s.signFuncFunc = f }) } func WithSignTxFunc(f func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error)) Option { return optionFunc(func(s *signerMock) { - s.signTx = f + s.signTxFunc = f }) } func WithSignTypedDataFunc(f func(*eip712.TypedData) ([]byte, error)) Option { return optionFunc(func(s *signerMock) { - s.signTypedData = f + s.signTypedDataFunc = f }) } func WithEthereumAddressFunc(f func() (common.Address, error)) Option { return optionFunc(func(s *signerMock) { - s.ethereumAddress = f + s.ethereumAddressFunc = f + }) +} + +func WithPublicKeyFunc(f func() (*ecdsa.PublicKey, error)) Option { + return optionFunc(func(s *signerMock) { + s.publicKeyFunc = f }) } diff --git a/transaction/mock/transaction.go b/transaction/mock/transaction.go index 0297572..f3da7e2 100644 --- a/transaction/mock/transaction.go +++ b/transaction/mock/transaction.go @@ -54,56 +54,56 @@ func (m *transactionServiceMock) Send(ctx context.Context, request *transaction. if m.send != nil { return m.send(ctx, request) } - return common.Hash{}, errors.New("not implemented") + return common.Hash{}, errors.New("transactionServiceMock.send not implemented") } func (m *transactionServiceMock) WaitForReceipt(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) { if m.waitForReceipt != nil { return m.waitForReceipt(ctx, txHash) } - return nil, errors.New("not implemented") + return nil, errors.New("transactionServiceMock.waitForReceipt not implemented") } func (m *transactionServiceMock) WatchSentTransaction(txHash common.Hash) (<-chan types.Receipt, <-chan error, error) { if m.watchSentTransaction != nil { return m.watchSentTransaction(txHash) } - return nil, nil, errors.New("not implemented") + return nil, nil, errors.New("transactionServiceMock.watchSentTransaction not implemented") } func (m *transactionServiceMock) Call(ctx context.Context, request *transaction.TxRequest) (result []byte, err error) { if m.call != nil { return m.call(ctx, request) } - return nil, errors.New("not implemented") + return nil, errors.New("transactionServiceMock.call not implemented") } func (m *transactionServiceMock) PendingTransactions() ([]common.Hash, error) { if m.pendingTransactions != nil { return m.pendingTransactions() } - return nil, errors.New("not implemented") + return nil, errors.New("transactionServiceMock.pendingTransactions not implemented") } func (m *transactionServiceMock) ResendTransaction(ctx context.Context, txHash common.Hash) error { if m.resendTransaction != nil { return m.resendTransaction(ctx, txHash) } - return errors.New("not implemented") + return errors.New("transactionServiceMock.resendTransaction not implemented") } func (m *transactionServiceMock) StoredTransaction(txHash common.Hash) (*transaction.StoredTransaction, error) { if m.storedTransaction != nil { return m.storedTransaction(txHash) } - return nil, errors.New("not implemented") + return nil, errors.New("transactionServiceMock.storedTransaction not implemented") } func (m *transactionServiceMock) CancelTransaction(ctx context.Context, originalTxHash common.Hash) (common.Hash, error) { if m.cancelTransaction != nil { return m.cancelTransaction(ctx, originalTxHash) } - return common.Hash{}, errors.New("not implemented") + return common.Hash{}, errors.New("transactionServiceMock.cancelTransaction not implemented") } func (m *transactionServiceMock) Close() error { @@ -114,14 +114,14 @@ func (m *transactionServiceMock) BttBalanceAt(ctx context.Context, address commo if m.bttBalanceAt != nil { return m.bttBalanceAt(ctx, address, block) } - return big.NewInt(0), errors.New("Error") + return big.NewInt(0), errors.New("transactionServiceMock.bttBalanceAt not implemented") } func (m *transactionServiceMock) MyBttBalance(ctx context.Context) (*big.Int, error) { if m.myBttBalance != nil { return m.myBttBalance(ctx) } - return big.NewInt(0), errors.New("Error") + return big.NewInt(0), errors.New("transactionServiceMock.myBttBalance not implemented") } // Option is the option passed to the mock Chequebook service @@ -269,7 +269,7 @@ func WithABICall(abi *abi.ABI, to common.Address, result []byte, method string, func WithABISend(abi *abi.ABI, txHash common.Hash, expectedAddress common.Address, expectedValue *big.Int, method string, params ...interface{}) Option { return optionFunc(func(s *transactionServiceMock) { - s.send = func(ctx context.Context, request *transaction.TxRequest) (common.Hash, error) { + s.send = func(_ context.Context, request *transaction.TxRequest) (common.Hash, error) { data, err := abi.Pack(method, params...) if err != nil { return common.Hash{}, err @@ -282,7 +282,8 @@ func WithABISend(abi *abi.ABI, txHash common.Hash, expectedAddress common.Addres if request.To != nil && *request.To != expectedAddress { return common.Hash{}, fmt.Errorf("sending to wrong contract. wanted %x, got %x", expectedAddress, request.To) } - if request.Value.Cmp(expectedValue) != 0 { + // if send is called by contract,then the request.Value is nil + if request.Value != nil && request.Value.Cmp(expectedValue) != 0 { return common.Hash{}, fmt.Errorf("sending with wrong value. wanted %d, got %d", expectedValue, request.Value) } diff --git a/transaction/monitormock/monitor.go b/transaction/monitormock/monitor.go index 6cbccd4..ead980a 100644 --- a/transaction/monitormock/monitor.go +++ b/transaction/monitormock/monitor.go @@ -19,14 +19,14 @@ func (m *transactionMonitorMock) WatchTransaction(txHash common.Hash, nonce uint if m.watchTransaction != nil { return m.watchTransaction(txHash, nonce) } - return nil, nil, errors.New("not implemented") + return nil, nil, errors.New("transactionMonitorMock.watchTransaction not implemented") } func (m *transactionMonitorMock) WaitBlock(ctx context.Context, block *big.Int) (*types.Block, error) { - if m.watchTransaction != nil { + if m.waitBlock != nil { return m.waitBlock(ctx, block) } - return nil, errors.New("not implemented") + return nil, errors.New("transactionMonitorMock.waitBlock not implemented") } func (m *transactionMonitorMock) Close() error { diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index b7fe5ca..14eaf81 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -69,7 +69,7 @@ func TestTransactionSend(t *testing.T) { recipient := common.HexToAddress("0xabcd") txData := common.Hex2Bytes("0xabcdee") value := big.NewInt(1) - suggestedGasPrice := big.NewInt(2) + suggestedGasPrice := big.NewInt(300000000000000) //gas price has been fixed to 300000000000000 estimatedGasLimit := uint64(3) nonce := uint64(2) chainID := big.NewInt(5) @@ -389,7 +389,11 @@ func TestTransactionWaitForReceipt(t *testing.T) { }, nil }), ), - signermock.New(), + signermock.New( + signermock.WithEthereumAddressFunc(func() (common.Address, error) { + return common.Address{}, nil + }), + ), store, chainID, monitormock.New( diff --git a/version.go b/version.go index c8b7778..c5e4b7e 100644 --- a/version.go +++ b/version.go @@ -4,7 +4,7 @@ package btfs var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "2.1.3" +const CurrentVersionNumber = "2.2.0" const ApiVersion = "/go-btfs/" + CurrentVersionNumber + "/"