Jeremy Rubin's Blog

Here you'll find an assorted mix of content from yours truly. I post about a lot of things, but primarily Bitcoin.

categories: Bitcoin, Shenzhen Journey.


Pillars of Bitcoin: Scalability

Day 2: Rubin's Bitcoin Advent Calendar

Welcome to day 2 of my Bitcoin Advent Calendar. You can see an index of all the posts here or subscribe at judica.org/join to get new posts in your inbox

This is the first of four posts in an advent mini-series about four fundamental pillars of Bitcoin. I know, I know, a series within a series. What am I, nuts? But it’s important that we begin our journey by setting the stage with a few big picture objectives for Bitcoin before we get into why Smart Contracts matter.

After all, we’re trying to build the hardest money possible, not Crypto Kitties… right?

The four pillars I’ve chosen to focus on are Scalability, Self Custody, Decentralization, and Privacy. Are there other properties that are also important? Sure. Might there be a “more fundamental” name for each pillar? Ok. But generally I find that these 4 categories are different enough from one another and capture a very wide swath of what Bitcoin is and not overly specific or overly general. Otherwise we’d just have one pillar for Bitcoin: “To Fix This”.

Now onto the content.


Scalability is a controversy generating issue. Throughout Bitcoin’s history there have been acerbic disagreements about what sort of scale is required and how to accomplish it. Back then I even helped create a conference series, Scaling Bitcoin, where people got to present to/shout at each other in person!

But why is scalability so important? And why does it generate controversy?

Famously, certain folks have remarked that, “you can’t buy coffee with Bitcoin” because fees would be too high. This is an issue that’s easy to empathize with; if transactions cost $10 who wants to do that for a $5 coffee – No One!

The common response is that Bitcoin isn’t for trivial purposes like buying a cup of coffee, it’s The Hardest And Most Sound Money To Ever Exist And If You Buy Coffee With It You Are Stupid.

There’s some truth to that. Bitcoin doesn’t need to function to enable your trivial day to day purchases, it needs to exist to help you take self-sovereign control over your money! Forget about your coffee, stack sats, survive hyperinflation, avoid the pod, don’t eat the bugs. Capiche?

So what’s the rub? Well, if Bitcoin is to really be the vaccine against autocratic rulers and corrupt financial systems, it needs to protect everyone, not just elite sat-stackers who can afford to use it. Scalability represents our desire for Bitcoin to be affordable for all who could benefit from it. Many who live under abusive or corrupt regimes today might already be priced out. Imagine earning 1000 satoshis per day and spending 300 satoshis to do a transaction. Real bummer. And what if fees go up? There’s also the insulting concept of dust in Bitcoin, 546 satoshis, currently about $0.30. Some people work hard just to earn that much! Where do you think people who fall on this low end of the economic spectrum live… in the freest of the free western countries? No, they’re Congolese children mining cobalt. Maybe it’s OK that they’re priced out: Bitcoin preserves wealth (and freedom), it doesn’t create it. And just having cheaper fees isn’t going to free the child workers. But still, wouldn’t you rather have Bitcoin be able to benefit anyone who might have the need to use it, regardless of net worth?

Good news: there are techniques that exist today for scaling access to Bitcoin. Bad news: they all have different tradeoffs.

Just Make the Blocks Bigger Bro

Early on in Bitcoin’s history a contingency of Bitcoiners felt strongly that Bitcoin should scale by increasing the size of Blocks to accommodate more transactions per second and keeping fees low. While mild block size increases (e.g., as done with SegWit) are probably ok, the ever-increasing block size would threaten Bitcoin’s decentralization and make it harder for anyone to be able to run and audit the system. And if you can’t run and audit Bitcoin yourself, you might as well be using the legacy financial system.

There are some efficiency improvements that can shrink transactions marginally, contributing to an effectively larger block. But Blockspace will always be scarce, no matter how space efficient transactions are.

Lightning Network

The Lightning Network is a very popular means of scaling bitcoin. It makes a second layer on top of Bitcoin where you can make cheaper and lower latency payments. It functions sort of like the equivalent of Venmo versus Bank Wire Transfers. You set up a “payment channel” with a counterparty, and are able to make many cheap payments between you and the counterparty. You can even route payments through friend’s channels if you don’t have a direct link. A few major downsides to this approach are as follows:

  1. That it requires an active online presence and ability to get bitcoin transactions confirmed (which still costs money!)
  2. It requires some form of durable storage any time you make a transaction.
  3. That in order to receive funds, you have to have someone loan you the “potential” capital (think credit worthiness, which requires some sort of reputation system and identities).

In countries like El Salvador, which have begun adopting Bitcoin as legal tender, many users of the Lightning Network are doing so through a centralized service provider which doesn’t protect users from the types of abuse possible in current banking paradigms. In theory, this central service provider isn’t there because the El Salvador government is some kind of soon-to-be dictatorship, but rather because solving the problems of capital loan, regular online presence, and durable storage are hard problems for citizens of a poor country.

Sidechains

Another popular approach is to make federated sidechains, such as RootStock, Liquid, Nomic, or ThorChain, etc. A Federated Sidechain is essentially a “fancy multisig”, where funds are sent into the custody of a set of entities (usually such that many independent entities would have to collude to steal funds). The federation then runs some sort of cryptocurrency backed by the deposits. Users are granted virtual bitcoin on the sidechain which they can use in accordance with the rules of the sidechain. Eventually they may request that whatever balance they have on the sidechain be sent out of the sidechain and into a normal bitcoin address of their choosing. This achieves a sort of scalability because the base layer does not have to validate or store any of the transactions occurring on the sidechain. However, the tradeoff is severe: the funds are completely owned by the Federation, which means that users are not guaranteed to be able to access their funds. It’s basically a bank with a cool API.


This post doesn’t end in a fun or upbeat way: we want everyone to be able to access and benefit from Bitcoin; we can’t get everyone for access in the obvious way of bigger blocks or we risk unravelling Bitcoin’s core guarantees; and the solutions using layers on top of bitcoin reduce some of the core properties that make Bitcoin valuable to society in the first place. Some of these tradeoffs may be acceptable in certain cases, but we must always strive to support the most users with the strongest Hard Money properties we can.

In future posts we’ll see how more sophisticated smart contracts could improve Bitcoin’s scalability, or at least provide a different set of tradeoffs compared to the solutions above.



Day 1: Rubin's Bitcoin Advent Calendar

What says Christmas more than an Advent Calendar to count the days till Santa comes? Honestly, I’m not too sure, I’m a Jew. Happy Hanukkah everyone! But in the spirit of the season, I figured the community would love a series of blog posts (one a day) discussing the future of Bitcoin and Smart Contracts.

You can find an index of all the posts here.

So here’s how it’s going to work:

Today’s the first day!

Advent Calendars are designed to be from the 4th Sunday before Christmas till Christmas and as such vary in length. Lucky you; this year is a long one! Unfortunately for me, I’ve got to make 26 more exciting posts to pull this off. Each of these posts is going to be short-but-sweet (much like the chocolates you’re used to) and designed to highlight an important concept or idea about Bitcoin Smart Contracting. I’ll put each post on my personal blog, email out a link on the judica newsletter, and tweet it out.

This series is for you.

It doesn’t matter if you’re a programmer, investor, pleb, or just trying to learn more. Through the series I’ll do my best to thoroughly introduce concepts for anyone to follow along and learn.

Of course I’m going to be a little biased.

The perspectives shared are my own and the focus is on things that I focus on, but I’ll do my best to present the balance and nuance!

If you want to send me some holiday cheer: 3E6p1UgrgwAFvZAF7xUiRcBR2vAEdYNXjZ

Hope you enjoy the series!



CheckSequenceVerify DISCOURAGE_UPGRADABLE_NOPS Defect

The other day I was writing some tests for BIP-119 (shoutout Gloria for the detailed feedback on improving tests). I noticed something peculiar while attempting to write static test vectors for CTV. This peculiar thing led me to discover a minor flaw in Bitcoin’s interpreter – it isn’t going to break anything in the short term, but it has implications for how certain upgrades might be done in the future.

In the interpreter we pass specific flags in at different times to check different rules at different times. This is used because we generally want the Mempool to be “restrictive” and block validation to be unrestrictive. That sounds like the opposite of what you would want, but it’s because we want to ensure that we never break a consensus rule, so our mempool is “strict” to protect e.g. a miner from making a bad block, because our node’s understanding of consensus validation is less strict so we always know the mempool is full of stuff that will pass consensus.

One of the specific types of “stricter” that is in the mempool is for things that may be changed in the future. For example, Taproot (a change proposed to Bitcoin) uses a Witness V1 script. Before Taproot activates, Witness V1 Scripts are always valid no matter if they’re signed or not. After it activates, a new rule takes effect in consensus, and Witness V1 Scripts will be processed in accordance with Taproot’s rules. Because the Mempool is stricter, it never lets in any Witness V1 script spends until it knows how to properly validate it. That way, for a miner who doesn’t want to upgrade to Taproot, they can use the old rules in their Mempool and not ever mine a bad block.

One of the flags used for this purpose is DISCOURAGE_UPGRADABLE_NOPS. A NOP is simply an opcode in bitcoin that has no effect (nada). In the future, someone could add a rule to that NOP (e.g., check that the stack args present when the NOP executes satisfy some properties or the transaction is invalid, but do not remove anything from the stack so that the old consensus rules still seem correct). This is sufficient for consensus, but maybe people have decided that they want to create a bunch of outputs with NOPs in it because they are cute. Then, a fork that would add new semantics to a NOP would have the impact of locking people out of their wallets. To prevent this, the Mempool uses the rule DISCOURAGE_UPGRADABLE_NOPS which makes it so that if you try to broadcast an output script with a NOP it gets bounced from the Mempool (but not consensus of course, should a deviant miner mine such a transaction). Hopefully our users get the message to not use NOPs because we… discourage upgradable nops.

CheckSequenceVerify (CSV) was one such NOP before it grew up to be a big n’ important opcode. Essentially all that CSV does is check that the sequence field is set in a particular manner. This lets you set relative block and time lock (e.g., takes this much time before a coin is spendable again). However, it’s possible that we might come up with new kinds of lock times in the future, so we have a bit we can set in the sequence that makes it ignored for consensus purposes. Maybe in the future, someone would find something nice to do with it, eh?

This is the sequence verification code:

case OP_CHECKSEQUENCEVERIFY:
{
    if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
        // not enabled; treat as a NOP3
        break;
    }

    if (stack.size() < 1)
        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

    // nSequence, like nLockTime, is a 32-bit unsigned integer
    // field. See the comment in CHECKLOCKTIMEVERIFY regarding
    // 5-byte numeric operands.
    const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);

    // In the rare event that the argument may be < 0 due to
    // some arithmetic being done first, you can always use
    // 0 MAX CHECKSEQUENCEVERIFY.
    if (nSequence < 0)
        return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);

    // To provide for future soft-fork extensibility, if the
    // operand has the disabled lock-time flag set,
    // CHECKSEQUENCEVERIFY behaves as a NOP.
    if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
        break;

    // Compare the specified sequence number with the input.
    if (!checker.CheckSequence(nSequence))
        return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);

    break;
}

Spot anything funky? Look closer…

    // To provide for future soft-fork extensibility, if the
    // operand has the disabled lock-time flag set,
    // CHECKSEQUENCEVERIFY behaves as a NOP.
    if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
        break;

Here, where we say it behaves as a NOP we don’t check any rules and skip the checks.

See where the problem lies? If we ever did get around to a future upgrade here, then old miners who refuse to upgrade would be more than happy to accept invalid transactions into their mempool, and then following the fork, would end up mining invalid blocks leading to potential network partitions.

That would be bad! Let’s not do that.

What we really should be doing is:

    // To provide for future soft-fork extensibility, if the
    // operand has the disabled lock-time flag set,
    // CHECKSEQUENCEVERIFY behaves as a NOP.
    if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) {
        if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
            return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
        break;
    }

Which is exactly what I propose to do in this PR.

If this solution is adopted, then after the last release of the Bitcoin Core Implementation that has the unpatched code goes End-of-Life, we could safely deploy new sequence rules. Because it takes a while for software to go EOL, I hope we can patch this soon.



Infrastructure Bill: It's Go Time for Radical Self Custody

TL;DR: click here to answer call to action

The infrastructure bill draft has been circulating which contains language that would have massive impact for the crypto ecosystem (and Bitcoin) in the United States, and most likely globally. The broad implication of the proposed bill is that many types of service provider would be categorized as brokers, even if fully ‘non custodial’. E.g., a coinjoin coordinator might be a broker, even if they never take control of the funds, because they are facilitating a transaction. There’s a lot of nuance, and the language is still being changed, so we’ll see where it lands. But that’s not the point of this blog post.

The point of this blog post is that we need to hurry the fuck up and improve the self-sovereign software available and widely used by bitcoiners. You heard me right, hurry the fuck up.

While there’s space for debate around perfect designs and optima for protocol improvements, these discussions take years to turn into code running in end users wallets. I do not believe that we have time to leisurely improve self-sovereign custody solutions while regulators figure out a wrench to throw in our spokes.

Why am I so concerned about this bill in particular? A confidential source tells me that this language came out of the blue, an executive branch driven regulatory ninja attack of sorts. Normally, when the government looks to regulate an industry, the provisions and terms get floated around by legislators for a long while with industry input, comment periods, and more. Then, when a bill or other rules get passed, it’s something that the industry has at least had a chance to weigh in on and prepare for. My source claims no one has seen the clauses in the infrastructure bill before, and they infer that may mean this is a part of a broader crack-down coming from specific political personalities and agencies. This means we may be seeing government actions further restricting users’ rights in the pipeline much sooner than anyone could anticipate.

I’ve long been saying that we should be deploying BIP-119 CTV for congestion control before we see broad congestion on the network. If you wait until a problem is manifest, it can take years to deploy a solution. This merits proactivity in solving a problem before it comes. Today, the need to improve self-custody looms urgently on the horizon.

CTV is not a panacea solution. It doesn’t magically fix all custodial issues. But, along with Sapio, it does offer a pathway to dramatically improving self custody options, letting users customize vault smart contracts which do not depend on any third parties. Deploying CTV now is an opportunity to put in motion the wheels for broad ecosystem support for these enhanced custody protocols. We may come up with better options in the future which may obsolete CTV in place of more clever technologies. I cheer those efforts. But we need solutions for Tomorrow.

A soft fork activation for CTV could be deployable for Bitcoin imminently, should the community embrace it. The spec is nearly 2 years old, the code has required only small updates to be mergeable with other changes to Bitcoin Core. The review burden is 185 lines of consensus code, and a couple hundred lines of tests. To that end I believe it is prudent for the Bitcoin community to embrace the deployment of CTV and I’m calling on the community to soft-signal intent for a soft-fork activation of CTV.

We cannot control what rules state authorities attempt to mandate. But we can individually control our own compliance with measures we see as unjust, and as a community we can advance technologies and solutions that ensure that choice remains squarely in the hands of every user and not the service providers they may use.



BIP-118 What Gets Hashed Chart

As a part of my ongoing review of BIP-118 I put together a chart of what gets hashed under the current proposal.

BIP-118 Chart

Not tightly checked to be free of errors, but I figured such a chart would be helpful for folks evaluating BIP-118.

Perhaps the BIPs (generally, incl 34x) could be updated to present the information in such a chart – at least for me it’s much clearer than following a bunch of conditional logic (maybe if there’s ever desire for some consensus refactoring this could be a table in the code replacing the cond logic). A few highlighted nuances:

  • input index is never signed (i previously thought one mode signed it). Key reuse under APOAS | Default and APOAS | All is a bit extra unsafe given susceptibility to the “half-spend” problem. This limits usability of APO for covenants a-la CTV because you can’t stop someone from adding inputs to your contract nor can you prevent half-spend problems when reusing addresses.
  • APO signs the Amounts, APOAS never does.
  • APO signs both the SPK and the Tapleaf hash, meaning that APO binds itself to the entire script rather than just it’s fragment. There’s no setting which is “just this fragment”
  • APO’s signature binds it to a specific script fragment within a taproot key, but not a specific script path
  • the flag “default” is not really a flag at all – when default is used (as a or’d byte) there are different results than when default is inferred (by absence of a byte) (this is maybe a bitcoin core specific quirk).
  • There are 16 different possible modes total, so all combinations of flags mean something (advisable or not as with ACP | None)
  • *| Default and *| All overlap, so there’s an opportunity to either reserve or assign 4 additional sighash modes if desired. These could cover some of the gaps above, or be saved for future purposes rather than be wasted now. Another point of interest is – not to rock the boat – but because BIP-118 is defining a new key type we could do away with the notion that sighash flags are “flags” and convert to an enum (e.g., numbered 0-256 for whatever combination of fields each would incur) and give each signature type a sensible name, rather than thinking of things as a combo of flags (e.g., APOAS is not some intersection of what APO and ACP do independently).

© 2011-2021 Jeremy Rubin. All rights reserved.