Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

Commit

Permalink
fix: use block headers only
Browse files Browse the repository at this point in the history
The current code was wrong. You could pass in a full block (with
transactions) and only the header was used. The correct behaviour
is, to use the header only.

This means that this library does support block headers only, there
is no support for transactions.
  • Loading branch information
vmx committed Jul 19, 2018
1 parent 3ce5f66 commit ef05359
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 52 deletions.
20 changes: 11 additions & 9 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const multihashes = require('multihashes')
const multihashing = require('multihashing-async')
const waterfall = require('async/waterfall')

const BITCOIN_BLOCK_HEADER_SIZE = 80

/**
* @callback SerializeCallback
* @param {?Error} error - Error if serialization failed
Expand All @@ -24,7 +26,7 @@ const serialize = (dagNode, callback) => {
let err = null
let binaryBlob
try {
binaryBlob = dagNode.toBuffer()
binaryBlob = dagNode.toBuffer(true)
} catch (serializeError) {
err = serializeError
} finally {
Expand All @@ -47,15 +49,14 @@ const serialize = (dagNode, callback) => {
* @returns {void}
*/
const deserialize = (binaryBlob, callback) => {
let err = null
let dagNode
try {
dagNode = BitcoinjsBlock.fromBuffer(binaryBlob)
} catch (deserializeError) {
err = deserializeError
} finally {
callback(err, dagNode)
if (binaryBlob.length !== BITCOIN_BLOCK_HEADER_SIZE) {
const err = new Error(
`Bitcoin block header needs to be ${BITCOIN_BLOCK_HEADER_SIZE} bytes`)
return callback(err)
}

const dagNode = BitcoinjsBlock.fromBuffer(binaryBlob)
callback(null, dagNode)
}

/**
Expand Down Expand Up @@ -106,6 +107,7 @@ const hashToCid = (hash) => {

module.exports = {
hashToCid: hashToCid,
BITCOIN_BLOCK_HEADER_SIZE: BITCOIN_BLOCK_HEADER_SIZE,

// Public API
cid: cid,
Expand Down
12 changes: 12 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'

const BITCOIN_BLOCK_HEADER_SIZE = require('../src/index')
.util.BITCOIN_BLOCK_HEADER_SIZE

const headerFromHexBlock = (hex) => {
return Buffer.from(hex.toString(), 'hex').slice(0, BITCOIN_BLOCK_HEADER_SIZE)
}

module.exports = {
headerFromHexBlock
}
33 changes: 17 additions & 16 deletions test/resolver.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ const expect = chai.expect
chai.use(dirtyChai)
const CID = require('cids')
const IpldBitcoin = require('../src/index')
const helpers = require('./helpers')

const fixtureBlockHex = loadFixture('test/fixtures/block.hex')
const fixtureBlock = Buffer.from(fixtureBlockHex.toString(), 'hex')
const fixtureBlockHeader = helpers.headerFromHexBlock(fixtureBlockHex)
const invalidBlock = Buffer.from('abcdef', 'hex')

describe('IPLD format resolver API resolve()', () => {
describe('IPLD format resolve API resolve()', () => {
it('should return the deserialized node if no path is given', (done) => {
IpldBitcoin.resolver.resolve(fixtureBlock, (err, value) => {
IpldBitcoin.resolver.resolve(fixtureBlockHeader, (err, value) => {
expect(err).to.not.exist()
expect(value.remainderPath).is.empty()
expect(value.value).is.not.empty()
Expand All @@ -24,7 +25,7 @@ describe('IPLD format resolver API resolve()', () => {
})

it('should return the deserialized node if path is empty', (done) => {
IpldBitcoin.resolver.resolve(fixtureBlock, '', (err, value) => {
IpldBitcoin.resolver.resolve(fixtureBlockHeader, '', (err, value) => {
expect(err).to.not.exist()
expect(value.remainderPath).is.empty()
expect(value.value).is.not.empty()
Expand All @@ -33,35 +34,35 @@ describe('IPLD format resolver API resolve()', () => {
})

it('should return the version', (done) => {
verifyPath(fixtureBlock, 'version', 2, done)
verifyPath(fixtureBlockHeader, 'version', 2, done)
})

it('should return the timestamp', (done) => {
verifyPath(fixtureBlock, 'timestamp', 1386981279, done)
verifyPath(fixtureBlockHeader, 'timestamp', 1386981279, done)
})

it('should return the difficulty', (done) => {
verifyPath(fixtureBlock, 'difficulty', 419740270, done)
verifyPath(fixtureBlockHeader, 'difficulty', 419740270, done)
})

it('should return the nonce', (done) => {
verifyPath(fixtureBlock, 'nonce', 3159344128, done)
verifyPath(fixtureBlockHeader, 'nonce', 3159344128, done)
})

it('should error on non-existent path', (done) => {
verifyError(fixtureBlock, 'something/random', done)
verifyError(fixtureBlockHeader, 'something/random', done)
})

it('should error on path starting with a slash', (done) => {
verifyError(fixtureBlock, '/version', done)
verifyError(fixtureBlockHeader, '/version', done)
})

it('should error on partially matching path that isn\'t a link', (done) => {
verifyError(fixtureBlock, 'version/but/additional/things', done)
verifyError(fixtureBlockHeader, 'version/but/additional/things', done)
})

it('should return a link when parent is requested', (done) => {
IpldBitcoin.resolver.resolve(fixtureBlock, 'parent', (err, value) => {
IpldBitcoin.resolver.resolve(fixtureBlockHeader, 'parent', (err, value) => {
expect(err).to.not.exist()
expect(value.remainderPath).is.empty()
expect(value.value).to.deep.equal({
Expand All @@ -72,7 +73,7 @@ describe('IPLD format resolver API resolve()', () => {

it('should return a link and remaining path when parent is requested',
(done) => {
IpldBitcoin.resolver.resolve(fixtureBlock, 'parent/timestamp',
IpldBitcoin.resolver.resolve(fixtureBlockHeader, 'parent/timestamp',
(err, value) => {
expect(err).to.not.exist()
expect(value.remainderPath).to.equal('timestamp')
Expand All @@ -84,7 +85,7 @@ describe('IPLD format resolver API resolve()', () => {
})

it('should return a link when transactions are requested', (done) => {
IpldBitcoin.resolver.resolve(fixtureBlock, 'tx/some/remainder',
IpldBitcoin.resolver.resolve(fixtureBlockHeader, 'tx/some/remainder',
(err, value) => {
expect(err).to.not.exist()
expect(value.remainderPath).to.equal('some/remainder')
Expand All @@ -101,7 +102,7 @@ describe('IPLD format resolver API resolve()', () => {

describe('IPLD format resolver API tree()', () => {
it('should return only paths by default', (done) => {
IpldBitcoin.resolver.tree(fixtureBlock, (err, value) => {
IpldBitcoin.resolver.tree(fixtureBlockHeader, (err, value) => {
expect(err).to.not.exist()
expect(value).to.deep.equal(['version', 'timestamp', 'difficulty',
'nonce', 'parent', 'tx'])
Expand All @@ -110,7 +111,7 @@ describe('IPLD format resolver API tree()', () => {
})

it('should be able to return paths and values', (done) => {
IpldBitcoin.resolver.tree(fixtureBlock, {values: true}, (err, value) => {
IpldBitcoin.resolver.tree(fixtureBlockHeader, {values: true}, (err, value) => {
expect(err).to.not.exist()
expect(value).to.deep.equal({
version: 2,
Expand Down
42 changes: 15 additions & 27 deletions test/util.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const IpldBitcoin = require('../src/index')
const helpers = require('./helpers')

const fixtureBlockHex = loadFixture('test/fixtures/block.hex')
const fixtureBlock = Buffer.from(fixtureBlockHex.toString(), 'hex')
const fixtureBlockHeader = helpers.headerFromHexBlock(fixtureBlockHex)
const invalidDagNode = {invalid: 'dagNode'}

describe('IPLD format util API deserialize()', () => {
it('should work correctly', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyBlock(dagNode, {
version: 2,
Expand All @@ -30,8 +31,8 @@ describe('IPLD format util API deserialize()', () => {

it('should deserialize Segwit correctly (a)', (done) => {
const segwitBlockHex = loadFixture('test/fixtures/segwit.hex')
const segwitBlock = Buffer.from(segwitBlockHex.toString(), 'hex')
IpldBitcoin.util.deserialize(segwitBlock, (err, dagNode) => {
const segwitBlockHeader = helpers.headerFromHexBlock(segwitBlockHex)
IpldBitcoin.util.deserialize(segwitBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyBlock(dagNode, {
version: 536870914,
Expand All @@ -50,8 +51,8 @@ describe('IPLD format util API deserialize()', () => {

it('should deserialize Segwit correctly (b)', (done) => {
const segwitBlockHex = loadFixture('test/fixtures/segwit2.hex')
const segwitBlock = Buffer.from(segwitBlockHex.toString(), 'hex')
IpldBitcoin.util.deserialize(segwitBlock, (err, dagNode) => {
const segwitBlockHeader = helpers.headerFromHexBlock(segwitBlockHex)
IpldBitcoin.util.deserialize(segwitBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyBlock(dagNode, {
version: 536870914,
Expand All @@ -70,8 +71,8 @@ describe('IPLD format util API deserialize()', () => {

it('should deserialize Segwit correctly (c)', (done) => {
const segwitBlockHex = loadFixture('test/fixtures/segwit3.hex')
const segwitBlock = Buffer.from(segwitBlockHex.toString(), 'hex')
IpldBitcoin.util.deserialize(segwitBlock, (err, dagNode) => {
const segwitBlockHeader = helpers.headerFromHexBlock(segwitBlockHex)
IpldBitcoin.util.deserialize(segwitBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyBlock(dagNode, {
version: 536870912,
Expand All @@ -88,19 +89,6 @@ describe('IPLD format util API deserialize()', () => {
})
})

it('should deserialize a block without transactions', (done) => {
const hexData = '01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d1398'
const block = Buffer.from(hexData.toString(), 'hex')
IpldBitcoin.util.deserialize(block, (err, dagNode) => {
expect(err).to.not.exist()
expect(dagNode.transactions).to.be.empty()
verifyCid(
dagNode,
'56200cf2049d7ce53bebaa4e8105606ee4663ca6d8e73a84fa40717133137cfc32b8',
done)
})
})

it('should error on an invalid block', (done) => {
const invalidBlock = Buffer.from('abcdef', 'hex')
IpldBitcoin.util.deserialize(invalidBlock, (err, dagNode) => {
Expand All @@ -113,11 +101,11 @@ describe('IPLD format util API deserialize()', () => {

describe('IPLD format util API serialize()', () => {
it('should round-trip (de)serialization correctly', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
IpldBitcoin.util.serialize(dagNode, (err, binaryBlob) => {
expect(err).to.not.exist()
expect(binaryBlob).to.deep.equal(fixtureBlock)
expect(binaryBlob).to.deep.equal(fixtureBlockHeader)
done()
})
})
Expand All @@ -134,7 +122,7 @@ describe('IPLD format util API serialize()', () => {

describe('IPLD format util API cid()', () => {
it('should encode the CID correctly', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyCid(
dagNode,
Expand All @@ -152,7 +140,7 @@ describe('IPLD format util API cid()', () => {
})

it('should encode the CID correctly with options', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyCid1(
dagNode,
Expand All @@ -163,7 +151,7 @@ describe('IPLD format util API cid()', () => {
})

it('should encode the CID correctly with undefined options', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyCid1(
dagNode,
Expand All @@ -174,7 +162,7 @@ describe('IPLD format util API cid()', () => {
})

it('should encode the CID correctly with default options specified', (done) => {
IpldBitcoin.util.deserialize(fixtureBlock, (err, dagNode) => {
IpldBitcoin.util.deserialize(fixtureBlockHeader, (err, dagNode) => {
expect(err).to.not.exist()
verifyCid1(
dagNode,
Expand Down

0 comments on commit ef05359

Please sign in to comment.