Commit graph

61 commits

Author SHA1 Message Date
Tomás Senart
f439dece37 Use chan struct{} for semaphores
With semaphores we don't actually care about the value passed in. It
makes sense to use a 0 bytes type in these cases.
There is also the added benefit of compiler optimisations for this
specific use case as described here:
https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub
2014-07-02 19:06:32 -05:00
Tomás Senart
cc2c486791 Replace map[a]bool with map[a]struct{}
The later uses no memory storage for values and provides the same
functionality.
2014-07-02 19:06:29 -05:00
Tomás Senart
84fa553b65 Split imports into logical groups 2014-07-02 15:56:41 +02:00
Dave Collins
d40cff64b0 Expose a close ntfn channel to all RPC handlers.
This commit modifies the RPC server such that all handlers now receive a
channel which will be notified when a client disconnects.  This
notification can then be used to stop long-running operations early when a
client disconnects.

This capability was already present for websocket clients, but this commit
exposes it to standard HTTP clients as well.
2014-06-27 11:58:47 -05:00
Josh Rickmar
6dc257b8c8 Notify websocket clients of finished rescans.
ok @davecgh
2014-06-16 14:48:52 -05:00
Dave Collins
3266bf6a8d Convert to use gorilla websockets package.
Also, since the new websoscket package allows the message type to be set
independently from the type of the variable, remove the casts between
strings and []byte in the websocket read/write paths.  This avoids extra
copies thereby reducing the garbage generated.

Closes #134.
2014-06-07 01:34:33 -05:00
Josh Rickmar
74303966c0 Updates for btcutil and btcscript's btcnet conversion.
ok @davecgh
2014-05-27 17:44:55 -05:00
Josh Rickmar
bcc78565fd Initial pass at updating to btcnet.
This change modifies the params struct to embed a *btcnet.Params,
removing the old parameter fields that are handled by the btcnet
package.

Hardcoded network checks have also been removed in favor of modifying
behavior based on the current active net's parameters.

Not all library packages, notable btcutil and btcchain, have been
updated to use btcnet yet, but with this change, each package can be
updated one at a time since the active net's btcnet.Params are
available at each callsite.

ok @davecgh
2014-05-23 01:02:14 -05:00
Dave Collins
5b376b3b5e Expose getcurrentnet and getbestblock to HTTP POST.
This commit makes the getcurrentnet and getbestblock RPCs available to
clients making HTTP POST requests.

Closes #127.
2014-05-11 02:21:27 -05:00
Josh Rickmar
a20fd1ab2c Modify notifyspent handler to take multiple outpoints. 2014-05-06 08:30:36 -05:00
Dave Collins
a38f93bf06 use fastsha256 in rpcwebsocket.go.
While this is not performance critical code, there is no need to import
another package into the final binary.
2014-05-01 10:36:41 -05:00
Josh Rickmar
bba0a0482d Include P2PK outputs for rescanned P2PKH addrs.
This change fixes rescan to include transactions that pay to the
pubkey for a rescanned pubkey hash address.  This behavior was lost
when the rescan was optimized for specific types of the
btcutil.Address interface.

ok @davecgh
2014-04-25 10:33:58 -05:00
Dave Collins
27082ace79 Correct error handling on createMarshalledReply.
This commit correctly sets the error in the marhsalled reply if it is
already a *btcjson.Error.  Previously it would only set the error if it
was not of that type which led to some RPC results showing no error when
they actually had one.
2014-04-25 02:51:57 -05:00
Josh Rickmar
f88db561f1 Make rescan faster by avoiding hash copies.
Copying the RIPEMD160 after SHA256 hash result into a new stack array
to be used as a map lookup key can be quite expensive, and this should
be avoided if possible on intensive tasks such as rescans.  This
change takes advantage of the new Hash160 methods of the
AddressPubKeyHash and AddressScriptHash types to use the address's
underlying hash array directly, rather than creating a copy from the
ScriptAddress result.

Unfortunately, for AddressPubKey, ScriptAddress may return either a
byte slice of len 33 or 65 depending on whether the pubkey is
compressed or not, so no such straightforward optimization is
possible.

As a result of this change, I have seen rescans perform roughly 3.5x
faster than before.
2014-04-20 21:16:59 -05:00
Dave Collins
a4673597bd Update for notifyallnewtxs rename.
The websocket extension command to register for notifications when a new
transaction has been accepted to the memory pool and the resulting
notifications have been renamed.  This commit catches up to the change.
2014-04-15 12:22:52 -05:00
Dave Collins
05a7979292 Update for notifynewtxs to notifyreceived rename.
The websocket extension command to register for notifications when an
address receives funds has been renamed.  This commit catches up to the
change.
2014-04-14 19:11:08 -05:00
Josh Rickmar
42061ebf87 Update for btcws API change. 2014-04-10 21:12:40 -05:00
Josh Rickmar
1fd5cd2742 Use btcws.GetBestBlockResult. 2014-04-10 20:03:54 -05:00
Josh Rickmar
d702e37141 Update websocket clients with rescan progress.
This change periodically (about every 10 seconds) notifies the
connected websocket client of the height of the last processed block
as part of the rescan.  This enables clients to listen for the
notification and keep track of how much progress a rescan has made
even without any results being found.  If the websocket connection is
lost during the rescan, on reconnect, clients may safely start over at
the last notified height.
2014-03-28 11:27:29 -05:00
Josh Rickmar
29dd411457 Prevent blocking on RPC server messages after shutdown.
This change adds select statements to each channel write that may
occur from a non-RPCS goroutine to unblock once the server has begun
shutting down.  This prevents issues in clean shutdown where non-RPCS
goroutines may block indefinitely on message sends to the RPC server.
2014-03-21 18:07:36 -05:00
Josh Rickmar
715fd22de9 Bootstrap unspents with rescan request's outpoints. 2014-03-21 15:43:31 -05:00
Josh Rickmar
de31674a8d Optimize rescan.
This change adds rescan fast paths for all current implementations of
the btcutil.Address interface.  Rather than encoding a payment address
string from a txout script, the minimum number of bytes (which depends
on the address type) are copied into a stack array and used as a
lookup key to a map exclusive for that address type.  This performs
better than the previous implementation due to avoiding the base58
encoding and generating less garbage (so each GC cycle completes
faster).

If the address type switch falls into the default (unhandled) case,
the encoded payment address is used as a fallback.  This keeps the
intended rescan behavior even when new implementations of
btcutil.Address are added without a rescan fast path.

Benchmarks indicate that when a fast path is followed, for 20 byte
RIPEMD-160 hashes (such as P2PKH and P2SH), skipping the payment
address encoding (and thus bypassing the base58 encoding code) can
result in map lookups up to 60x faster.
2014-03-21 10:54:37 -05:00
David Hill
eecea4180a Preallocate the tx serialization buffer.
Benchmarking shows this is slightly faster due to avoiding the extra
garbage collection in addition to less peak memory usage.

ok @davecgh
2014-03-20 15:33:09 -04:00
Dave Collins
3b9b11cb41 Update for recent btcutil.Address API change. 2014-03-18 20:44:03 -05:00
Francis Lam
33af740985 Added missing notificationMsg types to notificationHandler 2014-03-04 21:36:48 -05:00
Josh Rickmar
27f3d916ec Do not block removing clients if notification manager quit. 2014-03-04 11:31:44 -05:00
Josh Rickmar
a7d5b365b1 Retain order when processing client notifications.
This change modifies the RPC server's notifiation manager from a
struct with requests, protected by a mutux, to two goroutines.  The
first maintains a queue of all notifications and control requests
(registering/unregistering notifications), while the second reads from
the queue and processes notifications and requests one at a time.

Previously, to prevent slowing down block and mempool processing, each
notification would be handled by spawning a new goroutine.  This lead
to cases where notifications would end up being sent to clients in a
different order than they were created.  Adding a queue keeps the
order of notifications originating from the same goroutine, while also
not slowing down processing while waiting for notifications to be
processed and sent.

ok @davecgh
2014-03-04 11:15:25 -05:00
Dave Collins
8c7c1e84a3 Use mtx to control disconnect of websocket client.
This commit changes the websocket client code to use a mutex for
disconnect since it's theoretically possible a non-blocking select on the
quit channel could fall through from two different goroutines thus causing
a second call to close.

ok @jrick.
2014-02-25 12:50:32 -06:00
Josh Rickmar
0c6d7bbeae Improve websocket transaction notifications.
This change improves the mechanism by which btcd notifies a websocket
client of transaction relating to watched address and unspent outputs
in the following ways:

1. The old processedtx notification has been replaced with the new
   recvtx notification.  This notification, rather than parsing out
   details used by wallet clients, sends the serialized transaction
   (as hexadecimal) and any block details (if mined) if any transaction
   output sends to one of the websocket client's watched addresses.

2. The old txspent notification has been replaced with the new
   redeemingtx notification.  This notification, rather than parsing
   out details used by wallet clients, sends the serialized transaction
   (as hexadecimal) and any block details (if mined) if any transaction
   input spends a watched output.

3. When processing notifications for transaction outputs, if any output
   spends to a client's watched address, a corresponding spent request
   is automatically registered.

4. Transaction notifications originating from mempool now include both
   transaction inputs and outputs, rather than only processing

5. When processing notifications for transaction inputs, a client's
   output spent request is only removed if the transaction being
   processed has also been mined into a block.  In combination with the
   4th change, this results in two redeemingtx notifications for
   transactions which first appear in mempool and are subsequently mined
   into a block.
2014-02-24 13:17:57 -05:00
Dave Collins
8ac86f1053 Allow notifications to work for all address types.
Previously the websocket notifications for addresses were limited to
pay-to-pubkey-hash only.  This commit removes that restriction so
all btcutil.Address types are supported.  This includes pay-to-pubkey,
pay-to-pubkey-hash, and pay-to-script-hash.
2014-02-19 09:47:17 -06:00
Dave Collins
7162a11995 Remove tracking requests from websocket client too.
When a spent notification and address notification is removed, the
tracking entry in the client which is used to track what to remove on
shutdown needs to be removed as well.
2014-02-19 09:14:11 -06:00
Dave Collins
7d35bc9460 Add --rpcmaxwebsockets option with default of 25.
This commit adds a new configuration option, --rpcmaxwebsockets, to limit the
number of max RPC websocket clients that are served concurrently.
2014-02-19 00:53:14 -06:00
Dave Collins
54203d7db0 Rework and improve websocket notification system.
This commit refactors the entire websocket client code to resolve several
issues with the previous implementation.  Note that this commit does not
change the public API for websockets.  It only consists of internal
improvements.

The following is the major issues which have been addressed:
- A slow websocket client could impede notifications to all clients
- Long-running operations such as rescans would block all other requests
  until it had completed
- The above two points taken together could lead to apparant hangs since
  the client doing the rescan would eventually run out of channel buffer
  and block the entire group of clients until the rescan completed
- Disconnecting a websocket during certain operations could lead to a hang
- Stopping the rpc server with operations under way could lead to a hang
- There were no limits to the number of websocket clients that could
  connect

The following is a summary of the major changes:

- The websocket code has been split into two entities: a
  connection/notification manager and a websocket client
- The new connection/notification manager acts as the entry point from
  the rest of the subsystems to feed data which potentially needs to
  notify clients
- Each websocket client now has its own instance of the new websocket
  client type which controls its own lifecycle
- The data flow has been completely redesigned to closely resemble the
  peer data flow
- Each websocket now has its own long-lived goroutines for input, output,
  and queuing of notifications
- Notifications use the new notification queue goroutine along with
  queueing to ensure they dont't block on stalled or slow peers
- There is a new infrastructure for asynchronously executing long-running
  commands such as a rescan while still allowing the faster operations to
  continue to be serviced by the same client
- Since long-running operations now run asynchronously, they have been
  limited to one at a time
- Added a limit of 10 websocket clients.  This is hard coded for now, but
  will be made configurable in the future

Taken together these changes make the code far easier to reason about and
update as well solve the aforementioned issues.

Further optimizations to improve performance are possible in regards to
the way the connection/notification manager works, however this commit
already contains a ton of changes, so they are being left for another
time.
2014-02-19 00:53:05 -06:00
Francis Lam
9306270a84 Fixed wsContext locking problems in NewBlockNotifyCheckTxIn
The wsContext was being locked twice when NewBlockNotifyCheckTxIn is
called.  Fixed by changing handlers to assume lock is acquired and
renamed methods to not be exported.
2014-02-13 16:13:58 -05:00
Francis Lam
4431fd9c0d Added checking for closed connections in websocket handler helpers
Since the websocket handlers run in their own separate goroutines, it's
possible that they execute after the websocket connection has been
closed and cleaned up.  This commit add the necessary checks to ensure
stale data isn't added to notification lists and that requests to closed
connections are ignored.

This closes #92.
2014-02-11 22:39:11 -05:00
Francis Lam
1d60e5dba5 Fixed data races in rpcwebsocket Notify functions
Access to connections map and associated notification maps in rpcServer
need to be protected with s.ws.Lock to prevent race with add/remove new
clients.

This closes #88.
2014-02-10 10:34:26 -05:00
Francis Lam
354cc38d2d Added comments for new AddAllNewTxRequest method 2014-02-08 18:01:27 -05:00
Francis Lam
b89e93e52f Added notifyallnewtxs custom websocket command
Changed mempool.MaybeAcceptTransaction to accept an additional parameter
to differentiate betwee new transactions and those added from
disconnected blocks.

Added new fields to requestContexts to indicate which clients want to
receive all new transaction notifications.

Added NotifyForNewTx to rpcServer to deliver approriate transaction
notification.
2014-02-08 17:15:17 -05:00
Dave Collins
bcb5a21b37 Add comment to ErrBadAuth to make go lint happy. 2014-02-04 15:37:34 -06:00
Josh Rickmar
8f43dc758e Fix build. 2014-01-22 21:21:05 -05:00
Dave Collins
0d40bf901d Implement alternative auth for websockets.
The previous websocket code required HTTP auth headers to be sent in order
to use the websocket.  While this makes sense for most applications, some
use cases such as javascript-based websockets from browsers do no have the
ability to send headers.

This commit modifies the authentication logic to allow an alternative
authentication mechanism when HTTP auth headers can't be sent.  In
particular, it introduces a new JSON-RPC command named authenticate which
accepts the username and passphrase for the RPC server.  The command is
only required if the connetion has not already been authenticated via HTTP
auth headers and it must be the first command to be received.  Sending any
other command will immediately disconnect the websocket.

ok from @owainga and @jrick.

This closes #77.
2014-01-22 17:40:14 -06:00
Josh Rickmar
d3e4bcdcf5 Fix sendrawtransaction for websockets.
This fixes two issues: first, the sendrawtransaction handler had an
extra character in the key in the websocket handler map, preventing
the handler from never running.  Second, a nil pointer dereference was
removed from the handler.

This change fixes the minedtx notifications for btcwallet, since the
websocket-handler now runs instead of falling back to the legacy RPC
handler.
2014-01-20 18:27:27 -05:00
Dave Collins
8c7d44c8dc Add authentication deadline to RPC server cnxns.
Previously it was possible to open a connection to the RPC server, never
authenticate, and idle forever.

This is work toward #68.
2014-01-18 00:08:39 -06:00
Dave Collins
737e69594b Don't spend time on txout ntfns when no listeners. 2014-01-17 16:30:01 -06:00
Dave Collins
9474ef29d7 Use strings in websocket send/receive.
The websocket package assumes binary blobs if []byte is used.  Since we're
using JSON-RPC for all the websocket communications, it should be text
based.

This commit changes the websocket Send/Receive and associated channels to
strings accordingly.
2014-01-17 15:48:00 -06:00
Dave Collins
75554fab09 Fix merge conflict. 2014-01-17 15:45:23 -06:00
Dave Collins
f089853d4d Move RPC websocket init code to rpcwebsocket.go. 2014-01-17 15:44:36 -06:00
Josh Rickmar
20e56d6eda Ask for block(dis)connected updates.
This removes the last notification that was being sent unsolicited.
Since it is no longer needed, the code to duplicate notifications to
all clients has been removed.
2014-01-17 16:38:16 -05:00
Josh Rickmar
bd98836a2b Fix several bugs in the RPC server shutdown.
The RPC server was performing some of the shutdown logic in the wrong
order, that is, logging the the server has shut down, waiting for all
server goroutines to finish, and then closing a channel to notify
server goroutines to stop.  These three items have been reversed to
fix a hang where goroutines currently being waited on had not shut
down because they did not receive the notification.

While here, the server waitgroup was incremented for a goroutine that
was running without it, another select statement was added to stop a
duplicate close (which never occured last commit when I added the
select statements), and the "stopping rescan" logging was moved to
debug to make the ^C shutdown logging nicer.
2014-01-14 22:53:07 -05:00
Josh Rickmar
d8227c2751 Only close websocket disconnected chan if still open.
A channel cannot be closed multiple times, so use a select statement
to only close the channel if it can not be read from.
2014-01-14 21:47:27 -05:00