diff --git a/example/index.js b/example/index.js index 0d894e90..3d4349e9 100755 --- a/example/index.js +++ b/example/index.js @@ -14,10 +14,10 @@ bitcoind.start(function(err) { }); bitcoind.on('open', function(status) { console.log('bitcoind: status="%s"', status); - // getBlocks(bitcoind); - bitcoind.on('block', function(block) { - console.log('Found block: %j', block); - }); + getBlocks(bitcoind); + // bitcoind.on('block', function(block) { + // console.log('Found block: %j', block); + // }); }); }); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index b2af51e8..ae16b9ca 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -175,6 +175,12 @@ async_poll_blocks(uv_work_t *req); static void async_poll_blocks_after(uv_work_t *req); +static void +ctx_to_js(const CTransaction& tx, uint256 hashBlock, Local entry); + +static void +cblock_to_js(const CBlock& block, const CBlockIndex* blockindex, Local obj); + extern "C" void init(Handle); @@ -762,125 +768,7 @@ async_get_block_after(uv_work_t *req) { const CBlockIndex* blockindex = data->result_blockindex; Local obj = NanNew(); - obj->Set(NanNew("hash"), NanNew(block.GetHash().GetHex().c_str())); - CMerkleTx txGen(block.vtx[0]); - txGen.SetMerkleBranch(&block); - obj->Set(NanNew("confirmations"), NanNew((int)txGen.GetDepthInMainChain())); - obj->Set(NanNew("size"), NanNew((int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); - obj->Set(NanNew("height"), NanNew(blockindex->nHeight)); - obj->Set(NanNew("version"), NanNew(block.nVersion)); - obj->Set(NanNew("merkleroot"), NanNew(block.hashMerkleRoot.GetHex())); - - Local txs = NanNew(); - int ti = 0; - BOOST_FOREACH(const CTransaction& tx, block.vtx) { - Local entry = NanNew(); - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << tx; - string strHex = HexStr(ssTx.begin(), ssTx.end()); - entry->Set(NanNew("hex"), NanNew(strHex)); - - entry->Set(NanNew("txid"), NanNew(tx.GetHash().GetHex())); - entry->Set(NanNew("version"), NanNew(tx.nVersion)); - entry->Set(NanNew("locktime"), NanNew(tx.nLockTime)); - - Local vin = NanNew(); - int vi = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - Local in = NanNew(); - if (tx.IsCoinBase()) { - in->Set(NanNew("coinbase"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - } else { - in->Set(NanNew("txid"), NanNew(txin.prevout.hash.GetHex())); - in->Set(NanNew("vout"), NanNew((boost::int64_t)txin.prevout.n)); - Local o = NanNew(); - o->Set(NanNew("asm"), NanNew(txin.scriptSig.ToString())); - o->Set(NanNew("hex"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - in->Set(NanNew("scriptSig"), o); - } - in->Set(NanNew("sequence"), NanNew((boost::int64_t)txin.nSequence)); - vin->Set(vi, in); - vi++; - } - entry->Set(NanNew("vin"), vin); - - Local vout = NanNew(); - for (unsigned int vo = 0; vo < tx.vout.size(); vo++) { - const CTxOut& txout = tx.vout[vo]; - Local out = NanNew(); - out->Set(NanNew("value"), NanNew(txout.nValue)); - out->Set(NanNew("n"), NanNew((boost::int64_t)vo)); - - Local o = NanNew(); - { - const CScript& scriptPubKey = txout.scriptPubKey; - Local out = o; - bool fIncludeHex = true; - - txnouttype type; - vector addresses; - int nRequired; - out->Set(NanNew("asm"), NanNew(scriptPubKey.ToString())); - if (fIncludeHex) { - out->Set(NanNew("hex"), NanNew(HexStr(scriptPubKey.begin(), scriptPubKey.end()))); - } - if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { - out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); - } else { - out->Set(NanNew("reqSigs"), NanNew(nRequired)); - out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); - Local a = NanNew(); - int ai = 0; - BOOST_FOREACH(const CTxDestination& addr, addresses) { - a->Set(ai, NanNew(CBitcoinAddress(addr).ToString())); - ai++; - } - out->Set(NanNew("addresses"), a); - } - } - out->Set(NanNew("scriptPubKey"), o); - - vout->Set(vo, out); - } - entry->Set(NanNew("vout"), vout); - - { - const uint256 hashBlock = block.GetHash(); - if (hashBlock != 0) { - entry->Set(NanNew("blockhash"), NanNew(hashBlock.GetHex())); - map::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end() && (*mi).second) { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) { - entry->Set(NanNew("confirmations"), - NanNew(1 + chainActive.Height() - pindex->nHeight)); - entry->Set(NanNew("time"), NanNew((boost::int64_t)pindex->nTime)); - entry->Set(NanNew("blocktime"), NanNew((boost::int64_t)pindex->nTime)); - } else { - entry->Set(NanNew("confirmations"), NanNew(0)); - } - } - } - } - - txs->Set(ti, entry); - ti++; - } - obj->Set(NanNew("tx"), txs); - - obj->Set(NanNew("time"), NanNew((boost::int64_t)block.GetBlockTime())); - obj->Set(NanNew("nonce"), NanNew((boost::uint64_t)block.nNonce)); - obj->Set(NanNew("bits"), NanNew(block.nBits)); - obj->Set(NanNew("difficulty"), NanNew(GetDifficulty(blockindex))); - obj->Set(NanNew("chainwork"), NanNew(blockindex->nChainWork.GetHex())); - if (blockindex->pprev) { - obj->Set(NanNew("previousblockhash"), NanNew(blockindex->pprev->GetBlockHash().GetHex())); - } - CBlockIndex *pnext = chainActive.Next(blockindex); - if (pnext) { - obj->Set(NanNew("nextblockhash"), NanNew(pnext->GetBlockHash().GetHex())); - } + cblock_to_js(block, blockindex, obj); const unsigned argc = 2; Local argv[argc] = { @@ -999,85 +887,7 @@ async_get_tx_after(uv_work_t *req) { Local entry = NanNew(); entry->Set(NanNew("hex"), NanNew(strHex)); - entry->Set(NanNew("txid"), NanNew(tx.GetHash().GetHex())); - entry->Set(NanNew("version"), NanNew(tx.nVersion)); - entry->Set(NanNew("locktime"), NanNew(tx.nLockTime)); - - Local vin = NanNew(); - int vi = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - Local in = NanNew(); - if (tx.IsCoinBase()) { - in->Set(NanNew("coinbase"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - } else { - in->Set(NanNew("txid"), NanNew(txin.prevout.hash.GetHex())); - in->Set(NanNew("vout"), NanNew((boost::int64_t)txin.prevout.n)); - Local o = NanNew(); - o->Set(NanNew("asm"), NanNew(txin.scriptSig.ToString())); - o->Set(NanNew("hex"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - in->Set(NanNew("scriptSig"), o); - } - in->Set(NanNew("sequence"), NanNew((boost::int64_t)txin.nSequence)); - vin->Set(vi, in); - vi++; - } - entry->Set(NanNew("vin"), vin); - - Local vout = NanNew(); - for (unsigned int vo = 0; vo < tx.vout.size(); vo++) { - const CTxOut& txout = tx.vout[vo]; - Local out = NanNew(); - out->Set(NanNew("value"), NanNew(txout.nValue)); - out->Set(NanNew("n"), NanNew((boost::int64_t)vo)); - - Local o = NanNew(); - { - const CScript& scriptPubKey = txout.scriptPubKey; - Local out = o; - bool fIncludeHex = true; - - txnouttype type; - vector addresses; - int nRequired; - out->Set(NanNew("asm"), NanNew(scriptPubKey.ToString())); - if (fIncludeHex) { - out->Set(NanNew("hex"), NanNew(HexStr(scriptPubKey.begin(), scriptPubKey.end()))); - } - if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { - out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); - } else { - out->Set(NanNew("reqSigs"), NanNew(nRequired)); - out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); - Local a = NanNew(); - int ai = 0; - BOOST_FOREACH(const CTxDestination& addr, addresses) { - a->Set(ai, NanNew(CBitcoinAddress(addr).ToString())); - ai++; - } - out->Set(NanNew("addresses"), a); - } - } - out->Set(NanNew("scriptPubKey"), o); - - vout->Set(vo, out); - } - entry->Set(NanNew("vout"), vout); - - if (hashBlock != 0) { - entry->Set(NanNew("blockhash"), NanNew(hashBlock.GetHex())); - map::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end() && (*mi).second) { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) { - entry->Set(NanNew("confirmations"), - NanNew(1 + chainActive.Height() - pindex->nHeight)); - entry->Set(NanNew("time"), NanNew((boost::int64_t)pindex->nTime)); - entry->Set(NanNew("blocktime"), NanNew((boost::int64_t)pindex->nTime)); - } else { - entry->Set(NanNew("confirmations"), NanNew(0)); - } - } - } + ctx_to_js(tx, hashBlock, entry); const unsigned argc = 2; Local argv[argc] = { @@ -1196,6 +1006,217 @@ async_poll_blocks_after(uv_work_t *req) { delete req; } +/** + * Conversions + */ + +static void +cblock_to_js(const CBlock& block, const CBlockIndex* blockindex, Local obj) { + obj->Set(NanNew("hash"), NanNew(block.GetHash().GetHex().c_str())); + CMerkleTx txGen(block.vtx[0]); + txGen.SetMerkleBranch(&block); + obj->Set(NanNew("confirmations"), NanNew((int)txGen.GetDepthInMainChain())); + obj->Set(NanNew("size"), NanNew((int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); + obj->Set(NanNew("height"), NanNew(blockindex->nHeight)); + obj->Set(NanNew("version"), NanNew(block.nVersion)); + obj->Set(NanNew("merkleroot"), NanNew(block.hashMerkleRoot.GetHex())); + + Local txs = NanNew(); + int ti = 0; + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + Local entry = NanNew(); + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + string strHex = HexStr(ssTx.begin(), ssTx.end()); + entry->Set(NanNew("hex"), NanNew(strHex)); + + entry->Set(NanNew("txid"), NanNew(tx.GetHash().GetHex())); + entry->Set(NanNew("version"), NanNew(tx.nVersion)); + entry->Set(NanNew("locktime"), NanNew(tx.nLockTime)); + + Local vin = NanNew(); + int vi = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + Local in = NanNew(); + if (tx.IsCoinBase()) { + in->Set(NanNew("coinbase"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + } else { + in->Set(NanNew("txid"), NanNew(txin.prevout.hash.GetHex())); + in->Set(NanNew("vout"), NanNew((boost::int64_t)txin.prevout.n)); + Local o = NanNew(); + o->Set(NanNew("asm"), NanNew(txin.scriptSig.ToString())); + o->Set(NanNew("hex"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + in->Set(NanNew("scriptSig"), o); + } + in->Set(NanNew("sequence"), NanNew((boost::int64_t)txin.nSequence)); + vin->Set(vi, in); + vi++; + } + entry->Set(NanNew("vin"), vin); + + Local vout = NanNew(); + for (unsigned int vo = 0; vo < tx.vout.size(); vo++) { + const CTxOut& txout = tx.vout[vo]; + Local out = NanNew(); + out->Set(NanNew("value"), NanNew(txout.nValue)); + out->Set(NanNew("n"), NanNew((boost::int64_t)vo)); + + Local o = NanNew(); + { + const CScript& scriptPubKey = txout.scriptPubKey; + Local out = o; + bool fIncludeHex = true; + + txnouttype type; + vector addresses; + int nRequired; + out->Set(NanNew("asm"), NanNew(scriptPubKey.ToString())); + if (fIncludeHex) { + out->Set(NanNew("hex"), NanNew(HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + } + if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { + out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); + } else { + out->Set(NanNew("reqSigs"), NanNew(nRequired)); + out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); + Local a = NanNew(); + int ai = 0; + BOOST_FOREACH(const CTxDestination& addr, addresses) { + a->Set(ai, NanNew(CBitcoinAddress(addr).ToString())); + ai++; + } + out->Set(NanNew("addresses"), a); + } + } + out->Set(NanNew("scriptPubKey"), o); + + vout->Set(vo, out); + } + entry->Set(NanNew("vout"), vout); + + { + const uint256 hashBlock = block.GetHash(); + if (hashBlock != 0) { + entry->Set(NanNew("blockhash"), NanNew(hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) { + CBlockIndex* pindex = (*mi).second; + if (chainActive.Contains(pindex)) { + entry->Set(NanNew("confirmations"), + NanNew(1 + chainActive.Height() - pindex->nHeight)); + entry->Set(NanNew("time"), NanNew((boost::int64_t)pindex->nTime)); + entry->Set(NanNew("blocktime"), NanNew((boost::int64_t)pindex->nTime)); + } else { + entry->Set(NanNew("confirmations"), NanNew(0)); + } + } + } + } + + txs->Set(ti, entry); + ti++; + } + obj->Set(NanNew("tx"), txs); + + obj->Set(NanNew("time"), NanNew((boost::int64_t)block.GetBlockTime())); + obj->Set(NanNew("nonce"), NanNew((boost::uint64_t)block.nNonce)); + obj->Set(NanNew("bits"), NanNew(block.nBits)); + obj->Set(NanNew("difficulty"), NanNew(GetDifficulty(blockindex))); + obj->Set(NanNew("chainwork"), NanNew(blockindex->nChainWork.GetHex())); + if (blockindex->pprev) { + obj->Set(NanNew("previousblockhash"), NanNew(blockindex->pprev->GetBlockHash().GetHex())); + } + CBlockIndex *pnext = chainActive.Next(blockindex); + if (pnext) { + obj->Set(NanNew("nextblockhash"), NanNew(pnext->GetBlockHash().GetHex())); + } +} + +static void +ctx_to_js(const CTransaction& tx, uint256 hashBlock, Local entry) { + // entry->Set(NanNew("hex"), NanNew(strHex)); + entry->Set(NanNew("txid"), NanNew(tx.GetHash().GetHex())); + entry->Set(NanNew("version"), NanNew(tx.nVersion)); + entry->Set(NanNew("locktime"), NanNew(tx.nLockTime)); + + Local vin = NanNew(); + int vi = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + Local in = NanNew(); + if (tx.IsCoinBase()) { + in->Set(NanNew("coinbase"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + } else { + in->Set(NanNew("txid"), NanNew(txin.prevout.hash.GetHex())); + in->Set(NanNew("vout"), NanNew((boost::int64_t)txin.prevout.n)); + Local o = NanNew(); + o->Set(NanNew("asm"), NanNew(txin.scriptSig.ToString())); + o->Set(NanNew("hex"), NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + in->Set(NanNew("scriptSig"), o); + } + in->Set(NanNew("sequence"), NanNew((boost::int64_t)txin.nSequence)); + vin->Set(vi, in); + vi++; + } + entry->Set(NanNew("vin"), vin); + + Local vout = NanNew(); + for (unsigned int vo = 0; vo < tx.vout.size(); vo++) { + const CTxOut& txout = tx.vout[vo]; + Local out = NanNew(); + out->Set(NanNew("value"), NanNew(txout.nValue)); + out->Set(NanNew("n"), NanNew((boost::int64_t)vo)); + + Local o = NanNew(); + { + const CScript& scriptPubKey = txout.scriptPubKey; + Local out = o; + bool fIncludeHex = true; + + txnouttype type; + vector addresses; + int nRequired; + out->Set(NanNew("asm"), NanNew(scriptPubKey.ToString())); + if (fIncludeHex) { + out->Set(NanNew("hex"), NanNew(HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + } + if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { + out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); + } else { + out->Set(NanNew("reqSigs"), NanNew(nRequired)); + out->Set(NanNew("type"), NanNew(GetTxnOutputType(type))); + Local a = NanNew(); + int ai = 0; + BOOST_FOREACH(const CTxDestination& addr, addresses) { + a->Set(ai, NanNew(CBitcoinAddress(addr).ToString())); + ai++; + } + out->Set(NanNew("addresses"), a); + } + } + out->Set(NanNew("scriptPubKey"), o); + + vout->Set(vo, out); + } + entry->Set(NanNew("vout"), vout); + + if (hashBlock != 0) { + entry->Set(NanNew("blockhash"), NanNew(hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) { + CBlockIndex* pindex = (*mi).second; + if (chainActive.Contains(pindex)) { + entry->Set(NanNew("confirmations"), + NanNew(1 + chainActive.Height() - pindex->nHeight)); + entry->Set(NanNew("time"), NanNew((boost::int64_t)pindex->nTime)); + entry->Set(NanNew("blocktime"), NanNew((boost::int64_t)pindex->nTime)); + } else { + entry->Set(NanNew("confirmations"), NanNew(0)); + } + } + } +} + /** * Init */