diff --git a/lib/bitcoind.js b/lib/bitcoind.js index 92e9657d..6f111441 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -326,6 +326,8 @@ function Block(data) { } }); + this.vMerkleTree = data.merkletree || data.vMerkleTree; + this.toHex(); } @@ -335,6 +337,7 @@ Block.isBlock = function(block) { return block._isBlock === Block._blockFlag; }; +// NOTE: Could just call tx.GetHash() in C++ Block.prototype.hash = Block.prototype.getHash = function(enc) { if (!this._hash) { @@ -536,6 +539,7 @@ Transaction.prototype.isNull = function() { ; }; +// NOTE: Could just call tx.GetHash() in C++ Transaction.prototype.hash = Transaction.prototype.getHash = function(enc) { if (!this._hash) { diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 5b78f800..00a86d64 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -1214,6 +1214,29 @@ NAN_METHOD(VerifyTransaction) { NanReturnValue(NanNew(valid && standard)); } +// extern int64_t nTransactionFee; +int64_t nTransactionFee = 0; + +bool SelectCoins(CWallet& wallet, int64_t nTargetValue, + set >& setCoinsRet, + int64_t& nValueRet, const CCoinControl* coinControl) { + vector vCoins; + wallet.AvailableCoins(vCoins, true, coinControl); + + // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) + if (coinControl && coinControl->HasSelected()) { + BOOST_FOREACH(const COutput& out, vCoins) { + nValueRet += out.tx->vout[out.i].nValue; + setCoinsRet.insert(make_pair(out.tx, out.i)); + } + return (nValueRet >= nTargetValue); + } + + return (wallet.SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || + wallet.SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || + (bSpendZeroConfChange && wallet.SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); +} + NAN_METHOD(FillTransaction) { NanScope(); @@ -1232,10 +1255,59 @@ NAN_METHOD(FillTransaction) { CDataStream ssData(ParseHex(tx_hex), SER_NETWORK, PROTOCOL_VERSION); ssData >> tx; + // Get setCoins + int64_t nValueTotal = 0; + CScript scriptPubKeyMain; + bool scriptPubKeySet = false; + for (unsigned int vo = 0; vo < tx.vout.size(); vo++) { + const CTxOut& txout = tx.vout[vo]; + int64_t nValue = txout.nValue; + const CScript& scriptPubKey = txout.scriptPubKey; + if (!scriptPubKeySet) { + scriptPubKeyMain = scriptPubKey; + scriptPubKeySet = true; + } + nValueTotal += nValue; + } + + int64_t nValue = nValueTotal; + // Check amount + if (nValue <= 0) + return NanThrowError("Invalid amount"); + if (nValue + nTransactionFee > pwalletMain->GetBalance()) + return NanThrowError("Insufficient funds"); + + CScript scriptPubKey = scriptPubKeyMain; + //CScript scriptPubKey; + //scriptPubKey.SetDestination(address); + + CWalletTx wtxNew; + + CReserveKey reservekey(pwalletMain); + int64_t nFeeRet = nTransactionFee; + + if (pwalletMain->IsLocked()) { + return NanThrowError("Error: Wallet locked, unable to create transaction!"); + } + + const CCoinControl coinControl; + + vector< pair > vecSend; + vecSend.push_back(make_pair(scriptPubKey, nValue)); + + int64_t nTotalValue = nValue + nFeeRet; + set > setCoins; + int64_t nValueIn = 0; + + //if (!pwalletMain->SelectCoins(nTotalValue, setCoins, nValueIn, &coinControl)) { + if (!SelectCoins(*pwalletMain, nTotalValue, setCoins, nValueIn, &coinControl)) { + return NanThrowError("Insufficient funds"); + } + // Fill vin if (tx.vin.empty()) { BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) { - tx.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); + tx.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); } } @@ -1250,7 +1322,7 @@ NAN_METHOD(FillTransaction) { Local entry = NanNew(); ctx_to_jstx(tx, 0, entry); - NanReturnValue(tx); + NanReturnValue(entry); } /** @@ -1918,6 +1990,18 @@ cblock_to_jsblock(const CBlock& block, const CBlockIndex* blockindex, LocalSet(NanNew("version"), NanNew(block.nVersion)); obj->Set(NanNew("merkleroot"), NanNew(block.hashMerkleRoot.GetHex())); + // Build merkle tree + if (block.vMerkleTree.empty()) { + block.BuildMerkleTree(); + } + Local merkle = NanNew(); + int mi = 0; + BOOST_FOREACH(uint256& hash, block.vMerkleTree) { + merkle->Set(mi, NanNew(hash.ToString())); + mi++; + } + obj->Set(NanNew("merkletree"), merkle); + Local txs = NanNew(); int ti = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) {