From aa3e1214c5af220630aa3278302ef67b0f7e2e4e Mon Sep 17 00:00:00 2001 From: Alex Wu Date: Wed, 22 May 2024 14:25:57 +0800 Subject: [PATCH 1/9] release qng v1.2.0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6d9a7475..623057a8 100755 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ qng-build: @echo "Enable DEBUG" @go build -o $(GOBIN)/qng$(OUTPUT_SUFFIX) $(GOFLAGS_DEV) -gcflags="all=-N -l" "github.com/Qitmeer/qng/cmd/qng" else - @go build -o $(GOBIN)/qng$(OUTPUT_SUFFIX) $(GOFLAGS_DEV) "github.com/Qitmeer/qng/cmd/qng" + @go build -o $(GOBIN)/qng$(OUTPUT_SUFFIX) $(GOFLAGS_RELEASE) "github.com/Qitmeer/qng/cmd/qng" endif qx: @go build -o $(GOBIN)/qx $(GOFLAGS_DEV) "github.com/Qitmeer/qng/cmd/qx" From b6240087c95f974179e5edfe6e68a6f6878503ef Mon Sep 17 00:00:00 2001 From: Jin Date: Tue, 28 May 2024 18:55:11 +0800 Subject: [PATCH 2/9] BUG:AddBalance panic --- services/acct/acctmgr.go | 41 ++++++++++++++++++++++++++++++++-------- services/acct/api.go | 4 +++- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/services/acct/acctmgr.go b/services/acct/acctmgr.go index a4c1228e..78be64fb 100644 --- a/services/acct/acctmgr.go +++ b/services/acct/acctmgr.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" + "sync" "github.com/Qitmeer/qng/config" "github.com/Qitmeer/qng/core/address" @@ -22,13 +23,14 @@ import ( // account manager communicate with various backends for signing transactions. type AccountManager struct { service.Service - chain *blockchain.BlockChain - cfg *config.Config - db legacydb.DB - info *AcctInfo - utxoops []*UTXOOP - watchers map[string]*AcctBalanceWatcher - events *event.Feed + chain *blockchain.BlockChain + cfg *config.Config + db legacydb.DB + info *AcctInfo + utxoops []*UTXOOP + watchLock sync.RWMutex + watchers map[string]*AcctBalanceWatcher + events *event.Feed } func (a *AccountManager) SetEvents(evs *event.Feed) { @@ -313,13 +315,17 @@ func (a *AccountManager) apply(add bool, op *types.TxOutPoint, entry *utxo.UtxoE au := NewAcctUTXO() au.SetBalance(uint64(entry.Amount().Value)) + a.watchLock.RLock() wb, exist := a.watchers[addrStr] + a.watchLock.RUnlock() if entry.IsCoinBase() { au.SetCoinbase() // if !exist { wb = NewAcctBalanceWatcher(addrStr, balance) + a.watchLock.Lock() a.watchers[addrStr] = wb + a.watchLock.Unlock() } opk := OutpointKey(op) uw := BuildUTXOWatcher(opk, au, entry, a) @@ -330,7 +336,9 @@ func (a *AccountManager) apply(add bool, op *types.TxOutPoint, entry *utxo.UtxoE au.SetCLTV() if !exist { wb = NewAcctBalanceWatcher(addrStr, balance) + a.watchLock.Lock() a.watchers[addrStr] = wb + a.watchLock.Unlock() } opk := OutpointKey(op) uw := BuildUTXOWatcher(opk, au, entry, a) @@ -406,13 +414,17 @@ func (a *AccountManager) apply(add bool, op *types.TxOutPoint, entry *utxo.UtxoE func (a *AccountManager) DelWatcher(addr string, op *types.TxOutPoint) { if op != nil { + a.watchLock.RLock() wb, exist := a.watchers[addr] + a.watchLock.RUnlock() if !exist { return } wb.Del(OutpointKey(op)) } else { + a.watchLock.Lock() delete(a.watchers, addr) + a.watchLock.Unlock() } } @@ -449,10 +461,14 @@ func (a *AccountManager) initWatchers(dbTx legacydb.Tx) error { return nil } addrStr := string(k) + a.watchLock.RLock() wb, exist := a.watchers[addrStr] + a.watchLock.RUnlock() if !exist { wb = NewAcctBalanceWatcher(addrStr, balance) + a.watchLock.Lock() a.watchers[addrStr] = wb + a.watchLock.Unlock() } kus = append(kus, ku) aus = append(aus, au) @@ -472,6 +488,8 @@ func (a *AccountManager) initWatchers(dbTx legacydb.Tx) error { } } } + a.watchLock.RLock() + defer a.watchLock.RUnlock() if len(a.watchers) > 0 { for _, w := range a.watchers { err = w.Update(a) @@ -514,7 +532,8 @@ func (a *AccountManager) Commit() error { return err } } - + a.watchLock.RLock() + defer a.watchLock.RUnlock() if len(a.watchers) > 0 { for _, w := range a.watchers { err = w.Update(a) @@ -534,7 +553,9 @@ func (a *AccountManager) GetBalance(addr string) (uint64, error) { return 0, fmt.Errorf("network error:%s", addr) } result := uint64(0) + a.watchLock.RLock() wb, exist := a.watchers[addr] + a.watchLock.RUnlock() if exist { return wb.GetBalance(), nil } @@ -562,7 +583,9 @@ func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { if len(us) > 0 { for k, v := range us { ur := UTXOResult{Type: v.TypeStr(), Amount: v.balance, Status: "valid"} + a.watchLock.RLock() wb, exist := a.watchers[addr] + a.watchLock.RUnlock() if exist { wu := wb.GetByOPS(k) if wu != nil { @@ -606,7 +629,9 @@ func (a *AccountManager) AddAddress(addr string) error { if a.info.Has(addr) { return fmt.Errorf(fmt.Sprintf("Already exists:%s", addr)) } + a.watchLock.RLock() _, exist := a.watchers[addr] + a.watchLock.RUnlock() if exist { return fmt.Errorf(fmt.Sprintf("Already exists watcher:%s", addr)) } diff --git a/services/acct/api.go b/services/acct/api.go index 86b02e4d..ea8174f0 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -32,8 +32,10 @@ func (api *PublicAccountManagerAPI) GetAcctInfo() (interface{}, error) { Mode: api.a.cfg.AcctMode, Version: api.a.info.version, Total: api.a.info.total, - Watcher: uint32(len(api.a.watchers)), } + api.a.watchLock.RLock() + ai.Watcher = uint32(len(api.a.watchers)) + api.a.watchLock.RUnlock() if api.a.info.GetAddrTotal() > 0 { ai.Addrs = api.a.info.addrs } From c897b1a73bf2e4175701e9d1a209f1e0f9333e11 Mon Sep 17 00:00:00 2001 From: Jin Date: Wed, 29 May 2024 10:34:17 +0800 Subject: [PATCH 3/9] BUG:AddBalance panic about utxo watcher --- services/acct/watcher.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/services/acct/watcher.go b/services/acct/watcher.go index 19287478..4af0ffa2 100644 --- a/services/acct/watcher.go +++ b/services/acct/watcher.go @@ -3,6 +3,7 @@ package acct import ( "encoding/hex" "fmt" + "sync" "github.com/Qitmeer/qng/common/hash" "github.com/Qitmeer/qng/consensus/forks" @@ -19,6 +20,8 @@ type AcctBalanceWatcher struct { unlocUTXONum uint32 watchers map[string]AcctUTXOIWatcher + + lock sync.RWMutex } func (aw *AcctBalanceWatcher) Add(op []byte, au AcctUTXOIWatcher) { @@ -26,19 +29,25 @@ func (aw *AcctBalanceWatcher) Add(op []byte, au AcctUTXOIWatcher) { return } key := hex.EncodeToString(op) + aw.lock.Lock() aw.watchers[key] = au + aw.lock.Unlock() log.Trace(fmt.Sprintf("Balance (%s) add utxo watcher:%s %s", aw.address, key, au.GetName())) } func (aw *AcctBalanceWatcher) Del(op []byte) { key := hex.EncodeToString(op) + aw.lock.Lock() delete(aw.watchers, key) + aw.lock.Unlock() log.Trace(fmt.Sprintf("Balance (%s) del utxo watcher:%s", aw.address, key)) } func (aw *AcctBalanceWatcher) Has(op []byte) bool { ops := hex.EncodeToString(op) + aw.lock.RLock() _, exist := aw.watchers[ops] + aw.lock.RUnlock() return exist } @@ -48,7 +57,10 @@ func (aw *AcctBalanceWatcher) Get(op []byte) AcctUTXOIWatcher { } func (aw *AcctBalanceWatcher) GetByOPS(ops string) AcctUTXOIWatcher { - return aw.watchers[ops] + aw.lock.RLock() + ret := aw.watchers[ops] + aw.lock.RUnlock() + return ret } func (aw *AcctBalanceWatcher) GetBalance() uint64 { @@ -58,6 +70,8 @@ func (aw *AcctBalanceWatcher) GetBalance() uint64 { func (aw *AcctBalanceWatcher) Update(am *AccountManager) error { aw.unlocked = 0 aw.unlocUTXONum = 0 + aw.lock.RLock() + defer aw.lock.RUnlock() for k, w := range aw.watchers { err := w.Update(am) if err != nil { @@ -76,7 +90,7 @@ func (aw *AcctBalanceWatcher) Update(am *AccountManager) error { if err != nil { return err } - am.events.Send(event.New(&types.AutoCollectUtxo{ + go am.events.Send(event.New(&types.AutoCollectUtxo{ Op: *op, Address: aw.address, Amount: w.GetBalance(), From c1b380ff480e3ad8abb4c1c0a8931f7e6b28b42a Mon Sep 17 00:00:00 2001 From: Jin Date: Wed, 29 May 2024 15:16:03 +0800 Subject: [PATCH 4/9] acct:support delete balance RPC --- script/cli.sh | 10 ++++++++++ services/acct/acctmgr.go | 18 ++++++++++++++++++ services/acct/api.go | 4 ++++ services/acct/info.go | 16 ++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/script/cli.sh b/script/cli.sh index b860ad96..34f9c58a 100755 --- a/script/cli.sh +++ b/script/cli.sh @@ -568,6 +568,12 @@ function add_balance() { get_result "$data" } +function del_balance() { + local address=$1 + local data='{"jsonrpc":"2.0","method":"delBalance","params":["'$address'"],"id":null}' + get_result "$data" +} + function get_acctinfo() { local data='{"jsonrpc":"2.0","method":"getAcctInfo","params":[],"id":null}' get_result "$data" @@ -859,6 +865,7 @@ function usage(){ echo " getbalance
" echo " getbalanceinfo
" echo " addbalance
" + echo " delbalance
" echo " getaddresses " echo " modules" echo " daginfo" @@ -1298,6 +1305,9 @@ elif [ "$1" == "getbalanceinfo" ]; then elif [ "$1" == "addbalance" ]; then shift add_balance $@ +elif [ "$1" == "delbalance" ]; then + shift + del_balance $@ elif [ "$1" == "rpcmax" ]; then shift set_rpc_maxclients $@ diff --git a/services/acct/acctmgr.go b/services/acct/acctmgr.go index 78be64fb..09572602 100644 --- a/services/acct/acctmgr.go +++ b/services/acct/acctmgr.go @@ -644,6 +644,24 @@ func (a *AccountManager) AddAddress(addr string) error { } return a.rebuild([]string{addr}) } + +func (a *AccountManager) DelAddress(addr string) error { + if !a.cfg.AcctMode { + return fmt.Errorf("Please enable --acctmode") + } + if !address.IsForCurNetwork(addr) { + return fmt.Errorf("network error:%s", addr) + } + if !a.info.Has(addr) { + return fmt.Errorf(fmt.Sprintf("Account does not exist:%s", addr)) + } + a.DelWatcher(addr, nil) + a.info.Del(addr) + return a.db.Update(func(dbTx legacydb.Tx) error { + return a.cleanBalanceDB(dbTx, addr) + }) +} + func (a *AccountManager) GetChain() *blockchain.BlockChain { return a.chain } diff --git a/services/acct/api.go b/services/acct/api.go index ea8174f0..9b100c95 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -69,3 +69,7 @@ func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.Coi func (api *PublicAccountManagerAPI) AddBalance(addr string) (interface{}, error) { return nil, api.a.AddAddress(addr) } + +func (api *PublicAccountManagerAPI) DelBalance(addr string) (interface{}, error) { + return nil, api.a.DelAddress(addr) +} diff --git a/services/acct/info.go b/services/acct/info.go index 506f744a..778391a0 100644 --- a/services/acct/info.go +++ b/services/acct/info.go @@ -117,6 +117,22 @@ func (ai *AcctInfo) Has(addr string) bool { func (ai *AcctInfo) Add(addr string) { ai.addrs = append(ai.addrs, addr) + log.Info("Add address for AccountManager", "addr", addr, "total", ai.GetAddrTotal()) +} + +func (ai *AcctInfo) Del(addr string) { + if ai.GetAddrTotal() <= 0 { + return + } + ret := []string{} + for _, ad := range ai.addrs { + if ad == addr { + continue + } + ret = append(ret, ad) + } + ai.addrs = ret + log.Info("Delete address for AccountManager", "addr", addr, "total", ai.GetAddrTotal()) } func NewAcctInfo() *AcctInfo { From ac9bf4c0fa52d3b5da2ffe1bdc7e4c52c50210e5 Mon Sep 17 00:00:00 2001 From: Jin Date: Wed, 29 May 2024 17:36:13 +0800 Subject: [PATCH 5/9] acct:Optimize RPC --- core/json/node.go | 11 +++---- services/acct/acctmgr.go | 64 +++++++++++++++++++++++++++++----------- services/acct/api.go | 1 + services/acct/watcher.go | 6 ++++ 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/core/json/node.go b/core/json/node.go index 608c34d0..e474b2f1 100644 --- a/core/json/node.go +++ b/core/json/node.go @@ -115,11 +115,12 @@ type SubsidyInfo struct { } type AcctInfo struct { - Mode bool `json:"mode"` - Version uint32 `json:"version"` - Total uint32 `json:"total"` - Watcher uint32 `json:"watcher"` - Addrs []string `json:"addrs,omitempty"` + Mode bool `json:"mode"` + Version uint32 `json:"version"` + Total uint32 `json:"total"` + Watcher uint32 `json:"watcher"` + UtxoWatcher uint32 `json:"utxowatcher"` + Addrs []string `json:"addrs,omitempty"` } type MeerDAGInfoResult struct { diff --git a/services/acct/acctmgr.go b/services/acct/acctmgr.go index 09572602..515f8af1 100644 --- a/services/acct/acctmgr.go +++ b/services/acct/acctmgr.go @@ -546,11 +546,12 @@ func (a *AccountManager) Commit() error { } func (a *AccountManager) GetBalance(addr string) (uint64, error) { - if !a.cfg.AcctMode { - return 0, fmt.Errorf("Please enable --acctmode") + err := a.checkAddress(addr) + if err != nil { + return 0, err } - if !address.IsForCurNetwork(addr) { - return 0, fmt.Errorf("network error:%s", addr) + if !a.info.Has(addr) { + return 0, fmt.Errorf("Please track this account:%s", addr) } result := uint64(0) a.watchLock.RLock() @@ -560,7 +561,7 @@ func (a *AccountManager) GetBalance(addr string) (uint64, error) { return wb.GetBalance(), nil } - err := a.db.Update(func(dbTx legacydb.Tx) error { + err = a.db.Update(func(dbTx legacydb.Tx) error { balance, err := DBGetACCTBalance(dbTx, addr) if err != nil { return err @@ -577,8 +578,15 @@ func (a *AccountManager) GetBalance(addr string) (uint64, error) { } func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { + err := a.checkAddress(addr) + if err != nil { + return nil, err + } + if !a.info.Has(addr) { + return nil, fmt.Errorf("Please track this account:%s", addr) + } utxos := []UTXOResult{} - err := a.db.Update(func(dbTx legacydb.Tx) error { + err = a.db.Update(func(dbTx legacydb.Tx) error { us := DBGetACCTUTXOs(dbTx, addr) if len(us) > 0 { for k, v := range us { @@ -620,11 +628,9 @@ func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { } func (a *AccountManager) AddAddress(addr string) error { - if !a.cfg.AcctMode { - return fmt.Errorf("Please enable --acctmode") - } - if !address.IsForCurNetwork(addr) { - return fmt.Errorf("network error:%s", addr) + err := a.checkAddress(addr) + if err != nil { + return err } if a.info.Has(addr) { return fmt.Errorf(fmt.Sprintf("Already exists:%s", addr)) @@ -636,7 +642,7 @@ func (a *AccountManager) AddAddress(addr string) error { return fmt.Errorf(fmt.Sprintf("Already exists watcher:%s", addr)) } a.info.Add(addr) - err := a.db.Update(func(dbTx legacydb.Tx) error { + err = a.db.Update(func(dbTx legacydb.Tx) error { return a.cleanBalanceDB(dbTx, addr) }) if err != nil { @@ -646,11 +652,9 @@ func (a *AccountManager) AddAddress(addr string) error { } func (a *AccountManager) DelAddress(addr string) error { - if !a.cfg.AcctMode { - return fmt.Errorf("Please enable --acctmode") - } - if !address.IsForCurNetwork(addr) { - return fmt.Errorf("network error:%s", addr) + err := a.checkAddress(addr) + if err != nil { + return err } if !a.info.Has(addr) { return fmt.Errorf(fmt.Sprintf("Account does not exist:%s", addr)) @@ -695,6 +699,32 @@ func (a *AccountManager) APIs() []api.API { } } +func (a *AccountManager) checkAddress(addr string) error { + if !a.cfg.AcctMode { + return fmt.Errorf("Please enable --acctmode") + } + if len(addr) <= 0 { + return fmt.Errorf("The entered address cannot be empty") + } + if !address.IsForCurNetwork(addr) { + return fmt.Errorf("network error:%s", addr) + } + return nil +} + +func (a *AccountManager) getUtxoWatcherSize() int { + if len(a.watchers) <= 0 { + return 0 + } + a.watchLock.RLock() + defer a.watchLock.RUnlock() + size := 0 + for _, w := range a.watchers { + size += w.GetWatchersSize() + } + return size +} + func New(chain *blockchain.BlockChain, cfg *config.Config, _events *event.Feed) (*AccountManager, error) { a := AccountManager{ chain: chain, diff --git a/services/acct/api.go b/services/acct/api.go index 9b100c95..8c078c07 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -36,6 +36,7 @@ func (api *PublicAccountManagerAPI) GetAcctInfo() (interface{}, error) { api.a.watchLock.RLock() ai.Watcher = uint32(len(api.a.watchers)) api.a.watchLock.RUnlock() + ai.UtxoWatcher = uint32(api.a.getUtxoWatcherSize()) if api.a.info.GetAddrTotal() > 0 { ai.Addrs = api.a.info.addrs } diff --git a/services/acct/watcher.go b/services/acct/watcher.go index 4af0ffa2..55c95c23 100644 --- a/services/acct/watcher.go +++ b/services/acct/watcher.go @@ -100,6 +100,12 @@ func (aw *AcctBalanceWatcher) Update(am *AccountManager) error { return nil } +func (aw *AcctBalanceWatcher) GetWatchersSize() int { + aw.lock.RLock() + defer aw.lock.RUnlock() + return len(aw.watchers) +} + func NewAcctBalanceWatcher(address string, ab *AcctBalance) *AcctBalanceWatcher { return &AcctBalanceWatcher{ address: address, From e61cef0d71429fe5034ed97daa1d5b77f6b03813 Mon Sep 17 00:00:00 2001 From: Jin Date: Wed, 29 May 2024 17:44:22 +0800 Subject: [PATCH 6/9] acct:getbalanceinfo support verbose --- script/cli.sh | 8 ++++++-- services/acct/api.go | 10 ++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/script/cli.sh b/script/cli.sh index 34f9c58a..fa4e410f 100755 --- a/script/cli.sh +++ b/script/cli.sh @@ -516,11 +516,15 @@ function get_balance() { function get_balance_info() { local address=$1 local coinID=$2 + local verbose=$3 if [ "$coinID" == "" ]; then coinID=0 fi + if [ "$verbose" == "" ]; then + verbose="false" + fi - local data='{"jsonrpc":"2.0","method":"getBalanceInfo","params":["'$address'",'$coinID'],"id":null}' + local data='{"jsonrpc":"2.0","method":"getBalanceInfo","params":["'$address'",'$coinID','$verbose'],"id":null}' get_result "$data" } @@ -863,7 +867,7 @@ function usage(){ echo " amanapeerinfo" echo " acctinfo" echo " getbalance
" - echo " getbalanceinfo
" + echo " getbalanceinfo
" echo " addbalance
" echo " delbalance
" echo " getaddresses " diff --git a/services/acct/api.go b/services/acct/api.go index 8c078c07..0dc2f26b 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -43,7 +43,7 @@ func (api *PublicAccountManagerAPI) GetAcctInfo() (interface{}, error) { return ai, nil } -func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.CoinID) (interface{}, error) { +func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.CoinID, verbose bool) (interface{}, error) { result := BalanceInfoResult{CoinId: coinID.Name()} if coinID == types.MEERA { bal, err := api.a.GetBalance(addr) @@ -51,9 +51,11 @@ func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.Coi return nil, err } result.Balance = int64(bal) - result.UTXOs, err = api.a.GetUTXOs(addr) - if err != nil { - return nil, err + if verbose { + result.UTXOs, err = api.a.GetUTXOs(addr) + if err != nil { + return nil, err + } } return result, nil } else if coinID == types.MEERB { From d739ebcae1dd30439ff5642d3fddd985f1a561c4 Mon Sep 17 00:00:00 2001 From: Jin Date: Thu, 30 May 2024 16:25:42 +0800 Subject: [PATCH 7/9] acct:support get utxos --- consensus/model/acct.go | 2 +- core/blockchain/process.go | 2 +- core/json/node.go | 12 +++++------ script/cli.sh | 43 ++++++++++++++++++++++++++++++++++++++ services/acct/acctmgr.go | 35 ++++++++++++++++++++++++------- services/acct/api.go | 42 ++++++++++++++++++++++++++++++++----- services/acct/utils.go | 19 ++++++++++++++--- services/wallet/tx.go | 21 ++++--------------- 8 files changed, 136 insertions(+), 40 deletions(-) diff --git a/consensus/model/acct.go b/consensus/model/acct.go index 6c199866..6525eb9a 100644 --- a/consensus/model/acct.go +++ b/consensus/model/acct.go @@ -6,5 +6,5 @@ import ( type Acct interface { Apply(add bool, op *types.TxOutPoint, entry interface{}) error - Commit() error + Commit(point Block) error } diff --git a/core/blockchain/process.go b/core/blockchain/process.go index aeac229e..537346e8 100644 --- a/core/blockchain/process.go +++ b/core/blockchain/process.go @@ -311,7 +311,7 @@ func (b *BlockChain) maybeAcceptBlock(block *types.SerializedBlock, flags Behavi Source: source, }) if b.Acct != nil { - err = b.Acct.Commit() + err = b.Acct.Commit(ib) if err != nil { log.Error(err.Error()) } diff --git a/core/json/node.go b/core/json/node.go index e474b2f1..a5301920 100644 --- a/core/json/node.go +++ b/core/json/node.go @@ -115,12 +115,12 @@ type SubsidyInfo struct { } type AcctInfo struct { - Mode bool `json:"mode"` - Version uint32 `json:"version"` - Total uint32 `json:"total"` - Watcher uint32 `json:"watcher"` - UtxoWatcher uint32 `json:"utxowatcher"` - Addrs []string `json:"addrs,omitempty"` + Mode bool `json:"mode"` + Version uint32 `json:"version"` + StatPoint string `json:"statpoint"` + StatOrder uint32 `json:"statorder"` + Total uint32 `json:"total"` + Addrs []string `json:"addrs,omitempty"` } type MeerDAGInfoResult struct { diff --git a/script/cli.sh b/script/cli.sh index fa4e410f..22d65d5d 100755 --- a/script/cli.sh +++ b/script/cli.sh @@ -528,7 +528,33 @@ function get_balance_info() { get_result "$data" } +function get_utxos() { + local address=$1 + local limit=$2 + local locked=$3 + if [ "$limit" == "" ]; then + limit=0 + fi + if [ "$locked" == "" ]; then + local data='{"jsonrpc":"2.0","method":"getUTXOs","params":["'$address'",'$limit'],"id":null}' + get_result "$data" + else + local data='{"jsonrpc":"2.0","method":"getUTXOs","params":["'$address'",'$limit','$locked'],"id":null}' + get_result "$data" + fi +} +function get_valid_utxos() { + local address=$1 + local amount=$2 + if [ "$amount" == "" ]; then + amount=0 + fi + if [ "$locked" == "" ]; then + local data='{"jsonrpc":"2.0","method":"getValidUTXOs","params":["'$address'",'$amount'],"id":null}' + get_result "$data" + fi +} function unlock() { local account=$1 @@ -583,6 +609,11 @@ function get_acctinfo() { get_result "$data" } +function get_acctdebuginfo() { + local data='{"jsonrpc":"2.0","method":"getAcctDebugInfo","params":[],"id":null}' + get_result "$data" +} + function get_network_info(){ local data='{"jsonrpc":"2.0","method":"getNetworkInfo","params":[],"id":null}' get_result "$data" @@ -866,6 +897,7 @@ function usage(){ echo " amanainfo" echo " amanapeerinfo" echo " acctinfo" + echo " acctdebuginfo" echo " getbalance
" echo " getbalanceinfo
" echo " addbalance
" @@ -912,6 +944,8 @@ function usage(){ echo " getrawtxs
" echo "utxo :" echo " getutxo " + echo " getutxos
" + echo " getvalidutxos
" echo "miner :" echo " template" echo " miningstats" @@ -1299,6 +1333,9 @@ elif [ "$1" == "rpcinfo" ]; then elif [ "$1" == "acctinfo" ]; then shift get_acctinfo $@ +elif [ "$1" == "acctdebuginfo" ]; then + shift + get_acctdebuginfo $@ elif [ "$1" == "getbalance" ]; then shift get_balance $@ @@ -1306,6 +1343,12 @@ elif [ "$1" == "getbalance" ]; then elif [ "$1" == "getbalanceinfo" ]; then shift get_balance_info $@ +elif [ "$1" == "getutxos" ]; then + shift + get_utxos $@ +elif [ "$1" == "getvalidutxos" ]; then + shift + get_valid_utxos $@ elif [ "$1" == "addbalance" ]; then shift add_balance $@ diff --git a/services/acct/acctmgr.go b/services/acct/acctmgr.go index 515f8af1..12806f6e 100644 --- a/services/acct/acctmgr.go +++ b/services/acct/acctmgr.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/hex" "fmt" + "github.com/Qitmeer/qng/consensus/model" "sync" "github.com/Qitmeer/qng/config" @@ -31,6 +32,7 @@ type AccountManager struct { watchLock sync.RWMutex watchers map[string]*AcctBalanceWatcher events *event.Feed + statpoint model.Block } func (a *AccountManager) SetEvents(evs *event.Feed) { @@ -509,7 +511,7 @@ func (a *AccountManager) Apply(add bool, op *types.TxOutPoint, entry interface{} return nil } -func (a *AccountManager) Commit() error { +func (a *AccountManager) Commit(point model.Block) error { if !a.cfg.AcctMode { return nil } @@ -542,6 +544,7 @@ func (a *AccountManager) Commit() error { } } } + a.statpoint = point return nil } @@ -577,15 +580,16 @@ func (a *AccountManager) GetBalance(addr string) (uint64, error) { return result, nil } -func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { +func (a *AccountManager) GetUTXOs(addr string, limit *int, locked *bool, amount *uint64) ([]UTXOResult, uint64, error) { err := a.checkAddress(addr) if err != nil { - return nil, err + return nil, 0, err } if !a.info.Has(addr) { - return nil, fmt.Errorf("Please track this account:%s", addr) + return nil, 0, fmt.Errorf("Please track this account:%s", addr) } utxos := []UTXOResult{} + totalAmount := uint64(0) err = a.db.Update(func(dbTx legacydb.Tx) error { us := DBGetACCTUTXOs(dbTx, addr) if len(us) > 0 { @@ -598,8 +602,14 @@ func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { wu := wb.GetByOPS(k) if wu != nil { if wu.IsUnlocked() { + if locked != nil && *locked { + continue + } ur.Status = "unlocked" } else { + if locked != nil && !(*locked) { + continue + } ur.Status = "locked" } } @@ -616,15 +626,26 @@ func (a *AccountManager) GetUTXOs(addr string) ([]UTXOResult, error) { ur.PreTxHash = op.Hash.String() ur.PreOutIdx = op.OutIndex utxos = append(utxos, ur) + + if limit != nil { + if len(utxos) >= *limit { + break + } + } + totalAmount += ur.Amount + if amount != nil { + if totalAmount >= *amount { + break + } + } } } return nil }) if err != nil { - return nil, err + return nil, 0, err } - - return utxos, nil + return utxos, totalAmount, nil } func (a *AccountManager) AddAddress(addr string) error { diff --git a/services/acct/api.go b/services/acct/api.go index 0dc2f26b..33d8628e 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -5,6 +5,7 @@ import ( "github.com/Qitmeer/qng/core/json" "github.com/Qitmeer/qng/core/types" "github.com/Qitmeer/qng/meerevm/meer" + "math" ) // PublicEthereumAPI provides an API to access Ethereum full node-related @@ -31,15 +32,26 @@ func (api *PublicAccountManagerAPI) GetAcctInfo() (interface{}, error) { ai := json.AcctInfo{ Mode: api.a.cfg.AcctMode, Version: api.a.info.version, - Total: api.a.info.total, + Total: uint32(api.a.info.GetAddrTotal()), + } + if api.a.info.GetAddrTotal() > 0 { + ai.Addrs = api.a.info.addrs + } + if api.a.statpoint != nil { + ai.StatPoint = api.a.statpoint.GetHash().String() + ai.StatOrder = uint32(api.a.statpoint.GetOrder()) + } + return ai, nil +} + +func (api *PublicAccountManagerAPI) GetAcctDebugInfo() (interface{}, error) { + ai := AcctDebugInfo{ + Total: api.a.info.total, } api.a.watchLock.RLock() ai.Watcher = uint32(len(api.a.watchers)) api.a.watchLock.RUnlock() ai.UtxoWatcher = uint32(api.a.getUtxoWatcherSize()) - if api.a.info.GetAddrTotal() > 0 { - ai.Addrs = api.a.info.addrs - } return ai, nil } @@ -52,7 +64,7 @@ func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.Coi } result.Balance = int64(bal) if verbose { - result.UTXOs, err = api.a.GetUTXOs(addr) + result.UTXOs, result.TotalBalance, err = api.a.GetUTXOs(addr, nil, nil, nil) if err != nil { return nil, err } @@ -69,6 +81,26 @@ func (api *PublicAccountManagerAPI) GetBalanceInfo(addr string, coinID types.Coi return nil, fmt.Errorf("Not support %v", coinID) } +func (api *PublicAccountManagerAPI) GetUTXOs(addr string, limit *int, locked *bool) (interface{}, error) { + lt := math.MaxInt + if limit != nil && *limit > 0 { + lt = *limit + } + ret, _, err := api.a.GetUTXOs(addr, <, locked, nil) + return ret, err +} + +func (api *PublicAccountManagerAPI) GetValidUTXOs(addr string, amount uint64) (interface{}, error) { + ret := ValidUTXOsResult{} + locked := false + var err error + if amount <= 0 { + amount = math.MaxUint64 + } + ret.UTXOs, ret.Amount, err = api.a.GetUTXOs(addr, nil, &locked, &amount) + return ret, err +} + func (api *PublicAccountManagerAPI) AddBalance(addr string) (interface{}, error) { return nil, api.a.AddAddress(addr) } diff --git a/services/acct/utils.go b/services/acct/utils.go index d1bc45b4..1e95a123 100644 --- a/services/acct/utils.go +++ b/services/acct/utils.go @@ -1,9 +1,10 @@ package acct type BalanceInfoResult struct { - CoinId string `json:"coinid"` - Balance int64 `json:"balance"` - UTXOs []UTXOResult `json:"utxos,omitempty"` + CoinId string `json:"coinid"` + Balance int64 `json:"balance"` + TotalBalance uint64 `json:"totalbalance,omitempty"` + UTXOs []UTXOResult `json:"utxos,omitempty"` } type UTXOResult struct { @@ -13,3 +14,15 @@ type UTXOResult struct { PreOutIdx uint32 `json:"idx"` Status string `json:"status"` } + +type ValidUTXOsResult struct { + Amount uint64 `json:"amount"` + Num int `json:"total"` + UTXOs []UTXOResult `json:"utxos,omitempty"` +} + +type AcctDebugInfo struct { + Total uint32 `json:"total"` + Watcher uint32 `json:"watcher"` + UtxoWatcher uint32 `json:"utxowatcher"` +} diff --git a/services/wallet/tx.go b/services/wallet/tx.go index f3443541..3768d5e4 100644 --- a/services/wallet/tx.go +++ b/services/wallet/tx.go @@ -80,23 +80,10 @@ func (a *WalletManager) CollectUtxoToEvm() { } func (a *WalletManager) getAvailableUtxos(addr string, amount int64) ([]acct.UTXOResult, int64, error) { - otxoList := make([]acct.UTXOResult, 0) - utxos, err := a.am.GetUTXOs(addr) - if err != nil { - return nil, 0, err - } - sum := uint64(0) - for _, utxo := range utxos { - if utxo.Status != "unlocked" && utxo.Status != "valid" { - continue - } - sum += utxo.Amount - otxoList = append(otxoList, utxo) - if sum > uint64(amount) { - break - } - } - return otxoList, int64(sum), err + locked := false + am := uint64(amount) + utxos, sum, err := a.am.GetUTXOs(addr, nil, &locked, &am) + return utxos, int64(sum), err } func (a *WalletManager) sendTx(fromAddress string, amounts json.AddressAmountV3, targetLockTime, lockTime int64) (string, error) { From a9e6fdab1de6182a7d57100d637ab7525f9d0886 Mon Sep 17 00:00:00 2001 From: Jin Date: Thu, 30 May 2024 20:56:50 +0800 Subject: [PATCH 8/9] Optimize GetValidUTXOs --- services/acct/api.go | 1 + services/acct/utils.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/services/acct/api.go b/services/acct/api.go index 33d8628e..e5838ff8 100644 --- a/services/acct/api.go +++ b/services/acct/api.go @@ -98,6 +98,7 @@ func (api *PublicAccountManagerAPI) GetValidUTXOs(addr string, amount uint64) (i amount = math.MaxUint64 } ret.UTXOs, ret.Amount, err = api.a.GetUTXOs(addr, nil, &locked, &amount) + ret.Total = len(ret.UTXOs) return ret, err } diff --git a/services/acct/utils.go b/services/acct/utils.go index 1e95a123..f8d78903 100644 --- a/services/acct/utils.go +++ b/services/acct/utils.go @@ -17,7 +17,7 @@ type UTXOResult struct { type ValidUTXOsResult struct { Amount uint64 `json:"amount"` - Num int `json:"total"` + Total int `json:"total"` UTXOs []UTXOResult `json:"utxos,omitempty"` } From 156a6f59e58baadb1e19aafedc9c729b3f898dd5 Mon Sep 17 00:00:00 2001 From: Alex Wu Date: Sat, 1 Jun 2024 10:42:00 +0800 Subject: [PATCH 9/9] release qng v1.2.1 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 1a39f59b..1d845722 100644 --- a/version/version.go +++ b/version/version.go @@ -27,7 +27,7 @@ const ( const ( Major uint = 1 Minor uint = 2 - Patch uint = 0 + Patch uint = 1 ) var (