Skip to content

Commit 26e0dbb

Browse files
committed
feat: use new multiformats CID interface and exports
Ref: multiformats/js-multiformats#161
1 parent 54ad017 commit 26e0dbb

18 files changed

Lines changed: 124 additions & 89 deletions

src/bitcoin-block.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BitcoinBlock, fromHashHex } from 'bitcoin-block'
2-
import { CID, bytes } from 'multiformats'
2+
import { bytes } from 'multiformats'
3+
import { create as createCID } from 'multiformats/cid'
34
import * as dblSha2256 from './dbl-sha2-256.js'
45
import { CODEC_BLOCK, CODEC_BLOCK_CODE, CODEC_TX_CODE } from './constants.js'
56

@@ -8,9 +9,8 @@ import { CODEC_BLOCK, CODEC_BLOCK_CODE, CODEC_TX_CODE } from './constants.js'
89
* @typedef {import('multiformats/codecs/interface').ByteView<T>} ByteView
910
*/
1011

11-
/**
12-
* @typedef {import('./interface').BitcoinHeader} BitcoinHeader
13-
*/
12+
/** @typedef {import('./interface').BitcoinHeader} BitcoinHeader */
13+
/** @typedef {import('./interface').BitcoinBlockCID} BitcoinBlockCID */
1414

1515
/**
1616
* **`bitcoin-block` / `0xb0` codec**: Encodes an IPLD node representing a
@@ -46,13 +46,13 @@ export function decode (data) {
4646
// insert links derived from native hash hex strings
4747
if (deserialized.previousblockhash) {
4848
const parentDigest = dblSha2256.digestFrom(fromHashHex(deserialized.previousblockhash))
49-
deserialized.parent = CID.create(1, CODEC_BLOCK_CODE, parentDigest)
49+
deserialized.parent = createCID(1, CODEC_BLOCK_CODE, parentDigest)
5050
} else {
5151
// genesis
5252
deserialized.parent = null
5353
}
5454
const txDigest = dblSha2256.digestFrom(fromHashHex(deserialized.merkleroot))
55-
deserialized.tx = CID.create(1, CODEC_TX_CODE, txDigest)
55+
deserialized.tx = createCID(1, CODEC_TX_CODE, txDigest)
5656

5757
return deserialized
5858
}
@@ -74,13 +74,13 @@ export const code = CODEC_BLOCK_CODE
7474
* The process of converting to a CID involves reversing the hash (to little-endian form), encoding as a `dbl-sha2-256` multihash and encoding as a `bitcoin-block` multicodec. This process is reversable, see {@link cidToHash}.
7575
*
7676
* @param {string} blockHash a string form of a block hash
77-
* @returns {CID} a CID object representing this block identifier.
77+
* @returns {BitcoinBlockCID} a CID object representing this block identifier.
7878
* @name BitcoinBlock.blockHashToCID()
7979
*/
8080
export function blockHashToCID (blockHash) {
8181
if (typeof blockHash !== 'string') {
8282
blockHash = bytes.toHex(blockHash)
8383
}
8484
const digest = dblSha2256.digestFrom(fromHashHex(blockHash))
85-
return CID.create(1, CODEC_BLOCK_CODE, digest)
85+
return createCID(1, CODEC_BLOCK_CODE, digest)
8686
}

src/bitcoin-tx.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BitcoinTransaction as BitcoinBlockTransaction, fromHashHex, merkle } from 'bitcoin-block'
2-
import { CID, bytes } from 'multiformats'
2+
import { bytes } from 'multiformats'
3+
import { create as createCID, asCID } from 'multiformats/cid'
34
import * as dblSha2256 from './dbl-sha2-256.js'
45
import { CODEC_TX, CODEC_TX_CODE, CODEC_WITNESS_COMMITMENT_CODE } from './constants.js'
56

@@ -11,6 +12,7 @@ import { CODEC_TX, CODEC_TX_CODE, CODEC_WITNESS_COMMITMENT_CODE } from './consta
1112
/** @typedef {import('bitcoin-block/interface').BlockPorcelain} BlockPorcelain */
1213
/** @typedef {import('./interface').BitcoinTransaction} BitcoinTransaction */
1314
/** @typedef {import('./interface').BitcoinTransactionMerkleNode} BitcoinTransactionMerkleNode */
15+
/** @typedef {import('./interface').BitcoinTxCID} BitcoinTxCID */
1416

1517
/** @ignore */
1618
const NULL_HASH = new Uint8Array(32)
@@ -46,11 +48,11 @@ function _encode (node, noWitness) {
4648
export function encode (node) {
4749
if (Array.isArray(node)) {
4850
const bytes = new Uint8Array(64)
49-
const leftCid = CID.asCID(node[0])
51+
const leftCid = asCID(node[0])
5052
if (leftCid != null) {
5153
bytes.set(leftCid.multihash.digest)
5254
}
53-
const rightCid = CID.asCID(node[1])
55+
const rightCid = asCID(node[1])
5456
if (rightCid == null) {
5557
throw new TypeError('Expected BitcoinTransactionMerkleNode to be [CID|null,CID]')
5658
}
@@ -80,7 +82,7 @@ export function encodeNoWitness (node) {
8082
*
8183
* @param {BlockPorcelain} deserialized
8284
* @param {BitcoinBlockTransaction.HASH_NO_WITNESS} [noWitness]
83-
* @returns {IterableIterator<{cid:CID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
85+
* @returns {IterableIterator<{cid:BitcoinTxCID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
8486
* @private
8587
* @ignore
8688
*/
@@ -109,15 +111,15 @@ function * _encodeAll (deserialized, noWitness) {
109111
(deserialized.tx[ii])
110112
const { transaction, bytes } = _encode(tx, noWitness)
111113
const mh = dblSha2256.digest(bytes)
112-
const cid = CID.create(1, CODEC_TX_CODE, mh)
114+
const cid = createCID(1, CODEC_TX_CODE, mh)
113115
yield { cid, bytes, transaction } // base tx
114116
hashes.push(mh.digest)
115117
}
116118

117119
for (const { hash, data } of merkle(hashes)) {
118120
if (data) {
119121
const mh = dblSha2256.digestFrom(hash)
120-
const cid = CID.create(1, CODEC_TX_CODE, mh)
122+
const cid = createCID(1, CODEC_TX_CODE, mh)
121123
const bytes = new Uint8Array(64)
122124
bytes.set(data[0], 0)
123125
bytes.set(data[1], 32)
@@ -137,7 +139,7 @@ function * _encodeAll (deserialized, noWitness) {
137139
*
138140
* @name BitcoinTransaction.encodeAll()
139141
* @param {BlockPorcelain} obj
140-
* @returns {IterableIterator<{cid:CID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
142+
* @returns {IterableIterator<{cid:BitcoinTxCID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
141143
*/
142144
export function * encodeAll (obj) {
143145
yield * _encodeAll(obj)
@@ -150,7 +152,7 @@ export function * encodeAll (obj) {
150152
*
151153
* @name BitcoinTransaction.encodeAllNoWitness()
152154
* @param {BlockPorcelain} obj
153-
* @returns {IterableIterator<{cid:CID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
155+
* @returns {IterableIterator<{cid:BitcoinTxCID, bytes:Uint8Array, transaction?:BitcoinBlockTransaction}>}
154156
*/
155157
export function * encodeAllNoWitness (obj) {
156158
yield * _encodeAll(obj, BitcoinBlockTransaction.HASH_NO_WITNESS)
@@ -211,8 +213,8 @@ export function decode (data) {
211213
}
212214
const leftMh = left != null ? dblSha2256.digestFrom(left) : null
213215
const rightMh = dblSha2256.digestFrom(right)
214-
const leftCid = leftMh != null ? CID.create(1, CODEC_TX_CODE, leftMh) : null
215-
const rightCid = CID.create(1, CODEC_TX_CODE, rightMh)
216+
const leftCid = leftMh != null ? createCID(1, CODEC_TX_CODE, leftMh) : null
217+
const rightCid = createCID(1, CODEC_TX_CODE, rightMh)
216218
return [leftCid, rightCid]
217219
}
218220

@@ -229,14 +231,14 @@ export function decode (data) {
229231
// witness commitment and we can't discriminate at this point -- we can only do that by trying to
230232
// load the witness commitment from the generated CID
231233
const witnessCommitmentMh = dblSha2256.digestFrom(witnessCommitment)
232-
const witnessCommitmentCid = CID.create(1, CODEC_WITNESS_COMMITMENT_CODE, witnessCommitmentMh)
234+
const witnessCommitmentCid = createCID(1, CODEC_WITNESS_COMMITMENT_CODE, witnessCommitmentMh)
233235
deserialized.witnessCommitment = witnessCommitmentCid
234236
}
235237
}
236238
for (const vin of deserialized.vin) {
237239
if (typeof vin.txid === 'string' && /^[0-9a-f]{64}$/.test(vin.txid)) {
238240
const txidMh = dblSha2256.digestFrom(fromHashHex(vin.txid))
239-
vin.tx = CID.create(1, CODEC_TX_CODE, txidMh)
241+
vin.tx = createCID(1, CODEC_TX_CODE, txidMh)
240242
}
241243
}
242244

@@ -260,15 +262,15 @@ export const code = CODEC_TX_CODE
260262
* The process of converting to a CID involves reversing the hash (to little-endian form), encoding as a `dbl-sha2-256` multihash and encoding as a `bitcoin-tx` multicodec. This process is reversable, see {@link cidToHash}.
261263
*
262264
* @param {string} txHash a string form of a transaction hash
263-
* @returns {CID} A CID (`multiformats.CID`) object representing this transaction identifier.
265+
* @returns {BitcoinTxCID} A CID (`multiformats.CID`) object representing this transaction identifier.
264266
* @name BitcoinTransaction.txHashToCID()
265267
*/
266268
export function txHashToCID (txHash) {
267269
if (typeof txHash !== 'string') {
268270
txHash = bytes.toHex(txHash)
269271
}
270272
const digest = dblSha2256.digestFrom(fromHashHex(txHash))
271-
return CID.create(1, CODEC_TX_CODE, digest)
273+
return createCID(1, CODEC_TX_CODE, digest)
272274
}
273275

274276
/**

src/bitcoin-witness-commitment.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BitcoinTransaction } from 'bitcoin-block'
2-
import { CID } from 'multiformats'
2+
import { create as createCID, asCID } from 'multiformats/cid'
33
import * as dblSha2256 from './dbl-sha2-256.js'
44
import { CODEC_TX, CODEC_TX_CODE, CODEC_WITNESS_COMMITMENT, CODEC_WITNESS_COMMITMENT_CODE } from './constants.js'
55

@@ -9,6 +9,8 @@ import { CODEC_TX, CODEC_TX_CODE, CODEC_WITNESS_COMMITMENT, CODEC_WITNESS_COMMIT
99
*/
1010
/** @typedef {import('bitcoin-block/classes/Block').BlockPorcelain} BlockPorcelain */
1111
/** @typedef {import('./interface').BitcoinWitnessCommitment} BitcoinWitnessCommitment */
12+
/** @typedef {import('./interface').BitcoinTxCID} BitcoinTxCID */
13+
/** @typedef {import('./interface').BitcoinWitnessCommitmentCID} BitcoinWitnessCommitmentCID */
1214

1315
/** @ignore */
1416
const NULL_HASH = new Uint8Array(32)
@@ -23,16 +25,16 @@ const NULL_HASH = new Uint8Array(32)
2325

2426
/**
2527
* @param {import('bitcoin-block/classes/Block').BlockPorcelain} deserialized
26-
* @param {CID|null} witnessMerkleRoot
27-
* @returns {{cid:CID, bytes:Uint8Array}|null}
28+
* @param {BitcoinTxCID|null} witnessMerkleRoot
29+
* @returns {{cid:BitcoinWitnessCommitmentCID, bytes:Uint8Array}|null}
2830
* @ignore
2931
*/
3032
export function encodeWitnessCommitment (deserialized, witnessMerkleRoot) {
3133
if (typeof deserialized !== 'object' || !Array.isArray(deserialized.tx)) {
3234
throw new TypeError('deserialized argument must be a Bitcoin block representation')
3335
}
3436

35-
if (witnessMerkleRoot !== null && !(witnessMerkleRoot instanceof Uint8Array) && !CID.asCID(witnessMerkleRoot)) {
37+
if (witnessMerkleRoot !== null && !(witnessMerkleRoot instanceof Uint8Array) && !asCID(witnessMerkleRoot)) {
3638
throw new TypeError('witnessMerkleRoot must be a Uint8Array or CID')
3739
}
3840

@@ -45,7 +47,7 @@ export function encodeWitnessCommitment (deserialized, witnessMerkleRoot) {
4547
merkleRootHash = witnessMerkleRoot
4648
} else {
4749
// CID
48-
const mrhcid = CID.asCID(witnessMerkleRoot)
50+
const mrhcid = asCID(witnessMerkleRoot)
4951
if (mrhcid == null) {
5052
throw new TypeError('Expected witnessMerkleRoot to be a CID')
5153
}
@@ -87,7 +89,7 @@ export function encodeWitnessCommitment (deserialized, witnessMerkleRoot) {
8789
}
8890

8991
const mh = dblSha2256.digestFrom(hash)
90-
const cid = CID.create(1, CODEC_WITNESS_COMMITMENT_CODE, mh)
92+
const cid = createCID(1, CODEC_WITNESS_COMMITMENT_CODE, mh)
9193

9294
return { cid, bytes }
9395
}
@@ -112,7 +114,7 @@ export function encode (node) {
112114
if (!(node.nonce instanceof Uint8Array)) {
113115
throw new TypeError('bitcoin-witness-commitment must have a `nonce` Uint8Array')
114116
}
115-
const witnessMerkleRoot = CID.asCID(node.witnessMerkleRoot)
117+
const witnessMerkleRoot = asCID(node.witnessMerkleRoot)
116118
if (!witnessMerkleRoot) {
117119
throw new TypeError('bitcoin-witness-commitment must have a `witnessMerkleRoot` CID')
118120
}
@@ -154,7 +156,7 @@ export function decode (data) {
154156
let witnessMerkleRoot = null
155157
if (!isNullHash(witnessHash)) {
156158
const witnessDigest = dblSha2256.digestFrom(witnessHash)
157-
witnessMerkleRoot = CID.create(1, CODEC_TX_CODE, witnessDigest)
159+
witnessMerkleRoot = createCID(1, CODEC_TX_CODE, witnessDigest)
158160
}
159161
return { witnessMerkleRoot, nonce }
160162
}

src/complete.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { CID, bytes } from 'multiformats'
1+
import { bytes } from 'multiformats'
2+
import { create as createCID } from 'multiformats/cid'
23
import { BitcoinBlock, BitcoinTransaction as BitcoinBlockTransaction } from 'bitcoin-block'
34
import * as bitcoinBlockCodec from './bitcoin-block.js'
45
import * as bitcoinTxCodec from './bitcoin-tx.js'
@@ -13,17 +14,20 @@ const { toHex } = bytes
1314
/** @typedef {import('./interface').IPLDLoader} IPLDLoader */
1415
/** @typedef {import('./interface').BitcoinTransaction} BitcoinTransaction */
1516
/** @typedef {import('./interface').BitcoinTransactionMerkleNode} BitcoinTransactionMerkleNode */
17+
/** @typedef {import('./interface').BitcoinBlockCID} BitcoinBlockCID */
18+
/** @typedef {import('./interface').BitcoinTxCID} BitcoinTxCID */
19+
/** @typedef {import('./interface').BitcoinWitnessCommitmentCID} BitcoinWitnessCommitmentCID */
1620

1721
/**
1822
* @param {any} obj
19-
* @returns {{cid:CID, bytes:Uint8Array}}
23+
* @returns {{cid:BitcoinBlockCID, bytes:Uint8Array}}
2024
* @ignore
2125
*/
2226
function mkblock (obj) {
2327
const bytes = bitcoinBlockCodec.encode(obj)
2428
const mh = dblSha256.digest(bytes)
2529
return {
26-
cid: CID.create(1, bitcoinBlockCodec.code, mh),
30+
cid: createCID(1, bitcoinBlockCodec.code, mh),
2731
bytes
2832
}
2933
}
@@ -38,7 +42,7 @@ function mkblock (obj) {
3842
*
3943
* @name Bitcoin.encodeAll()
4044
* @param {BlockPorcelain} block
41-
* @returns {IterableIterator<{cid: CID, bytes: Uint8Array}>}
45+
* @returns {IterableIterator<{cid: BitcoinBlockCID|BitcoinTxCID|BitcoinWitnessCommitmentCID, bytes: Uint8Array}>}
4246
*/
4347
export function * encodeAll (block) {
4448
if (typeof block !== 'object' || !Array.isArray(block.tx)) {
@@ -135,7 +139,7 @@ export function * encodeAll (block) {
135139
* `bitcoin-tx` and `bitcoin-witness-commitment` CIDs.
136140
*
137141
* @param {IPLDLoader} loader an IPLD block loader function that takes a CID argument and returns a `Uint8Array` containing the binary block data for that CID
138-
* @param {CID} blockCid a CID of type `bitcoin-block` pointing to the Bitcoin block header for the block to be assembled
142+
* @param {BitcoinBlockCID} blockCid a CID of type `bitcoin-block` pointing to the Bitcoin block header for the block to be assembled
139143
* @returns {Promise<{deserialized:BlockPorcelain, bytes:Uint8Array}>} an object containing two properties, `deserialized` and `bytes` where `deserialized` contains a full JavaScript instantiation of the Bitcoin block graph and `bytes` contains a `Uint8Array` with the binary representation of the graph.
140144
* @name Bitcoin.assemble()
141145
*/
@@ -146,7 +150,7 @@ export async function assemble (loader, blockCid) {
146150
*/
147151
const merkleCache = {}
148152
/**
149-
* @param {CID} txCid
153+
* @param {BitcoinTxCID} txCid
150154
* @returns {Promise<BitcoinTransaction|BitcoinTransactionMerkleNode>}
151155
* @ignore
152156
*/
@@ -178,7 +182,7 @@ export async function assemble (loader, blockCid) {
178182
})()
179183

180184
/**
181-
* @param {CID} txCid
185+
* @param {BitcoinTxCID} txCid
182186
* @returns {AsyncIterableIterator<BitcoinTransaction|BitcoinTransactionMerkleNode>}
183187
* @ignore
184188
*/

src/interface.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,43 @@
11
import { TransactionInCoinbasePorcelain, TransactionInPorcelain } from 'bitcoin-block/classes/TransactionIn';
22
import { BlockHeaderPorcelain, TransactionPorcelain } from 'bitcoin-block/interface'
3-
import { CID } from 'multiformats';
3+
import { CID } from 'multiformats/interface';
4+
5+
export type HASH_ALG_CODE = 0x56
6+
export type CODEC_BLOCK_CODE = 0xb0
7+
export type CODEC_TX_CODE = 0xb1
8+
export type CODEC_WITNESS_COMMITMENT_CODE = 0xb2
49

510
export type IPLDLoader = (cid:CID)=>Promise<Uint8Array>
611

12+
export interface BitcoinBlockCID extends CID<CODEC_BLOCK_CODE, HASH_ALG_CODE, 1>{}
13+
export interface BitcoinTxCID extends CID<CODEC_TX_CODE, HASH_ALG_CODE, 1>{}
14+
export interface BitcoinWitnessCommitmentCID extends CID<CODEC_WITNESS_COMMITMENT_CODE, HASH_ALG_CODE, 1>{}
15+
716
export interface BitcoinHeader extends BlockHeaderPorcelain {
8-
parent: CID|null
9-
tx: CID
17+
parent: BitcoinBlockCID|null
18+
tx: BitcoinTxCID
1019
}
1120

1221
export interface BitcoinTransactionMerkleNode {
13-
0: CID|null
14-
1: CID
22+
0: BitcoinTxCID|null
23+
1: BitcoinTxCID
1524
}
1625

17-
1826
export interface BitcoinTransactionInCoinbase extends TransactionInCoinbasePorcelain {
19-
tx: CID
27+
tx: BitcoinTxCID
2028
txinwitness: [string]
2129
}
2230

2331
export interface BitcoinTransactionIn extends TransactionInPorcelain {
24-
tx: CID
32+
tx: BitcoinTxCID
2533
}
2634

2735
export interface BitcoinTransaction extends TransactionPorcelain {
28-
witnessCommitment?: CID
36+
witnessCommitment?: BitcoinWitnessCommitmentCID
2937
vin: (BitcoinTransactionInCoinbase | BitcoinTransactionIn)[]
3038
}
3139

3240
export interface BitcoinWitnessCommitment {
33-
witnessMerkleRoot: CID|null
41+
witnessMerkleRoot: BitcoinTxCID|null
3442
nonce: Uint8Array
3543
}

src/util.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { CID } from 'multiformats/cid'
1+
import { parse as parseCID, asCID } from 'multiformats/cid'
22
import { BitcoinBlock, toHashHex } from 'bitcoin-block'
33
import * as block from './bitcoin-block.js'
44
import * as tx from './bitcoin-tx.js'
55

66
export const blockHashToCID = block.blockHashToCID
77
export const txHashToCID = tx.txHashToCID
88

9+
/**
10+
* @typedef {import('multiformats/interface').CID} CID
11+
*/
12+
913
/** @typedef {import('bitcoin-block/interface').BlockPorcelain} BlockPorcelain */
1014

1115
/**
@@ -64,9 +68,9 @@ export function serializeFullBitcoinBytes (obj) {
6468
*/
6569
export function cidToHash (cid) {
6670
if (typeof cid === 'string') {
67-
cid = CID.parse(cid)
71+
cid = parseCID(cid)
6872
}
69-
const acid = CID.asCID(cid)
73+
const acid = asCID(cid)
7074
if (!acid) {
7175
throw new TypeError('Must provide a CID or a CID string')
7276
}

0 commit comments

Comments
 (0)