[Note, data for this document was originally collected using a “debug” build. This has been corrected to use the much more efficient “release” build]

Block (and therefore transaction) validation can consume a tremendous amount of time and processing power due to an oversight in the original code that can cause super-linear transaction validation times. This problem can be solved via a new transaction format, but in the mean time we should to do something — especially since larger blocks could mean even larger transactions and therefore exponentially (in the English sense, encompassing all equations with an exponent, not in the mathematical one specifically referring to e^x) larger validation times.

Bitcoin Unlimited will merge a technology we call “Parallel Validation” that allows short, quick-to-validate sibling blocks to supersede large, slowly-validating blocks. This competition-based approach will cause larger blocks to be orphaned, resulting in miners favoring smaller blocks. However, it still makes sense to provide some very granular “emergent consensus” style limits to very actively discourage extremely costly transactions and blocks.

The current software attempts to solve this problem by counting signature operation (sigops). Unfortunately, it counts the wrong set of sigops! Let’s take 2 transactions as an example, created using the bitcoin RPC’s “create raw transaction” API. The first has 1 input and 10000 outputs, second 10000 inputs and one output.

Transaction 1 reports the following statistics:

Vin: 1, Vout: 10000



length: 340126 bytes

calculated sigops: 10000

actual sigops: 1

sighash: 340092

validation time: 24ms

Transaction 2 reports something completely different:

Vin 10000, Vout: 1



length: 1474955 bytes

calculated sigops: 1

actual sigops: 10000

sighash: 4100750000

validation time: 47,483ms

As you can see, the calculated sigops are the exact opposite of the actual signature operations, and the validation time is long for the transaction that has 1 “calculated” sigop, and short for the transaction that has 10000.

The problem is that to validate a transaction, the bitcoin client runs the input scripts and then runs the scripts of the prior transaction output (what we call the UTXO — unspent transaction output). This makes sense… the input is attempting to spend the prior output. And the signature instructions need to be in the prior output to ensure that the signature validation is actually executed (unless you are using a P2SH-style tx — the 3xxx addresses, but that is a detail).

And of course, the signature operations in this transaction’s outputs are not run during validation of this transaction. They are run when the next transaction spends these outputs.

So the sigop calculation code includes signature operations that are not relevant, and skips ones that are.

It should be noted that by limiting the number of output sigops, the system ultimately limits the number of inputs in subsequent transactions since the outputs of one transaction become the inputs of another. But since a transaction can contain 1000s of inputs, there is a high possible multiplier.

What does transaction validation really cost?

The following graph shows validation times for “normal” transactions with a different number of inputs and outputs. This data was collected on an Intel 6-core 4.0 Ghz achine. The vertical axis corresponds to milliseconds of validation time, the horizontal left axis corresponds to the number of outputs, and the horizontal right (depth) axis corresponds to the number of inputs:

Transaction validation times in milliseconds for transactions ranging from 1 to 2000 inputs and outputs

While a 3.3 second maximum time is not an issue, the situation is very different for small embedded ARM computers, like the RaspberryPI. These are the results for a OrangePI+(basically a RasPi+ with a SATA disk).

Transaction Validation times for Intel (green) and 1.6 GHz ARM dual core Orange PI+ (blue)

A Super-Linear Relationship

To make the super-linear rise clear, the following is a graph of transactions with N inputs and 1 output (blue), and transactions with 1 input and N outputs (orange):

It is quite clear visually that the nonlinear behavior results from the inputs, not the outputs. But we can fit a curve to the data. Let us assume a quadratic model (i.e. ax² + by² + cxy + dx + ey + f):

This results in the following fit:

X= # inputs, Y= # outputs:

Model is: 0.000452*x^2 + -0.000008*y^2 + 0.217728*x +

0.075476*y + 0.000289*x*y + 27.769676

-0.000008 is essentially 0 for the breadth of data collection (1 to 2000 outputs). So numerically and visually, the data does look quadratic in the number of inputs and weakly linearly in the number of outputs.

In this casual report I will not do a formal error analysis because we will not directly use these constants, but graphically in 3d, you can see that the model (red) reasonably captures the trend in the actual data (green). In the 2d projections of the extreme 1 by N cases, it seems to be off only when the number of inputs are 1.