From 6c79b06aba7011bd59bbed1e959db246648d8092 Mon Sep 17 00:00:00 2001 From: Donald Adu-Poku Date: Wed, 22 May 2019 13:58:20 +0000 Subject: [PATCH 1/2] wallet: deprecate exported header extraction funcs This deprecates udb.ExtractBlockHeaderParentHash and udb.ExtractBlockHeaderHeight in preference of using an unexported copy of the extract function at the call site. --- wallet/rescan.go | 17 ++++++++++++++++- wallet/udb/txmined.go | 6 +++--- wallet/wallet.go | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/wallet/rescan.go b/wallet/rescan.go index ca417baf4..afaffe32d 100644 --- a/wallet/rescan.go +++ b/wallet/rescan.go @@ -6,6 +6,7 @@ package wallet import ( + "encoding/binary" "context" "time" @@ -62,6 +63,20 @@ func NewRescanFilter(addresses []dcrutil.Address, unspentOutPoints []*wire.OutPo return filter } +// extractBlockHeaderHeight fetches the block height from wire encoded block +// header bytes. +func extractBlockHeaderHeight(header []byte) int32 { + const heightOffset = 128 + return int32(binary.LittleEndian.Uint32(header[heightOffset:])) +} + +// extractBlockHeaderUnixTime fetches the unix timestamp from wire encoded +// block header bytes. +func extractBlockHeaderUnixTime(header []byte) uint32 { + const timestampOffset = 136 + return binary.LittleEndian.Uint32(header[timestampOffset:]) +} + // AddAddress adds an address to the filter if it does not already exist. func (f *RescanFilter) AddAddress(a dcrutil.Address) { switch a := a.(type) { @@ -269,7 +284,7 @@ func (w *Wallet) Rescan(ctx context.Context, n NetworkBackend, startHash *chainh if err != nil { return err } - startHeight = udb.ExtractBlockHeaderHeight(header) + startHeight = extractBlockHeaderHeight(header) return nil }) if err != nil { diff --git a/wallet/udb/txmined.go b/wallet/udb/txmined.go index 9ca551ab0..de1f00fa5 100644 --- a/wallet/udb/txmined.go +++ b/wallet/udb/txmined.go @@ -458,7 +458,7 @@ func extractBlockHeaderParentHash(header []byte) []byte { // ExtractBlockHeaderParentHash subslices the header to return the bytes of the // parent block's hash. Must only be called on known good input. // -// TODO: This really should not be exported by this package. +// DEPRECATED: to be removed in the next major release. func ExtractBlockHeaderParentHash(header []byte) []byte { return extractBlockHeaderParentHash(header) } @@ -476,7 +476,7 @@ func extractBlockHeaderHeight(header []byte) int32 { // ExtractBlockHeaderHeight returns the height field that is encoded in the // header. Must only be called on known good input. // -// TODO: This really should not be exported by this package. +// DEPRECATED: to be removed in the next major release. func ExtractBlockHeaderHeight(header []byte) int32 { return extractBlockHeaderHeight(header) } @@ -490,7 +490,7 @@ func extractBlockHeaderUnixTime(header []byte) uint32 { // header. Must only be called on known good input. Header timestamps are only // 4 bytes and this value is actually limited to a maximum unix time of 2^32-1. // -// TODO: This really should not be exported by this package. +// DEPRECATED: to be removed in the next major release. func ExtractBlockHeaderTime(header []byte) int64 { return int64(extractBlockHeaderUnixTime(header)) } diff --git a/wallet/wallet.go b/wallet/wallet.go index bdae68e61..1da2aa413 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -2223,7 +2223,7 @@ func (w *Wallet) BlockInfo(blockID *BlockIdentifier) (*BlockInfo, error) { if err != nil { return err } - height := udb.ExtractBlockHeaderHeight(header) + height := extractBlockHeaderHeight(header) inMainChain, invalidated := w.TxStore.BlockInMainChain(dbtx, blockHash) var confs int32 if inMainChain { @@ -2234,7 +2234,7 @@ func (w *Wallet) BlockInfo(blockID *BlockIdentifier) (*BlockInfo, error) { Height: height, Confirmations: confs, Header: header, - Timestamp: udb.ExtractBlockHeaderTime(header), + Timestamp: int64(extractBlockHeaderUnixTime(header)), StakeInvalidated: invalidated, } return nil From 778b5a2d2c943b466a67ef174bd3b019117f15a0 Mon Sep 17 00:00:00 2001 From: Donald Adu-Poku Date: Mon, 10 Jun 2019 16:54:19 +0000 Subject: [PATCH 2/2] udb: use a credit iterator for detached credits. This uses a credit iterator for converting detached and unspent non-coinbase credits to unmined credit. --- wallet/udb/txmined.go | 61 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/wallet/udb/txmined.go b/wallet/udb/txmined.go index de1f00fa5..d36a12164 100644 --- a/wallet/udb/txmined.go +++ b/wallet/udb/txmined.go @@ -1984,39 +1984,39 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBuc // credit output to unmined. If the credit is marked // unspent, it is removed from the utxo set and the // mined balance is decremented. - // - // TODO: use a credit iterator - for i, output := range rec.MsgTx.TxOut { - k, v := existsCredit(ns, &rec.Hash, uint32(i), - &b.Block) - if v == nil { - continue + k := keyTxRecord(&rec.Hash, &b.Block) + credIter := makeReadCreditIterator(ns, k, DBVersion) + defer credIter.close() + for credIter.next() { + if int(credIter.elem.Index) >= len(rec.MsgTx.TxOut) { + credIter.close() + return errors.E(errors.IO, + "saved credit index exceeds number of outputs") } - vcopy := make([]byte, len(v)) - copy(vcopy, v) - removedCredits[string(k)] = vcopy - amt, change, err := fetchRawCreditAmountChange(v) + // scrType := pkScriptType(output.PkScript) + scrPos := fetchRawCreditScriptOffset(credIter.cv) + scrLen := fetchRawCreditScriptLength(credIter.cv) + + pkScript, err := fetchRawTxRecordPkScript(credIter.ck, + credIter.cv, credIter.elem.Index, scrPos, scrLen) if err != nil { return err } - opCode := fetchRawCreditTagOpCode(v) - isCoinbase := fetchRawCreditIsCoinbase(v) - hasExpiry := fetchRawCreditHasExpiry(v, DBVersion) - scrType := pkScriptType(output.PkScript) - scrLoc := rec.MsgTx.PkScriptLocs()[i] - scrLen := len(rec.MsgTx.TxOut[i].PkScript) - - acct, err := s.fetchAccountForPkScript(addrmgrNs, v, nil, output.PkScript) + acct, err := s.fetchAccountForPkScript(addrmgrNs, credIter.cv, + nil, pkScript) if err != nil { return err } - outPointKey := canonicalOutPoint(&rec.Hash, uint32(i)) - unminedCredVal := valueUnminedCredit(amt, change, opCode, - isCoinbase, hasExpiry, scrType, uint32(scrLoc), uint32(scrLen), - acct, DBVersion) + scrType := pkScriptType(pkScript) + scrLoc := rec.MsgTx.PkScriptLocs()[credIter.elem.Index] + outPointKey := canonicalOutPoint(&rec.Hash, credIter.elem.Index) + unminedCredVal := valueUnminedCredit(credIter.elem.Amount, + credIter.elem.Change, credIter.elem.OpCode, + credIter.elem.IsCoinbase, credIter.elem.HasExpiry, scrType, + uint32(scrLoc), uint32(scrLen), acct, DBVersion) err = putRawUnminedCredit(ns, outPointKey, unminedCredVal) if err != nil { return err @@ -2031,9 +2031,10 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBuc if credKey != nil { // Ticket amounts were never added, so ignore them when // correcting the balance. - isTicketOutput := (txType == stake.TxTypeSStx && i == 0) + isTicketOutput := (txType == stake.TxTypeSStx && + credIter.elem.Index == 0) if !isTicketOutput { - minedBalance -= dcrutil.Amount(output.Value) + minedBalance -= credIter.elem.Amount } err = deleteRawUnspent(ns, outPointKey) if err != nil { @@ -2041,10 +2042,9 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBuc } } - // Check if this output is a multisignature - // P2SH output. If it is, access the value - // for the key and mark it unmined. - msKey := keyMultisigOut(*txHash, uint32(i)) + // Check if this output is a multisignature P2SH output. + // If it is, access the value for the key and mark it unmined. + msKey := keyMultisigOut(*txHash, uint32(credIter.elem.Index)) msVal := existsMultisigOutCopy(ns, msKey) if msVal != nil { setMultisigOutUnmined(msVal) @@ -2054,6 +2054,9 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, addrmgrNs walletdb.ReadBuc } } } + if credIter.err != nil { + return credIter.err + } // When rolling back votes and revocations, return unspent status // for tracked commitments.