Commit graph

32 commits

Author SHA1 Message Date
Dave Collins d406d9e52b wire: Consolidate tests into the wire pkg. (#728)
Putting the test code in the same package makes it easier for forks
since they don't have to change the import paths as much and it also
gets rid of the need for internal_test.go to bridge.

This same thing should probably be done for the majority of the code
base.
2016-08-08 11:42:54 -05:00
Dave Collins 6229e35835 wire: Further reduce transaction allocs.
This commit drastically reduces the number of allocations needed to
deserialize a transaction and its scripts by using the combination of a
free list for initially deserializing the individual scripts along with
copying them into a single contiguous byte slice after the final size is
known and modifying each script in the transaction to point to its
location within the contiguous blob.

The end result is only a single allocation that holds all of the scripts
for a transaction regardless of the total number of scripts it has.

The script free list allows a maximum of 12,500 items with each buffer
being 512 bytes.  This implies it will have a peak usage of 6.1MB.  The
values were chosen based on profiling data and a desire to allow at
least 100 scripts per transaction to be simultaneously deserialized by
125 peers.

Also, while optimizing, decode directly into the existing previous
outpoint structure of each transaction input in order to avoid the extra
allocation per input that is otherwise caused when the local escapes to
the heap.

The following is a before and after comparison of the allocations
with the benchmarks that did not change removed:

benchmark              old allocs     new allocs     delta
-----------------------------------------------------------
ReadTxOut              1              0              -100.00%
ReadTxIn               2              0              -100.00%
DeserializeTxSmall     7              5              -28.57%
DeserializeTxLarge     11146          6              -99.95%
2016-06-03 17:09:14 -05:00
Dave Collins 2adfb3b56a wire: Reduce allocs with contiguous slices.
The current code involves a ton of small allocations which is harsh on
the garbage collector and in turn causes a lot of addition runtime
overhead both in terms of additional memory and processing time.

In order to improve the situation, this drasticially reduces the number
of allocations by creating contiguous slices of objects and
deserializing into them.  Since the final data structures consist of
slices of pointers to the objects, they are constructed by pointing them
into the appropriate offset of the contiguous slice.

This could be improved upon even further by converting all of the data
structures provided the wire package to be slices of contiguous objects
directly, however that would be a major breaking API change and would
end up requiring updating a lot more code in every caller.  I do think
that ultimately the API should be changed, but the changes in this
commit already makes a massive difference and it doesn't require
touching any of the callers, so it is a good place to begin.

The following is a before and after comparison of the allocations
with the benchmarks that did not change removed:

benchmark              old allocs     new allocs     delta
-----------------------------------------------------------
DeserializeTxLarge     16715          11146          -33.32%
DecodeGetHeaders       501            2              -99.60%
DecodeHeaders          2001           2              -99.90%
DecodeGetBlocks        501            2              -99.60%
DecodeAddr             3001           2002           -33.29%
DecodeInv              50003          3              -99.99%
DecodeNotFound         50002          3              -99.99%
DecodeMerkleBlock      107            3              -97.20%
2016-06-03 17:08:31 -05:00
Dave Collins 5de5b7354c wire: Avoid allocation on timestamp decodes.
Since the protocol encodes timestamps differently depending on the
message, the code currently decodes into a local variable and then
converts it to a time.Time.  However, this causes an allocation due to
the local having to escape to the heap in order for the readElement
function to write to it.

So, in order to avoid that, this introduces two new types for a
timestamp named uint32Time and int64Time that are encoded as the
respective type on the read.  When calling the readElements function,
the time.Time field in the message is cast to a pointer of the
appropriate type which effectively allows the allocations to be avoided.

The following is a before and after comparison of the allocations
with the benchmarks that did not change removed:

benchmark              old allocs     new allocs     delta
----------------------------------------------------------------------
ReadBlockHeader        1              0              -100.00%
DecodeHeaders          4001           2001           -49.99%
DecodeAddr             4001           3001           -24.99%
DecodeMerkleBlock      108            107            -0.93%
2016-06-03 17:08:31 -05:00
Dave Collins f68cd7422d wire: Reduce allocs with a binary free list.
This introduces a new binary free list which provides a concurrent safe
list of unused buffers for the purpose of serializing and deserializing
primitive integers to their raw binary bytes.

For convenience, the type also provides functions for each of the
primitive unsigned integers that automatically obtain a buffer from the
free list, perform the necessary binary conversion, read from or write
to the given io.Reader or io.Writer, and return the buffer to the free
list.

A global instance of the type has been introduced with a maximum number
of 1024 items. Since each buffer is 8 bytes, it will consume a maximum
of 8KB.  Theoretically, this value would only allow up to 1024 peers
simultaneously reading and writing without having to resort to burdening
the garbage collector with additional allocations.  However, due to the
fact the code is designed in such a way that the buffers are quickly
used and returned to the free list, in practice it can support much more
than 1024 peers without involving the garbage collector since it is
highly unlikely every peer would need a buffer at the exact same time.

The following is a before and after comparison of the allocations
with the benchmarks that did not change removed:

benchmark              old allocs     new allocs     delta
-------------------------------------------------------------
WriteVarInt1           1              0              -100.00%
WriteVarInt3           1              0              -100.00%
WriteVarInt5           1              0              -100.00%
WriteVarInt9           1              0              -100.00%
ReadVarInt1            1              0              -100.00%
ReadVarInt3            1              0              -100.00%
ReadVarInt5            1              0              -100.00%
ReadVarInt9            1              0              -100.00%
ReadVarStr4            3              2              -33.33%
ReadVarStr10           3              2              -33.33%
WriteVarStr4           2              1              -50.00%
WriteVarStr10          2              1              -50.00%
ReadOutPoint           1              0              -100.00%
WriteOutPoint          1              0              -100.00%
ReadTxOut              3              1              -66.67%
WriteTxOut             2              0              -100.00%
ReadTxIn               5              2              -60.00%
WriteTxIn              3              0              -100.00%
DeserializeTxSmall     15             7              -53.33%
DeserializeTxLarge     33428          16715          -50.00%
SerializeTx            8              0              -100.00%
ReadBlockHeader        7              1              -85.71%
WriteBlockHeader       10             4              -60.00%
DecodeGetHeaders       1004           501            -50.10%
DecodeHeaders          18002          4001           -77.77%
DecodeGetBlocks        1004           501            -50.10%
DecodeAddr             9002           4001           -55.55%
DecodeInv              150005         50003          -66.67%
DecodeNotFound         150004         50002          -66.67%
DecodeMerkleBlock      222            108            -51.35%
TxSha                  10             2              -80.00%
2016-06-03 17:08:31 -05:00
Dave Collins b14032487f wire: Add several decode benchmarks. (#682)
This adds decode benchmarks for several of the messages that profiling
has identified to cause a lot of allocations in addition to those that
already exist.  By adding these benchmarks, it makes it easier to get
allocation and speed statistics which can in turn be used to compare
future improvements.

The following bencharmarks have been added:

DecodeGetHeaders, DecodeHeaders, DecodeGetBlocks, DecodeAddr, DecodeInv,
DecodeNotFound, and DecodeMerkleBlock

For reference, here is the benchmark data as of this commit.

DecodeGetHeaders     93261 ns/op     24120 B/op     1004 allocs/op
DecodeHeaders      2071263 ns/op    368399 B/op    18002 allocs/op
DecodeGetBlocks      92486 ns/op     24120 B/op     1004 allocs/op
DecodeAddr          850608 ns/op    136202 B/op     9002 allocs/op
DecodeInv         17107172 ns/op   3601447 B/op   150004 allocs/op
DecodeNotFound    17522225 ns/op   3601444 B/op   150004 allocs/op
DecodeMerkleBlock    21062 ns/op      5192 B/op      222 allocs/op
2016-04-25 17:32:29 -05:00
Dave Collins e7ddaa468e wire: Don't allocate new readers in benchmarks. (#679)
This modifies the benchmarks in the wire package to avoid creating a new
reader for each iteration.  This is useful since it means that showing
the memory allocations will only show the function under test instead of
the allocation for the benchmark setup as well.

The following is a before and after comparison of the allocations
with the benchmarks that did not change removed:

benchmark              old allocs     new allocs     delta
------------------------------------------------------------
ReadVarInt1            2              1              -50.00%
ReadVarInt3            2              1              -50.00%
ReadVarInt5            2              1              -50.00%
ReadVarInt9            2              1              -50.00%
ReadVarStr4            4              3              -25.00%
ReadVarStr10           4              3              -25.00%
ReadOutPoint           2              1              -50.00%
ReadTxOut              4              3              -25.00%
ReadTxIn               6              5              -16.67%
DeserializeTxSmall     16             15             -6.25%
DeserializeTxLarge     33430          33428          -0.01%
ReadBlockHeader        8              7              -12.50%
2016-04-25 16:57:44 -05:00
Dave Collins 27c0f9f8d1 wire: Add large tx deserialize benchmark. (#678)
This adds a benchmark for deserializing a large transaction that is
often referred to as the megatransaction since it is the largest Bitcoin
transaction mined to date.  It consists of 5569 inputs and 1 output and
its hash is:

bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e08.

This is being done so there is a benchmark that tests more of a
worst-case scenario which is a better candidate for identifying and
testing improvements.

The following benchmark results shows the how much more intensive this
transaction is over the existing mock transaction:

DeserializeTxSmall  1000000    1751 ns/op      376 B/op     16 allocs/op
DeserializeTxLarge  300     5093980 ns/op  1672829 B/op  33430 allocs/op
2016-04-25 16:51:27 -05:00
Dave Collins 491acd4ca6 blockchain: Rework to use new db interface.
This commit is the first stage of several that are planned to convert
the blockchain package into a concurrent safe package that will
ultimately allow support for multi-peer download and concurrent chain
processing.  The goal is to update btcd proper after each step so it can
take advantage of the enhancements as they are developed.

In addition to the aforementioned benefit, this staged approach has been
chosen since it is absolutely critical to maintain consensus.
Separating the changes into several stages makes it easier for reviewers
to logically follow what is happening and therefore helps prevent
consensus bugs.  Naturally there are significant automated tests to help
prevent consensus issues as well.

The main focus of this stage is to convert the blockchain package to use
the new database interface and implement the chain-related functionality
which it no longer handles.  It also aims to improve efficiency in
various areas by making use of the new database and chain capabilities.

The following is an overview of the chain changes:

- Update to use the new database interface
- Add chain-related functionality that the old database used to handle
  - Main chain structure and state
  - Transaction spend tracking
- Implement a new pruned unspent transaction output (utxo) set
  - Provides efficient direct access to the unspent transaction outputs
  - Uses a domain specific compression algorithm that understands the
    standard transaction scripts in order to significantly compress them
  - Removes reliance on the transaction index and paves the way toward
    eventually enabling block pruning
- Modify the New function to accept a Config struct instead of
  inidividual parameters
- Replace the old TxStore type with a new UtxoViewpoint type that makes
  use of the new pruned utxo set
- Convert code to treat the new UtxoViewpoint as a rolling view that is
  used between connects and disconnects to improve efficiency
- Make best chain state always set when the chain instance is created
  - Remove now unnecessary logic for dealing with unset best state
- Make all exported functions concurrent safe
  - Currently using a single chain state lock as it provides a straight
    forward and easy to review path forward however this can be improved
    with more fine grained locking
- Optimize various cases where full blocks were being loaded when only
  the header is needed to help reduce the I/O load
- Add the ability for callers to get a snapshot of the current best
  chain stats in a concurrent safe fashion
  - Does not block callers while new blocks are being processed
- Make error messages that reference transaction outputs consistently
  use <transaction hash>:<output index>
- Introduce a new AssertError type an convert internal consistency
  checks to use it
- Update tests and examples to reflect the changes
- Add a full suite of tests to ensure correct functionality of the new
  code

The following is an overview of the btcd changes:

- Update to use the new database and chain interfaces
- Temporarily remove all code related to the transaction index
- Temporarily remove all code related to the address index
- Convert all code that uses transaction stores to use the new utxo
  view
- Rework several calls that required the block manager for safe
  concurrency to use the chain package directly now that it is
  concurrent safe
- Change all calls to obtain the best hash to use the new best state
  snapshot capability from the chain package
- Remove workaround for limits on fetching height ranges since the new
  database interface no longer imposes them
- Correct the gettxout RPC handler to return the best chain hash as
  opposed the hash the txout was found in
- Optimize various RPC handlers:
  - Change several of the RPC handlers to use the new chain snapshot
    capability to avoid needlessly loading data
  - Update several handlers to use new functionality to avoid accessing
    the block manager so they are able to return the data without
    blocking when the server is busy processing blocks
  - Update non-verbose getblock to avoid deserialization and
    serialization overhead
  - Update getblockheader to request the block height directly from
    chain and only load the header
  - Update getdifficulty to use the new cached data from chain
  - Update getmininginfo to use the new cached data from chain
  - Update non-verbose getrawtransaction to avoid deserialization and
    serialization overhead
  - Update gettxout to use the new utxo store versus loading
    full transactions using the transaction index

The following is an overview of the utility changes:
- Update addblock to use the new database and chain interfaces
- Update findcheckpoint to use the new database and chain interfaces
- Remove the dropafter utility which is no longer supported

NOTE: The transaction index and address index will be reimplemented in
another commit.
2016-04-11 16:47:27 -05:00
Dave Collins eb882f39f8 multi: Fix several misspellings in the comments.
This commit corrects several typos in the comments found by misspell.
2016-02-25 11:17:12 -06:00
Jouke Hofman c17ff82061 wire: Export (read|write)(VarInt|VarBytes). 2016-02-22 18:11:58 +01:00
David Hill ae00fff14a wire: Implement sendheaders command (BIP0130)
This implements the wire protocol encoding portion of a new
sendheaders message as described by BIP0130. It purpose is to request
that a peer sends header commands instead of inv commands when
announcing new blocks. This includes a protocol version bump to 70012
and a wire version bump to 0.4.0.

Note that this does not implement logic to handle the command in btcd,
rather it only makes the command available at the wire protocol level.
A future commit which honors the command and therefore provides full
BIP0130 support is still required.
2016-02-05 12:41:39 -05:00
Jonathan Gillham 95361a2afc wire: Minor code clean up. 2016-01-26 23:09:18 +00:00
David Hill 7811770d31 Implement BIP0065 changeover logic for v4 blocks.
This commit implements the changeover logic for version 4 blocks as
described by BIP0065.
2015-10-28 13:28:50 -04:00
Dave Collins 3942a116e4 docs: Make various README.md files consistent.
First, it removes the documentation section from all the README.md files
and instead puts a web-based godoc badge and link at the top with the
other badges.  This is being done since the local godoc tool no longer
ships with Go by default, so the instructions no longer work without
first installing godoc. Due to this, pretty much everyone uses the
web-based godoc these days anyways.  Anyone who has manually installed
godoc won't need instructions.

Second, it makes sure the ISC license badge is at the top with the other
badges and removes the textual reference in the overview section.

Finally, it's modifies the Installation section to Installation and
Updating and adds a '-u' to the 'go get' command since it works for both
and thus is simpler.
2015-10-23 14:51:36 -05:00
Dave Collins 5a9bac9668 Correct a few style related issues found by golint.
Also, update TravisCI goclean script to remove the special casing which
ignored 'Id' from the lint output since that exception is no longer
needed.  It was previously required due to the old version of btcjson,
but that is no longer in the repo.
2015-10-20 10:34:14 -05:00
Dave Collins 80fa803875 wire: Export var length string serialization funcs.
This commit exports the ReadVarString and WriteVarString functions so
they are available for callers to use.

A variable length string is encoded as a variable length integer
containing the length of the string followed by the bytes that represent
the string itself.
2015-10-16 11:24:45 -05:00
David Hill c9ee3d9c5e wire: Implement SFNodeBloom (BIP0111).
SFNodeBloom is a new service flag that a node is required to use to
indicate that it supports bloom filtering.  This includes a protocol
version bump to 70011 and a wire version bump to 0.3.0.

btcd:
The SFNodeBloom flag is set by default.  A new configuration option
--nopeerbloomfilters has been added to to disable bloom filtering.

Any node advertising a version greater than or equal to 70011 that
attempts to use bloom filtering will be disconnected if bloom
filtering is disabled.

This mimics Bitcoin Core commit afb0ccaf9c9e4e8fac7db3564c4e19c9218c6b03
2015-09-28 16:25:44 -04:00
Dave Collins 79aac01b02 wire: Reject non-canonically encoded varints.
The Bitcoin wire protocol includes several fields with their lengths
encoded according to a variable length integer encoding scheme that does
not enforce a unique encoding for all numbers.

This can lead to a situation where deserializing and re-serializing the
same data can result in different bytes.  There are no currently known
issues due to this, but it is safer to reject such subtle differences as
they could potentially lead to exploits.

Consequently, this commit modifies the varint decoding function to error
when the value is not canonically encoded which effectively means that
all messages with varints that are not canonically encoded will now be
rejected.  This will not cause issues with old client versions in
regards to blocks and transactions since the data is deserialized into
memory and then reserialized before being relayed thereby effectively
erasing any non-canonical encodings.

Also, new tests have been added to ensure non-canonical encodings are
properly rejected and exercise the new code, and the default user agent
version for wire has been bumped to version 0.2.1 to differentiate the
new behavior.

The equivalent logic was implemented in Bitcoin Core by PR 2884.
2015-09-26 16:22:31 -05:00
David Hill 2441120b55 Recognize the BIP0064 service bit.
This does not add BIP0064 (getutxos/utxos) support to btcd.
2015-08-22 09:11:05 -04:00
Dave Collins 51fca61707 wire: Remove duplicate tx error path tests. 2015-07-26 13:05:09 -05:00
David Hill eb4ad09598 Implmement BlockHeader BtcEncode/BtcDecode.
At the current time, there is no difference between the wire encoding
at protocol version 0 and the stable long-term storage format.  These
methods are simply for consistency with the other types.
2015-07-22 11:34:18 -04:00
Dave Collins 3d89b56b27 wire: Update tests to force error in tx lock time.
This commit updates the wire tests for transactions which force
serialization and deserialization errors to force an error in the the
transaction lock time path.

This brings the wire test coverage back up to 100%.
2015-07-22 09:26:52 -05:00
Dave Collins 6e402deb35 Relicense to the btcsuite developers.
This commit relicenses all code in this repository to the btcsuite
developers.
2015-05-01 12:00:56 -05:00
Dave Collins a4a52ae24f wire: Remove errs from BlockHeader/MsgBlock/MsgTx.
This commit removes the error returns from the BlockHeader.BlockSha,
MsgBlock.BlockSha, and MsgTx.TxSha functions since they can never fail and
end up causing a lot of unneeded error checking throughout the code base.

It also updates all call sites for the change.
2015-04-17 01:27:12 -05:00
Dave Collins 6211eef7ee wire: Add new DoubleSha256SH function.
This commit adds a new function which is similar to the DoubleSha256
function except it returns a ShaHash copy instead of a byte slice.  It
also adds a new benchmark for it.

This can be a slight optimization in certain cases where the caller
ultimately wants a ShaHash since it can avoid a heap allocation and
additional copy to convert the result to a ShaHash (the function simply
performs a type cast against the returned array which is not possible
against a []byte).

existing: DoubleSha256     500000   3081 ns/op   32 B/op   1 allocs/op
     new: DoubleSha256SH   500000   2939 ns/op    0 B/op   0 allocs/op

The hashing functions for blocks and transactions have also been updated
to make use of the new function since they directly return the ShaHash.
The transaction change in particular is quite useful since transactions
are frequently hashed and this change allows all of those hashes to avoid
an additional heap allocation.
2015-04-06 11:37:43 -05:00
Dave Collins f5cdf2d6a8 Minor hashing-related optimizations.
This commit contains three classes of optimizations:
 - Reducing the number of unnecessary hash copies
 - Improve the performance of the DoubleSha256 function
 - A couple of minor optimizations of the ShaHash functions

The first class is a result of the Bytes function on a ShaHash making a
copy of the bytes before returning them.  It really should have been named
CloneBytes, but that would break the API now.

To address this, a comment has been added to the function which explicitly
calls out the copy behavior.  In addition, all call sites of .Bytes on a
ShaHash in the code base have been updated to simply slice the array when
a copy is not needed.  This saves a significant amount of data copying.

The second optimization modifies the DoubleSha256 function to directly use
fastsha256.Sum256 instead of the hasher interface.  This reduces the
number of allocations needed.  A benchmark for the function has been added
as well.

old: BenchmarkDoubleSha256  500000   3691 ns/op   192 B/op   3 allocs/op
new: BenchmarkDoubleSha256  500000   3081 ns/op    32 B/op   1 allocs/op

The final optimizations are for the ShaHash IsEqual and SetBytes functions
which have been modified to make use of the fact the type is an array and
remove an unneeded subslice.
2015-04-06 11:33:58 -05:00
Dave Collins 62432a6f90 wire: Add func to get pkscript locs from a tx.
This commit provides a new function named PkScriptLocs on the MsgTx type
which can be used to efficiently retrieve a list of offsets for the public
key scripts for the serialized form of the transaction.

This is useful for certain applications which store fully serialized
transactions and want to be able to quickly index into the serialized
transaction to extract a give public key script directly thereby avoiding
the need to deserialize the entire transaction.
2015-03-09 22:09:09 -05:00
Dave Collins 3ed8f363e7 Implement BIP0066 changeover logic for v3 blocks.
This commit implements the changeover logic for version 3 blocks as
described by BIP0066.
2015-02-26 09:54:29 -06:00
Josh Rickmar 859d9a7520 wire: Display correct RandomUint64 test failures. 2015-02-25 15:32:00 -05:00
Dave Collins 116736ee73 Run gofmt on wire directory. 2015-02-05 13:07:51 -06:00
Dave Collins 2eef3720a9 Import btcwire repo into wire directory.
This commit contains the entire btcwire repository along with several
changes needed to move all of the files into the wire directory in
order to prepare it for merging.  This does NOT update btcd or any of the
other packages to use the new location as that will be done separately.

- All import paths in the old btcwire test files have been changed to the
  new location
- All references to btcwire as the package name have been chagned to
  wire
- The coveralls badge has been removed since it unfortunately doesn't
  support coverage of sub-packages

This is ongoing work toward #214.
2015-01-31 14:59:57 -06:00