Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync clarity and eliminate batch vouts.spend_tx_row_id update #1840

Merged
merged 6 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,14 @@ the `dcrdata` executable.

The time required to sync varies greatly with system hardware and software
configuration. The most important factor is the storage medium on the database
machine. An SSD (preferably NVMe, not SATA) is strongly recommended if you value
your time and system performance.
machine. An SSD (preferably NVMe, not SATA) is REQUIRED. The PostgreSQL
operations are extremely disk intensive, especially during the initial
synchronization process. Both high throughput and low latencies for fast
random accesses are essential.

### dcrdata only (PostgreSQL on other host)

Minimum:
Without PostgreSQL, the dcrdata process can get by with:

- 1 CPU core
- 2 GB RAM
Expand All @@ -452,13 +454,13 @@ Minimum:

- 2 CPU core
- 6 GB RAM
- HDD with 120GB free space
- SSD with 120GB free space (no spinning hard drive for the DB!)

Recommend:

- 2+ CPU cores
- 8+ GB RAM
- SSD (NVMe preferred) with 120 GB free space
- 3+ CPU cores
- 12+ GB RAM
- NVMe SSD with 120 GB free space

## dcrdata Daemon

Expand Down
1 change: 0 additions & 1 deletion cmd/dcrdata/explorer/explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ type explorerDataSource interface {
GetBlockHeight(hash string) (int64, error)
GetBlockHash(idx int64) (string, error)
GetExplorerTx(txid string) *types.TxInfo
GetExplorerAddress(address string, count, offset int64) (*dbtypes.AddressInfo, txhelpers.AddressType, txhelpers.AddressError)
GetTip() (*types.WebBasicBlock, error)
DecodeRawTransaction(txhex string) (*chainjson.TxRawResult, error)
SendRawTransaction(txhex string) (string, error)
Expand Down
126 changes: 70 additions & 56 deletions cmd/dcrdata/explorer/explorerroutes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1923,51 +1923,30 @@ func (exp *explorerUI) Search(w http.ResponseWriter, r *http.Request) {
return
}

// Execute search for proposals by both RefID and proposal token before
// the address search because most search strings with alphanumeric
// characters are interprated as addresses.
if exp.proposalsSource != nil {
// Check if the search term references a proposal token exists.
proposalInfo, err := exp.proposalsSource.ProposalByToken(searchStr)

if err != nil || proposalInfo.RefID == "" {
// Check if the search term references a proposal RefID exists.
proposalInfo, err = exp.proposalsSource.ProposalByRefID(searchStr)
}
if err == nil && proposalInfo.RefID != "" {
http.Redirect(w, r, "/proposal/"+proposalInfo.RefID, http.StatusPermanentRedirect)
return
}
}

// Call GetExplorerAddress to see if the value is an address hash and
// then redirect to the address page if it is.
address, _, addrErr := exp.dataSource.GetExplorerAddress(searchStr, 1, 0)
switch addrErr {
case txhelpers.AddressErrorNoError, txhelpers.AddressErrorZeroAddress:
http.Redirect(w, r, "/address/"+searchStr, http.StatusPermanentRedirect)
return
case txhelpers.AddressErrorWrongNet:
// Status page will provide a link, but the address page can too.
message := fmt.Sprintf("The address %v is valid on %s, not %s",
searchStr, address.Net, exp.NetName)
exp.StatusPage(w, wrongNetwork, message, searchStr, ExpStatusWrongNetwork)
return
}

// This is be unnecessarily duplicative and possible very slow for a very
// active addresses.
addrHist, _, _ := exp.dataSource.AddressHistory(searchStr,
1, 0, dbtypes.AddrTxnAll)
if len(addrHist) > 0 {
_, err = dcrutil.DecodeAddress(searchStr, exp.ChainParams)
if err == nil {
http.Redirect(w, r, "/address/"+searchStr, http.StatusPermanentRedirect)
return
}
/*
switch _, _, addrErr := txhelpers.AddressValidation(searchStr, exp.ChainParams); addrErr {
case txhelpers.AddressErrorNoError, txhelpers.AddressErrorZeroAddress: // valid
http.Redirect(w, r, "/address/"+searchStr, http.StatusPermanentRedirect)
return
case txhelpers.AddressErrorWrongNet: // decodes, but wrong network
// Status page will provide a link, but the address page can too.
message := fmt.Sprintf("The address %v is not valid on %s",
searchStr, exp.NetName)
exp.StatusPage(w, wrongNetwork, message, searchStr, ExpStatusWrongNetwork)
return
}
*/

// Split searchStr to the first part corresponding to a transaction hash and
// to the second part corresponding to a transaction output index.
searchStrSplit := strings.Split(searchStr, ":")
searchStrRewritten := searchStrSplit[0]
var utxoLike bool
switch {
case len(searchStrSplit) > 2:
exp.StatusPage(w, "search failed", "Transaction outpoint does not have a valid format: "+searchStr,
Expand All @@ -1976,47 +1955,82 @@ func (exp *explorerUI) Search(w http.ResponseWriter, r *http.Request) {
case len(searchStrSplit) > 1:
if _, err := strconv.ParseUint(searchStrSplit[1], 10, 32); err == nil {
searchStrRewritten = searchStrRewritten + "/out/" + searchStrSplit[1]
utxoLike = true
} else {
exp.StatusPage(w, "search failed", "Transaction output index is not a valid non-negative integer: "+searchStrSplit[1],
"", ExpStatusNotFound)
return
}
}

// Remaining possibilities are hashes, so verify the string is a hash.
tryProp := func() bool {
// Try proposal token.
proposalInfo, err := exp.proposalsSource.ProposalByToken(searchStr)
if err != nil || proposalInfo.RefID == "" {
// Try proposal RefID.
proposalInfo, err = exp.proposalsSource.ProposalByRefID(searchStr)
}
if err == nil && proposalInfo.RefID != "" {
http.Redirect(w, r, "/proposal/"+proposalInfo.RefID, http.StatusPermanentRedirect)
return true
}
return false
}

// If it is not a valid hash, try proposals and give up.
if _, err = chainhash.NewHashFromStr(searchStrSplit[0]); err != nil {
if tryProp() {
return
}
exp.StatusPage(w, "search failed",
"Search string is not a valid hash or address: "+searchStr,
"Search string is not a valid block, tx hash, address, or proposal: "+searchStr,
"", ExpStatusNotFound)
return
}

// Attempt to get a block index by calling GetBlockHeight to see if the
// value is a block hash and then redirect to the block page if it is.
_, err = exp.dataSource.GetBlockHeight(searchStrSplit[0])
if err == nil {
http.Redirect(w, r, "/block/"+searchStrSplit[0], http.StatusPermanentRedirect)
return
// A valid hash could be block, txid, or prop. First try blocks, then tx via
// getrawtransaction, then props, then tx via DB query.

if !utxoLike {
// Attempt to get a block index by calling GetBlockHeight to see if the
// value is a block hash and then redirect to the block page if it is.
_, err = exp.dataSource.GetBlockHeight(searchStrSplit[0])
if err == nil {
http.Redirect(w, r, "/block/"+searchStrSplit[0], http.StatusPermanentRedirect)
return
}
}

// It's unlikely to be a tx id with many leading/trailing zeros.
trimmedZeros := 2*chainhash.HashSize - len(strings.Trim(searchStrSplit[0], "0"))

// Call GetExplorerTx to see if the value is a transaction hash and then
// redirect to the tx page if it is.
tx := exp.dataSource.GetExplorerTx(searchStrSplit[0])
if tx != nil {
http.Redirect(w, r, "/tx/"+searchStrRewritten, http.StatusPermanentRedirect)
return
if trimmedZeros < 10 {
tx := exp.dataSource.GetExplorerTx(searchStrSplit[0])
if tx != nil {
http.Redirect(w, r, "/tx/"+searchStrRewritten, http.StatusPermanentRedirect)
return
}
}

// Also check the aux DB as it may have transactions from orphaned blocks.
dbTxs, err := exp.dataSource.Transaction(searchStrSplit[0])
if err != nil && !errors.Is(err, dbtypes.ErrNoResult) {
log.Errorf("Searching for transaction failed: %v", err)
}
if dbTxs != nil {
http.Redirect(w, r, "/tx/"+searchStrRewritten, http.StatusPermanentRedirect)
// Before checking the DB for txns in orphaned blocks, try props.
if tryProp() {
return
}

// Also check the DB as it may have transactions from orphaned blocks.
if trimmedZeros < 10 {
dbTxs, err := exp.dataSource.Transaction(searchStrSplit[0])
if err != nil && !errors.Is(err, dbtypes.ErrNoResult) {
log.Errorf("Searching for transaction failed: %v", err)
}
if dbTxs != nil {
http.Redirect(w, r, "/tx/"+searchStrRewritten, http.StatusPermanentRedirect)
return
}
}

message := "The search did not find any matching address, block, transaction or proposal token: " + searchStr
exp.StatusPage(w, "search failed", message, "", ExpStatusNotFound)
}
Expand Down
Loading