From 9c2726b09cfdb8bf2ec69e8a8b9beb180b8c8194 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 7 Jul 2015 23:24:22 -0400 Subject: [PATCH 1/4] Read block as a buffer --- src/bitcoindjs.cc | 60 +++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 3611d043..8b11078d 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,34 +837,45 @@ 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; - } - std::string strHash = data->hash; uint256 hash(strHash); if (mapBlockIndex.count(hash) == 0) { - data->err_msg = std::string("Block not found."); + data->err_msg = std::string("Block not found."); } else { - CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; - if(!ReadBlockFromDisk(block, pblockindex)) { - data->err_msg = std::string("Can't read block from disk"); - } else { - data->cblock = block; - data->cblock_index = pblockindex; + 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[size]; + fread((void *)buffer, sizeof(char), size, blockFile); + fclose(blockFile); + + data->buffer = buffer; + data->size = size; + data->cblock_index = pblockindex; } } @@ -883,19 +896,14 @@ 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 jsblock = NanNew(strHex); + Local rawNodeBuffer = node::Buffer::New(isolate, data->buffer, data->size); 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); From 69ed6efcb215c1e6656da0a201142ab418674934 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 9 Jul 2015 16:12:38 -0400 Subject: [PATCH 2/4] Allocate memory for block buffer. --- integration/index.js | 2 +- src/bitcoindjs.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integration/index.js b/integration/index.js index 2eb4160b..04849e6c 100644 --- a/integration/index.js +++ b/integration/index.js @@ -51,7 +51,7 @@ describe('Basic Functionality', function() { 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(); }); }); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 8b11078d..0c0c6bc5 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -869,7 +869,7 @@ async_get_block(uv_work_t *req) { fread(&size, sizeof(uint32_t), 1, blockFile); // Read block - char buffer[size]; + char* buffer = (char *)malloc(sizeof(char) * size); fread((void *)buffer, sizeof(char), size, blockFile); fclose(blockFile); From 24e705b26569ad443b6247c29880e1131fc55bb2 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 9 Jul 2015 16:45:30 -0400 Subject: [PATCH 3/4] Get blocks by height. --- integration/index.js | 22 +++++++++++++- src/bitcoindjs.cc | 72 ++++++++++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/integration/index.js b/integration/index.js index 04849e6c..f7cbe53c 100644 --- a/integration/index.js +++ b/integration/index.js @@ -45,7 +45,7 @@ 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); @@ -58,4 +58,24 @@ describe('Basic Functionality', function() { }); }); + 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(); + }); + }); + }); + }); + }); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 0c0c6bc5..a62f3d06 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -837,46 +837,52 @@ static void async_get_block(uv_work_t *req) { async_block_data* data = static_cast(req->data); + 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 { - - CBlockIndex* 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"); + if (mapBlockIndex.count(hash) == 0) { + data->err_msg = std::string("Block not found."); return; + } else { + pblockindex = mapBlockIndex[hash]; } - - // 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; } + + 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 From 91004a24a934a58194b8c16737021d2163a38f90 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 9 Jul 2015 17:34:37 -0400 Subject: [PATCH 4/4] Free block buffer memory. --- integration/index.js | 18 ++++++++++++++++++ src/bitcoindjs.cc | 3 +++ 2 files changed, 21 insertions(+) diff --git a/integration/index.js b/integration/index.js index f7cbe53c..10758fa5 100644 --- a/integration/index.js +++ b/integration/index.js @@ -78,4 +78,22 @@ describe('Basic Functionality', function() { }); }); + 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 a62f3d06..28599bad 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -906,6 +906,9 @@ async_get_block_after(uv_work_t *req) { Local rawNodeBuffer = node::Buffer::New(isolate, data->buffer, data->size); + delete data->buffer; + data->buffer = NULL; + const unsigned argc = 2; Local argv[argc] = { Local::New(isolate, NanNull()),