Use the correct synced block when calculating confs.
This was previously using the most recently notified (by the chain package) block, but transaction processing from this block may not be finished yet. Using this block's height to calculate the number of confirmations is therefore incorrect, and can result in every RPC handler missing transactions or returning transactions from the wrong block.
This commit is contained in:
parent
c9d9b4b610
commit
5ad37374fb
2 changed files with 31 additions and 78 deletions
57
rpcserver.go
57
rpcserver.go
|
@ -1057,13 +1057,8 @@ func (b blockDisconnected) notificationCmds(w *Wallet) []btcjson.Cmd {
|
|||
}
|
||||
|
||||
func (c txCredit) notificationCmds(w *Wallet) []btcjson.Cmd {
|
||||
bs, err := w.chainSvr.BlockStamp()
|
||||
if err != nil {
|
||||
log.Warnf("Dropping tx credit notification due to unknown "+
|
||||
"chain height: %v", err)
|
||||
return nil
|
||||
}
|
||||
ltr, err := txstore.Credit(c).ToJSON("", bs.Height, activeNet.Params)
|
||||
blk := w.Manager.SyncedTo()
|
||||
ltr, err := txstore.Credit(c).ToJSON("", blk.Height, activeNet.Params)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot create notification for transaction "+
|
||||
"credit: %v", err)
|
||||
|
@ -1074,13 +1069,8 @@ func (c txCredit) notificationCmds(w *Wallet) []btcjson.Cmd {
|
|||
}
|
||||
|
||||
func (d txDebit) notificationCmds(w *Wallet) []btcjson.Cmd {
|
||||
bs, err := w.chainSvr.BlockStamp()
|
||||
if err != nil {
|
||||
log.Warnf("Dropping tx debit notification due to unknown "+
|
||||
"chain height: %v", err)
|
||||
return nil
|
||||
}
|
||||
ltrs, err := txstore.Debits(d).ToJSON("", bs.Height, activeNet.Params)
|
||||
blk := w.Manager.SyncedTo()
|
||||
ltrs, err := txstore.Debits(d).ToJSON("", blk.Height, activeNet.Params)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot create notification for transaction "+
|
||||
"debits: %v", err)
|
||||
|
@ -1961,10 +1951,7 @@ func GetTransaction(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interf
|
|||
return nil, btcjson.ErrNoTxInfo
|
||||
}
|
||||
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
var txBuf bytes.Buffer
|
||||
txBuf.Grow(record.Tx().MsgTx().SerializeSize())
|
||||
|
@ -1991,7 +1978,7 @@ func GetTransaction(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interf
|
|||
ret.BlockIndex = int64(record.Tx().Index())
|
||||
ret.BlockHash = txBlock.Hash.String()
|
||||
ret.BlockTime = txBlock.Time.Unix()
|
||||
ret.Confirmations = int64(record.Confirmations(bs.Height))
|
||||
ret.Confirmations = int64(record.Confirmations(blk.Height))
|
||||
}
|
||||
|
||||
credits := record.Credits()
|
||||
|
@ -2042,7 +2029,7 @@ func GetTransaction(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interf
|
|||
|
||||
ret.Details = append(ret.Details, btcjson.GetTransactionDetailsResult{
|
||||
Account: "",
|
||||
Category: cred.Category(bs.Height).String(),
|
||||
Category: cred.Category(blk.Height).String(),
|
||||
Amount: cred.Amount().ToUnit(btcutil.AmountBTC),
|
||||
Address: addr,
|
||||
})
|
||||
|
@ -2087,10 +2074,7 @@ func ListLockUnspent(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (inter
|
|||
func ListReceivedByAccount(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interface{}, error) {
|
||||
cmd := icmd.(*btcjson.ListReceivedByAccountCmd)
|
||||
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
// Total amount received.
|
||||
var amount btcutil.Amount
|
||||
|
@ -2100,12 +2084,12 @@ func ListReceivedByAccount(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd)
|
|||
|
||||
for _, record := range w.TxStore.Records() {
|
||||
for _, credit := range record.Credits() {
|
||||
if !credit.Confirmed(cmd.MinConf, bs.Height) {
|
||||
if !credit.Confirmed(cmd.MinConf, blk.Height) {
|
||||
// Not enough confirmations, skip the current block.
|
||||
continue
|
||||
}
|
||||
amount += credit.Amount()
|
||||
confirmations = credit.Confirmations(bs.Height)
|
||||
confirmations = credit.Confirmations(blk.Height)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2143,10 +2127,7 @@ func ListReceivedByAddress(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd)
|
|||
tx []string
|
||||
}
|
||||
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
// Intermediate data for all addresses.
|
||||
allAddrData := make(map[string]AddrData)
|
||||
|
@ -2164,8 +2145,8 @@ func ListReceivedByAddress(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd)
|
|||
}
|
||||
for _, record := range w.TxStore.Records() {
|
||||
for _, credit := range record.Credits() {
|
||||
confirmations := credit.Confirmations(bs.Height)
|
||||
if !credit.Confirmed(cmd.MinConf, bs.Height) {
|
||||
confirmations := credit.Confirmations(blk.Height)
|
||||
if !credit.Confirmed(cmd.MinConf, blk.Height) {
|
||||
// Not enough confirmations, skip the current block.
|
||||
continue
|
||||
}
|
||||
|
@ -2228,20 +2209,14 @@ func ListSinceBlock(w *Wallet, chainSvr *chain.Client, icmd btcjson.Cmd) (interf
|
|||
height = int32(block.Height())
|
||||
}
|
||||
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
// For the result we need the block hash for the last block counted
|
||||
// in the blockchain due to confirmations. We send this off now so that
|
||||
// it can arrive asynchronously while we figure out the rest.
|
||||
gbh := chainSvr.GetBlockHashAsync(int64(bs.Height) + 1 - int64(cmd.TargetConfirmations))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gbh := chainSvr.GetBlockHashAsync(int64(blk.Height) + 1 - int64(cmd.TargetConfirmations))
|
||||
|
||||
txInfoList, err := w.ListSinceBlock(height, bs.Height,
|
||||
txInfoList, err := w.ListSinceBlock(height, blk.Height,
|
||||
cmd.TargetConfirmations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
52
wallet.go
52
wallet.go
|
@ -717,12 +717,8 @@ func (w *Wallet) AddressUsed(addr waddrmgr.ManagedAddress) bool {
|
|||
// the balance will be calculated based on how many how many blocks
|
||||
// include a UTXO.
|
||||
func (w *Wallet) CalculateBalance(confirms int) (btcutil.Amount, error) {
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return w.TxStore.Balance(confirms, bs.Height)
|
||||
blk := w.Manager.SyncedTo()
|
||||
return w.TxStore.Balance(confirms, blk.Height)
|
||||
}
|
||||
|
||||
// CurrentAddress gets the most recently requested Bitcoin payment address
|
||||
|
@ -782,16 +778,13 @@ func (w *Wallet) ListTransactions(from, count int) ([]btcjson.ListTransactionsRe
|
|||
|
||||
// Get current block. The block height used for calculating
|
||||
// the number of tx confirmations.
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return txList, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
records := w.TxStore.Records()
|
||||
lastLookupIdx := len(records) - count
|
||||
// Search in reverse order: lookup most recently-added first.
|
||||
for i := len(records) - 1; i >= from && i >= lastLookupIdx; i-- {
|
||||
jsonResults, err := records[i].ToJSON("", bs.Height,
|
||||
jsonResults, err := records[i].ToJSON("", blk.Height,
|
||||
w.Manager.ChainParams())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -812,10 +805,7 @@ func (w *Wallet) ListAddressTransactions(pkHashes map[string]struct{}) (
|
|||
|
||||
// Get current block. The block height used for calculating
|
||||
// the number of tx confirmations.
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return txList, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
for _, r := range w.TxStore.Records() {
|
||||
for _, c := range r.Credits() {
|
||||
|
@ -833,7 +823,7 @@ func (w *Wallet) ListAddressTransactions(pkHashes map[string]struct{}) (
|
|||
if _, ok := pkHashes[string(apkh.ScriptAddress())]; !ok {
|
||||
continue
|
||||
}
|
||||
jsonResult, err := c.ToJSON("", bs.Height,
|
||||
jsonResult, err := c.ToJSON("", blk.Height,
|
||||
w.Manager.ChainParams())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -853,15 +843,12 @@ func (w *Wallet) ListAllTransactions() ([]btcjson.ListTransactionsResult, error)
|
|||
|
||||
// Get current block. The block height used for calculating
|
||||
// the number of tx confirmations.
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return txList, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
// Search in reverse order: lookup most recently-added first.
|
||||
records := w.TxStore.Records()
|
||||
for i := len(records) - 1; i >= 0; i-- {
|
||||
jsonResults, err := records[i].ToJSON("", bs.Height,
|
||||
jsonResults, err := records[i].ToJSON("", blk.Height,
|
||||
w.Manager.ChainParams())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -882,10 +869,7 @@ func (w *Wallet) ListUnspent(minconf, maxconf int,
|
|||
|
||||
results := []*btcjson.ListUnspentResult{}
|
||||
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
filter := len(addresses) != 0
|
||||
|
||||
|
@ -895,12 +879,12 @@ func (w *Wallet) ListUnspent(minconf, maxconf int,
|
|||
}
|
||||
|
||||
for _, credit := range unspent {
|
||||
confs := credit.Confirmations(bs.Height)
|
||||
confs := credit.Confirmations(blk.Height)
|
||||
if int(confs) < minconf || int(confs) > maxconf {
|
||||
continue
|
||||
}
|
||||
if credit.IsCoinbase() {
|
||||
if !credit.Confirmed(blockchain.CoinbaseMaturity, bs.Height) {
|
||||
if !credit.Confirmed(blockchain.CoinbaseMaturity, blk.Height) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -1245,10 +1229,7 @@ func (w *Wallet) NewChangeAddress() (btcutil.Address, error) {
|
|||
// total amount of bitcoins received for any wallet address. Amounts received
|
||||
// through multisig transactions are ignored.
|
||||
func (w *Wallet) TotalReceived(confirms int) (btcutil.Amount, error) {
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
var amount btcutil.Amount
|
||||
for _, r := range w.TxStore.Records() {
|
||||
|
@ -1259,7 +1240,7 @@ func (w *Wallet) TotalReceived(confirms int) (btcutil.Amount, error) {
|
|||
}
|
||||
|
||||
// Tally if the appropiate number of block confirmations have passed.
|
||||
if c.Confirmed(confirms, bs.Height) {
|
||||
if c.Confirmed(confirms, blk.Height) {
|
||||
amount += c.Amount()
|
||||
}
|
||||
}
|
||||
|
@ -1271,16 +1252,13 @@ func (w *Wallet) TotalReceived(confirms int) (btcutil.Amount, error) {
|
|||
// returning the total amount of bitcoins received for a single wallet
|
||||
// address.
|
||||
func (w *Wallet) TotalReceivedForAddr(addr btcutil.Address, confirms int) (btcutil.Amount, error) {
|
||||
bs, err := w.SyncedChainTip()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
blk := w.Manager.SyncedTo()
|
||||
|
||||
addrStr := addr.EncodeAddress()
|
||||
var amount btcutil.Amount
|
||||
for _, r := range w.TxStore.Records() {
|
||||
for _, c := range r.Credits() {
|
||||
if !c.Confirmed(confirms, bs.Height) {
|
||||
if !c.Confirmed(confirms, blk.Height) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue