You are on page 1of 24

bcoin

Christopher
Jeffrey (JJ)
CTO at purse.io
Twitter: @_chjj
Email: chjj@purse.io
GitHub: https://github.com/
bcoin-org/bcoin

bcoin: make javascript great again


History
- bcoin created by Fedor Indutny
(@indutny) in 2014.

- rewritten as a fullnode in 2015 for


eventual use on purse.io

bitcoind

The Proof of Concept Reference Implementation

It comes with baggage: a long-standing


mentality that it is the one and only
fullnode.

"I don't believe a second, compatible implementation of Bitcoin will ever be


a good idea. So much of the design depends on all nodes getting exactly
identical results in lockstep that a second implementation would be a menace
to the network. The MIT license is compatible with all other licenses and
commercial uses, so there is no need to rewrite it from a licensing
standpoint." - Satoshi
"You are testing an alternative implementation with full validation rules. If
you are doing this, you should go rethink your life. Seriously, why are you
reimplementing Bitcoin consensus rules? Instead, go work on making Bitcoin
Core consensus rules a shared library and use that. Seriously, you wont get
it right, and starting with this tester as a way to try to do so will simply
end in pain and lost coins. SERIOUSLY, JUST STOP!" - Matt Corallo
"I don't believe there is anyone who is competent enough to do this. ... Even
the Bitcoin Core devs aren't good enough to do this." - Peter Todd

Str8 up menace
Menace implementations:
BitcoinJ: Java (bad)
btcd: Golang (good)
NBitcoin: C# (good)
bcoin: JS (good?)

Quote
"A fucked up childhood is why the
way I am." - MC Eiht

Conclusion: Bitcoin's
childhood is what led to the
creation of menaces.

Bitcoins Childhood
Satoshi releases whitepaper.
Satoshi releases a working C+
+ implementation of his
protocol.
The implementation itself has
no tests, docs, and global
state everywhere.

Bitcoind shortcomings (or "Satoshi


was not a programmer")

Global state.

Poor coding style

Cumbersome external API, especially for


notifications.

C++

Mike Hearn Was Right

Quote
"Whoever Satoshi was, he showed no familiarity with
post-1995 software development techniques and that includes
a complete lack of any unit tests and therefore a testable
codebase. Any modern implementation should do better....

You cannot currently build fake chains or inject test


messages and get the responses back. Making Core a fully
testable codebase is a big job that nobody has really
tackled even after five years.

-Mike Hearn (2014)

Nowadays things are better?


Whats Changed

Tests and docs

libbitcoinconsensus (handles only a small part of what bitcoin


consensus is)

More fleshed out API (more RPC calls and REST API)

Whats not changed

Global state.

Code insanity

Notifications

C++ (unfortunately)

Sample bitcoind code


static int GetWitnessCommitmentIndex(const CBlock& block)
{
int commitpos = -1;
for (size_t o = 0; o < block.vtx[0].vout.size(); o++) {
if (block.vtx[0].vout[o].scriptPubKey.size() >= 38 &&
block.vtx[0].vout[o].scriptPubKey[0] == OP_RETURN &&
block.vtx[0].vout[o].scriptPubKey[1] == 0x24 &&
block.vtx[0].vout[o].scriptPubKey[2] == 0xaa &&
block.vtx[0].vout[o].scriptPubKey[3] == 0x21 &&
block.vtx[0].vout[o].scriptPubKey[4] == 0xa9 &&
block.vtx[0].vout[o].scriptPubKey[5] == 0xed) {
commitpos = o;
}
}
return commitpos;
}

So,
lets
make
something
-bitcoind
better: something more
readable, more hackable, more
maintainable.

Hard Parts

Vastness

Complexity

Data management, scalability

Consensus

Policy

"You're not a programmer anymore. You're a bitcoin dev now. You're


on the other side: whole new ballgame. You can't learn about it in
school... and you can't have a late start." - Al Pacino

Data Management:Coins Everywhere

Coins (UTXOs) are the heart and soul of


bitcoin

Currently 40m+ coins in 11m+ unspent


transactions.

Every key in the database can potentially


make a key lookup slower.

Coins generally need to be cached in memory


for fast access.

Coins need to be future-proof.

Coins need to be compressed.

Indexing by UTXO ID Vs. TXID: Coin


Viewpoints

Blockchain vs. Mempool


Blockchain: neat and organized
Everything is in order.
Easy checking for double spends.
Mempool: The Wild West
Orphan transactions (we cant check whether
a tx actually exists)
Malicious transactions are more common
Non-consensus relay policies

Consensus (Lockstep)
Bugs become consensus
rules (Why? Because were
not Ethereum)

Example of a consensus edge case


TX#1:
19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff

Output#1: [sig-SINGLE] OP_DROP OP_2 [key] [key] OP_2


OP_CHECKMULTISIG

TX#2:
2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1

Input #1: [script not important]

Input #2: (redeems Output#1): OP_0 [sig-SINGLE] [sig-ALL]

Output #1: OP_Return [data]

Having a valid signature for the next transaction in an output


script should be logically impossible, short of a hash collision.
What's happening here?

Chicken-or-egg
SIGHASH_SINGLE flag: The initial bitcoin release had
a bug which implicity cast an error code of 1 to a
sha256 hash (explicit typing protects us, right?).
This results in a predictable signature hash of
01000000."
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo,
unsigned int nIn, int nHashType)
{
...
unsigned int nOut = nIn;
if (nOut >= txTmp.vout.size())
{
printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
return 1; // This gets cast to a uint256!
}
...
}

It gets weirder:

FindAndDelete(): Odd borderline-useless behavior added by Satoshi


which removes any signature passed to OP_CHECKSIG from the previous
output script. Because of this, the second "non-one" signature must
take into account the dropped signature from the output script.
scriptCode.FindAndDelete(CScript(vchSig)); // Passing the sig into the
CScript constructor reserializes it!

Example Policy Edge Case


(the recent rejects problem)

. Recent

rejects filter tracks by TXID, not

WTXID

Witness vectors are mutable

Mutating a witness to cause validation to


fail may insert the TXID into the recent
rejects filter, effectively censoring the
transaction until the next block

Johnson Laus solution IsBadWitness()

If we can reimplement consensus and


policy, we now have a framework to
build a nice clean bitcoin library on
top of.

bcoin
Creating a blockchain technology
(TM)
var bcoin = require('bcoin');
var chain = new bcoin.chain();
chain.open().then(() =>
chain.db.getBlock(0)).then(console.log);

Syncing the blockchain


var pool = new bcoin.pool({ chain: chain });
pool.open().then(() => pool.startSync());
chain.on('block', console.log);

Loose Coupling-tying these together via proxying events


Pool

Block Event

Chain

Pool

TX Event

Mempool

Chain

Connect/Disconnect
Event

Wallet DB/
Mempool/Miner

Mempool

TX Event

Wallet DB/Miner

Miner

Block Event

Chain

Wallet DB

Send Event

Pool

Wallet DB

TX Event

Websocket Server

HTTP Client

TX

HTTP Server

Mempool

Javascript, why?
Benefits

Faster than you think

Ubiquitous

Server-side AND browser-side

Drawbacks

No 64 bit number type, only doubles which lose precision


at 53bits.

Single threaded.

People arent used to writing real code in JS.

Solving the drawbacks


64-bit ints

A lot of trickery to treat doubles as though they were


ints.

Precision loss can be combatted by the fact that


MAX_MONEY is only 51bits.
(51-bit-max + 51-bit-max is never greater than 52 bits).

Single threaded

In node.js we can use worker processes for parallel tx


verification.

In the browser, we can use web worker threads.

Not much real code in JS


We can make javascript great again!

Example

Bcoin Features
Supported?

Versionbits

CSV

SegWit

BIP 150+BIP 151

Compact Block Relay

Preliminary MAST Support

Future Development
Plasma: Javascript Lightning
Implementation (LND Compatible)

fin?
slides by McKie :D

Coming
Soon
Starring:
Olaolu
(Roasbeef)
&
JJ

You might also like