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

api: add address/{address}/exists endpoint #1714

Merged
merged 2 commits into from
Apr 6, 2020

Conversation

buck54321
Copy link
Member

Provides access to the existsaddresses RPC call and parses the result to a []bool. Allows multiple comma-separated addresses to be specified in the same way as the addrs insight endpoints. Limited to 64 addresses, mostly because it simplifies parsing and use of the RPC result.

The dcrd address existence index is enabled by default and seems to be quite fast. I did a little DB testing with the query

SELECT exists(select 1 from addresses where address = a) FROM unnest(ARRAY[...]) AS a;

and it seems to be roughly the same speed on my system and network.

Provides access to the existsaddresses RPC and parses the result.
@chappjc
Copy link
Member

chappjc commented Mar 21, 2020

I prefer RPC these days anyway, so that's good.

Comment on lines +1771 to +1775
mask := binary.LittleEndian.Uint64(append(b, make([]byte, 8-len(b))...))
exists := make([]bool, 0, len(addresses))
for n := range addresses {
exists = append(exists, (mask&(1<<uint8(n))) != 0)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. My only concern is that maxExistAddrs cannot be more than 64 because of this, and there's no check on maxExistAddrs. I worry about someone bumping up maxExistAddrs in the future without understanding it would lead to a panic in make here when >64 addresses get passed, especially because it might appear to work OK in many cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I just document maxExistAddr better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, that's cool. I think a note there not to go beyond 64 without modifying addressExists (or whatever) would be sufficient to prevent future breakage.

Comment on lines 429 to 464
// GetAddressRawCtx returns a slice of addresses parsed from the {address} URL
// parameter. Multiple comma-delimited address strings can be specified.
func GetAddressRawCtx(r *http.Request, activeNetParams *chaincfg.Params, maxAddrs int) ([]dcrutil.Address, error) {
addressStrs, err := addressStrings(r, maxAddrs)
if err != nil {
return nil, err
}
addresses := make([]dcrutil.Address, 0, len(addressStrs))
for _, addrStr := range addressStrs {
addr, err := dcrutil.DecodeAddress(addrStr, activeNetParams)
if err != nil {
return nil, fmt.Errorf("invalid address '%v' for this network: %v",
addrStr, err)
}
addresses = append(addresses, addr)
}
return addresses, nil
}

// addressStrings retrieves the CtxAddress data from the request context. If not
// set, an error is generated. The CtxAddress string data may be a
// comma-separated list of addresses, subject to the maxAddrs limit.
func addressStrings(r *http.Request, maxAddrs int) ([]string, error) {
addressStr, ok := r.Context().Value(CtxAddress).(string)
if !ok || len(addressStr) == 0 {
apiLog.Trace("address not set")
return nil, fmt.Errorf("address not set")
}
addressStrs := strings.Split(addressStr, ",")
if len(addressStrs) > maxAddrs {
return nil, fmt.Errorf("maximum of %d addresses allowed", maxAddrs)
}

return addressStrs, nil
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Good validation. Although I'm thinking it could be even better to have this further up in the request handling chain, where CtxAddress is set (middleware.AddressPathCtx) to preempt the http handlers entirely if any of the addresses are invalid. If this opens a can of worms or becomes a major overhaul of all the /addr/... endpoints, let's skip it though... just a thought.
It's basically the idea applied in the new indent middleware - validate the url bits and call next.ServerHTTP otherwise http.Error so that no other middlewares, subrouters, or any parts of the routed handler actually have to run if validation fails.

Comment on lines -84 to -90
{
testName: "not_set",
args: args{2, nil},
want: nil,
wantErr: true,
errMsg: "address not set",
},
Copy link
Member Author

@buck54321 buck54321 Mar 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not very useful because the URL reduced to "/address/", which would be a different handler so chi was just returning a 404.

@chappjc chappjc merged commit d3b3e2c into decred:master Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants