diff --git a/integration/index.js b/integration/index.js index 2eb4160b..10758fa5 100644 --- a/integration/index.js +++ b/integration/index.js @@ -45,13 +45,51 @@ describe('Basic Functionality', function() { }); }); - describe('will get correct block data', function() { + describe('get blocks by hash', function() { blockData.forEach(function(data) { var block = bitcore.Block.fromString(data); it('block ' + block.hash, function(done) { bitcoind.getBlock(block.hash, function(err, response) { - assert(response === data, 'incorrect block data for ' + block.hash); + assert(response.toString('hex') === data, 'incorrect block data for ' + block.hash); + done(); + }); + }); + }); + }); + + describe('get blocks by height', function() { + + var knownHeights = [ + [0, '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'], + [1, '00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048'], + [100000,'000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506'], + [314159, '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45'] + ]; + + knownHeights.forEach(function(data) { + it('block at height ' + data[0], function(done) { + bitcoind.getBlock(data[0], function(err, response) { + var block = bitcore.Block.fromBuffer(response); + block.hash.should.equal(data[1]); + done(); + }); + }); + }); + }); + + describe.skip('get the chain', function() { + + var heights = []; + for (var i = 364599; i >= 0 ; i--) { + heights.push(i); + } + + heights.forEach(function(height) { + it('block at height ' + height, function(done) { + bitcoind.getBlock(height, function(err, response) { + var block = bitcore.Block.fromBuffer(response); + console.log(block.hash); done(); }); }); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 3611d043..28599bad 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -189,6 +189,8 @@ struct async_block_data { std::string err_msg; std::string hash; int64_t height; + char* buffer; + uint32_t size; CBlock cblock; CBlockIndex* cblock_index; Eternal callback; @@ -835,35 +837,52 @@ static void async_get_block(uv_work_t *req) { async_block_data* data = static_cast(req->data); - if (data->height != -1) { - CBlockIndex* pblockindex = chainActive[data->height]; - CBlock cblock; - if (ReadBlockFromDisk(cblock, pblockindex)) { - data->cblock = cblock; - data->cblock_index = pblockindex; - } else { - data->err_msg = std::string("Block not found."); - } - return; - } - + CBlockIndex* pblockindex; std::string strHash = data->hash; uint256 hash(strHash); - if (mapBlockIndex.count(hash) == 0) { - data->err_msg = std::string("Block not found."); + if (data->height != -1) { + pblockindex = chainActive[data->height]; } else { - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if(!ReadBlockFromDisk(block, pblockindex)) { - data->err_msg = std::string("Can't read block from disk"); + if (mapBlockIndex.count(hash) == 0) { + data->err_msg = std::string("Block not found."); + return; } else { - data->cblock = block; - data->cblock_index = pblockindex; + pblockindex = mapBlockIndex[hash]; } } + + const CDiskBlockPos& pos = pblockindex->GetBlockPos(); + + // We can read directly from the file, and pass that, we don't need to + // deserialize the entire block only for it to then be serialized + // and then deserialized again in JavaScript + + // Open history file to read + CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) { + data->err_msg = std::string("ReadBlockFromDisk: OpenBlockFile failed"); + return; + } + + // Get the actual file, seeked position and rewind a uint32_t + FILE* blockFile = filein.release(); + long int filePos = ftell(blockFile); + fseek(blockFile, filePos - sizeof(uint32_t), SEEK_SET); + + // Read the size of the block + uint32_t size = 0; + fread(&size, sizeof(uint32_t), 1, blockFile); + + // Read block + char* buffer = (char *)malloc(sizeof(char) * size); + fread((void *)buffer, sizeof(char), size, blockFile); + fclose(blockFile); + + data->buffer = buffer; + data->size = size; + data->cblock_index = pblockindex; + } static void @@ -883,19 +902,17 @@ async_get_block_after(uv_work_t *req) { node::FatalException(try_catch); } } else { - const CBlock& cblock = data->cblock; CBlockIndex* cblock_index = data->cblock_index; - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - ssBlock << cblock; - std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + Local rawNodeBuffer = node::Buffer::New(isolate, data->buffer, data->size); - Local jsblock = NanNew(strHex); + delete data->buffer; + data->buffer = NULL; const unsigned argc = 2; Local argv[argc] = { Local::New(isolate, NanNull()), - Local::New(isolate, jsblock) + rawNodeBuffer }; TryCatch try_catch; cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);