Closed lukasz-zimnoch closed 1 year ago
Here is the list of use cases for the bcoin
library in the tbtc-ts
. All of them are related to creating Bitcoin transactions:
1) Creating a new transaction: A new mutable transaction (MTX) is created using new bcoin.MTX().
const transaction = new bcoin.MTX();
2) Adding output: An output is added to the transaction with bcoin.Script.fromAddress(refunderAddress) used for generating the script from the given refunderAddress.
transaction.addOutput({
script: bcoin.Script.fromAddress(refunderAddress),
value: utxo.value.toNumber(),
});
3) Creating a coin: A coin object is created from a raw transaction, which is used later for funding the transaction.
const inputCoin = bcoin.Coin.fromTX(
bcoin.MTX.fromRaw(utxo.transactionHex, "hex"),
utxo.outputIndex,
-1
);
4) Funding the transaction: The transaction is funded using the transaction.fund method.
await transaction.fund([inputCoin], {
changeAddress: refunderAddress,
hardFee: fee.toNumber(),
subtractFee: true,
});
5) Creating a script: A new script object is created from a raw buffer or address.
const depositScript = bcoin.Script.fromRaw(
Buffer.from(await assembleDepositScript(depositScriptParameters), "hex")
);
bcoin.Script.fromAddress(walletAddress)
6) Signing the transaction: The transaction.signature() method is used to generate a signature for specific inputs:
const signature: Buffer = transaction.signature(
inputIndex,
depositScript,
previousOutputValue,
refunderKeyRing.privateKey,
bcoin.Script.hashType.ALL,
0 // legacy sighash version for P2SH
);
// and similarly for P2WSH with segwit sighash version 1
Sometimes built-in functions for scripting and signing are used if the input is standard:
transaction.scriptInput(inputIndex, previousOutput, walletKeyRing)
transaction.signInput(inputIndex, previousOutput, walletKeyRing)
7) Converting the transaction object to the raw format:
transaction.toRaw().toString("hex")
8) Access to opcodes: The opcodes from the bcoin.script.common package are accessed. They are used to create a custom script:
const { opcodes } = bcoin.script.common
9) Keyring creation from the provate key:
new bcoin.KeyRing({
witness: witness,
privateKey: decodedPrivateKey.privateKey,
compressed: decodedPrivateKey.compressed,
})
10) Creating addresses based public keys:
bcoin.Address.fromWitnessPubkeyhash(buffer).toString(bcoinNetwork)
: bcoin.Address.fromPubkeyhash(buffer).toString(bcoinNetwork)
11) Unit test-only. Converting transaction to JSON format:
const txJSON = bcoin.TX.fromRaw(buffer).getJSON("testnet")
SOLUTION 1: Rewriting (parts of) the bcoin library to typescript:
Writing own code for parts of the bcoin
library that are used in our code would require creating classes such as:
transaction
: see https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/mtx.js and https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/tx.jstransaction output
: see https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/output.jstransaction input
: see https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/input.jscoin
: https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/coin.jsscript
: https://github.com/bcoin-org/bcoin/blob/master/lib/script/script.jsopcode
: https://github.com/bcoin-org/bcoin/blob/master/lib/script/opcode.jswitness
: https://github.com/bcoin-org/bcoin/blob/master/lib/script/witness.jsaddress
: https://github.com/bcoin-org/bcoin/blob/master/lib/primitives/address.jsTherefore this solution would require recreating most of transaction-related bcoin
-code and would be very time-consuming.
Parts related to block or chain could be skipped.
SOLUTION 2: Forking bcoin
and removing bcrypto
dependency.
In this solution, we could fork the bcoin
library (possibly leaving only transaction-related code and removing the rest), replace the bcrypto
with some other cryptographic library.
Those are some examples of what is imported from bcrypto
into bcoin
:
const ripemd160 = require('bcrypto/lib/ripemd160');
const sha1 = require('bcrypto/lib/sha1');
const sha256 = require('bcrypto/lib/sha256');
const hash160 = require('bcrypto/lib/hash160');
const hash256 = require('bcrypto/lib/hash256');
const secp256k1 = require('bcrypto/lib/secp256k1');
const base58 = require('bcrypto/lib/encoding/base58');
This solution could be faster than the first one, but it requires finding a replacement for the bcrypto
library and possibly touching low-level error-prone cryptographic code.
SOLUTION 3: Replacing bcoin
with another library.
Here are some Bitcoin-related javascript libraries:
This solution would probably be the fastest. However, the chosen library must be elastic enough to allow for creating non-standard Bitcoin transactions (i.e. singing inputs with non-standard scripts). Obviously, it must not have bcrypto
in its dependencies.
The two libraries mentioned above do not seem to depend on bcrypto
and are MIT-licensed.
We discussed the possible solutions with @tomaszslabon:
bcoin
with another library. Specifically, we will replace everything we can with https://github.com/bitcoinjs/bitcoinjs-lib which doesn't have painful dependencies and is actively maintained. It may happen that not everything will be replaceable 1:1 so we may need to write our own code for some parts. Nevertheless, this solution is the most promising and provides a good tradeoff between quality and time consumption.bcoin
library to typescript. Although it seems to be the best solution at a glance, it is the most time-consuming (rough guesstimate is even several weeks). There is a ton of code that would have to be written and covered with unit tests. Also, the burden of maintaining all of this will be on our shouldersbcoin
and removing bcrypto
dependency. This would require us to make direct changes in bcoin
library. This library is large, quite complex, and doesn't have active maintainers able to provide help. This solution has the biggest potential for generating serious blockers and extending the work beyond a reasonable duration. Additionally, we would have to maintain the bcoin
fork on our own
Our SDK uses
bcoin
library for Bitcoin-related operations. Thebcoin
library depends onbcrypto
which turned out to be a big pain that dramatically decreases the developer experience of our typescript SDK. Although we are getting rid of the directbcrypto
dependency in our SDK (see https://github.com/keep-network/tbtc-v2/pull/693),bcoin
still pullsbcrypto
transitively.One possible solution we want to explore is removing
bcoin
completely and replacing it with an alternative or our own code.The goal of this task is:
bcoin
in our SDK codebase and list all touching pointsbcoin
usage