Added bindings to be able to listen to tx leaving mempool.
This commit is contained in:
parent
275a0b57ea
commit
f0ec424161
@ -367,14 +367,27 @@ index f94771a..72ee00e 100644
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/src/net.h b/src/net.h
|
diff --git a/src/net.h b/src/net.h
|
||||||
index 17502b9..e181d68 100644
|
index 17502b9..c9ae1b2 100644
|
||||||
--- a/src/net.h
|
--- a/src/net.h
|
||||||
+++ b/src/net.h
|
+++ b/src/net.h
|
||||||
@@ -99,6 +99,7 @@ struct CNodeSignals
|
@@ -99,6 +99,8 @@ struct CNodeSignals
|
||||||
{
|
{
|
||||||
boost::signals2::signal<int ()> GetHeight;
|
boost::signals2::signal<int ()> GetHeight;
|
||||||
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
|
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
|
||||||
+ boost::signals2::signal<bool (const CTransaction&)> TxToMemPool;
|
+ boost::signals2::signal<bool (const CTransaction&)> TxToMemPool;
|
||||||
|
+ boost::signals2::signal<bool (const CTransaction&)> TxLeaveMemPool;
|
||||||
boost::signals2::signal<bool (CNode*, bool), CombinerAll> SendMessages;
|
boost::signals2::signal<bool (CNode*, bool), CombinerAll> SendMessages;
|
||||||
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
|
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
|
||||||
boost::signals2::signal<void (NodeId)> FinalizeNode;
|
boost::signals2::signal<void (NodeId)> FinalizeNode;
|
||||||
|
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
|
||||||
|
index c3d1b60..03e265d 100644
|
||||||
|
--- a/src/txmempool.cpp
|
||||||
|
+++ b/src/txmempool.cpp
|
||||||
|
@@ -133,6 +133,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
|
||||||
|
if (!mapTx.count(hash))
|
||||||
|
continue;
|
||||||
|
const CTransaction& tx = mapTx[hash].GetTx();
|
||||||
|
+ GetNodeSignals().TxLeaveMemPool(tx);
|
||||||
|
if (fRecursive) {
|
||||||
|
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||||
|
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
|
||||||
|
|||||||
@ -360,6 +360,30 @@ describe('Daemon Binding Functionality', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('transactions leaving the mempool', function() {
|
||||||
|
it('receive event when transaction leaves', function(done) {
|
||||||
|
|
||||||
|
// add transaction to build a new block
|
||||||
|
var tx = bitcore.Transaction();
|
||||||
|
tx.from(utxos[4]);
|
||||||
|
tx.change(privateKey.toAddress());
|
||||||
|
tx.to(destKey.toAddress(), utxos[4].amount * 1e8 - 1000);
|
||||||
|
tx.sign(bitcore.PrivateKey.fromWIF(utxos[4].privateKeyWIF));
|
||||||
|
bitcoind.sendTransaction(tx.serialize());
|
||||||
|
|
||||||
|
bitcoind.once('txleave', function(txInfo) {
|
||||||
|
txInfo.hash.should.equal(tx.hash);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.generate(1, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('mempool functionality', function() {
|
describe('mempool functionality', function() {
|
||||||
|
|
||||||
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
|
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
|
||||||
|
|||||||
@ -110,12 +110,19 @@ Bitcoin.prototype._registerEventHandlers = function() {
|
|||||||
// Set the height and emit a new tip
|
// Set the height and emit a new tip
|
||||||
bindings.onTipUpdate(self._onTipUpdate.bind(this));
|
bindings.onTipUpdate(self._onTipUpdate.bind(this));
|
||||||
|
|
||||||
// Register callback function to handle incoming transactions
|
// Register callback function to handle transactions entering the mempool
|
||||||
bindings.startTxMon(function(txs) {
|
bindings.startTxMon(function(txs) {
|
||||||
for(var i = 0; i < txs.length; i++) {
|
for(var i = 0; i < txs.length; i++) {
|
||||||
self.emit('tx', txs[i]);
|
self.emit('tx', txs[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register callback function to handle transactions leaving the mempool
|
||||||
|
bindings.startTxMonLeave(function(txs) {
|
||||||
|
for(var i = 0; i < txs.length; i++) {
|
||||||
|
self.emit('txleave', txs[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._onReady = function(result, callback) {
|
Bitcoin.prototype._onReady = function(result, callback) {
|
||||||
|
|||||||
@ -39,6 +39,9 @@ extern int64_t nTimeBestReceived;
|
|||||||
static void
|
static void
|
||||||
tx_notifier(uv_async_t *handle);
|
tx_notifier(uv_async_t *handle);
|
||||||
|
|
||||||
|
static void
|
||||||
|
txleave_notifier(uv_async_t *handle);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
async_tip_update(uv_work_t *req);
|
async_tip_update(uv_work_t *req);
|
||||||
|
|
||||||
@ -90,6 +93,9 @@ async_get_tx_and_info_after(uv_work_t *req);
|
|||||||
static bool
|
static bool
|
||||||
queueTx(const CTransaction&);
|
queueTx(const CTransaction&);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
queueTxLeave(const CTransaction&);
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
init(Handle<Object>);
|
init(Handle<Object>);
|
||||||
|
|
||||||
@ -98,9 +104,13 @@ init(Handle<Object>);
|
|||||||
* Used only by bitcoind functions.
|
* Used only by bitcoind functions.
|
||||||
*/
|
*/
|
||||||
static std::vector<CTransaction> txQueue;
|
static std::vector<CTransaction> txQueue;
|
||||||
|
static std::vector<CTransaction> txQueueLeave;
|
||||||
static uv_async_t txmon_async;
|
static uv_async_t txmon_async;
|
||||||
|
static uv_async_t txmonleave_async;
|
||||||
static Eternal<Function> txmon_callback;
|
static Eternal<Function> txmon_callback;
|
||||||
|
static Eternal<Function> txmonleave_callback;
|
||||||
static bool txmon_callback_available;
|
static bool txmon_callback_available;
|
||||||
|
static bool txmonleave_callback_available;
|
||||||
|
|
||||||
static volatile bool shutdown_complete = false;
|
static volatile bool shutdown_complete = false;
|
||||||
static char *g_data_dir = NULL;
|
static char *g_data_dir = NULL;
|
||||||
@ -259,6 +269,21 @@ NAN_METHOD(StartTxMon) {
|
|||||||
info.GetReturnValue().Set(Null());
|
info.GetReturnValue().Set(Null());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NAN_METHOD(StartTxMonLeave) {
|
||||||
|
Isolate* isolate = info.GetIsolate();
|
||||||
|
Local<Function> callback = Local<Function>::Cast(info[0]);
|
||||||
|
Eternal<Function> cb(isolate, callback);
|
||||||
|
txmonleave_callback = cb;
|
||||||
|
txmonleave_callback_available = true;
|
||||||
|
|
||||||
|
CNodeSignals& nodeSignals = GetNodeSignals();
|
||||||
|
nodeSignals.TxLeaveMemPool.connect(&queueTxLeave);
|
||||||
|
|
||||||
|
uv_async_init(uv_default_loop(), &txmonleave_async, txleave_notifier);
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(Null());
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tx_notifier(uv_async_t *handle) {
|
tx_notifier(uv_async_t *handle) {
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
Isolate* isolate = Isolate::GetCurrent();
|
||||||
@ -307,6 +332,53 @@ queueTx(const CTransaction& tx) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
txleave_notifier(uv_async_t *handle) {
|
||||||
|
Isolate* isolate = Isolate::GetCurrent();
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
|
Local<Array> results = Array::New(isolate);
|
||||||
|
int arrayIndex = 0;
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
BOOST_FOREACH(const CTransaction& tx, txQueueLeave) {
|
||||||
|
|
||||||
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ssTx << tx;
|
||||||
|
std::string stx = ssTx.str();
|
||||||
|
Nan::MaybeLocal<v8::Object> txBuffer = Nan::CopyBuffer((char *)stx.c_str(), stx.size());
|
||||||
|
|
||||||
|
uint256 hash = tx.GetHash();
|
||||||
|
|
||||||
|
Local<Object> obj = New<Object>();
|
||||||
|
|
||||||
|
Nan::Set(obj, New("buffer").ToLocalChecked(), txBuffer.ToLocalChecked());
|
||||||
|
Nan::Set(obj, New("hash").ToLocalChecked(), New(hash.GetHex()).ToLocalChecked());
|
||||||
|
|
||||||
|
results->Set(arrayIndex, obj);
|
||||||
|
arrayIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned argc = 1;
|
||||||
|
Local<Value> argv[argc] = {
|
||||||
|
Local<Value>::New(isolate, results)
|
||||||
|
};
|
||||||
|
|
||||||
|
Local<Function> cb = txmonleave_callback.Get(isolate);
|
||||||
|
|
||||||
|
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
|
||||||
|
|
||||||
|
txQueueLeave.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
static bool
|
||||||
|
queueTxLeave(const CTransaction& tx) {
|
||||||
|
LOCK(cs_main);
|
||||||
|
txQueueLeave.push_back(tx);
|
||||||
|
uv_async_send(&txmonleave_async);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions
|
* Functions
|
||||||
*/
|
*/
|
||||||
@ -1527,6 +1599,7 @@ NAN_MODULE_INIT(init) {
|
|||||||
Nan::Set(target, New("sendTransaction").ToLocalChecked(), GetFunction(New<FunctionTemplate>(SendTransaction)).ToLocalChecked());
|
Nan::Set(target, New("sendTransaction").ToLocalChecked(), GetFunction(New<FunctionTemplate>(SendTransaction)).ToLocalChecked());
|
||||||
Nan::Set(target, New("estimateFee").ToLocalChecked(), GetFunction(New<FunctionTemplate>(EstimateFee)).ToLocalChecked());
|
Nan::Set(target, New("estimateFee").ToLocalChecked(), GetFunction(New<FunctionTemplate>(EstimateFee)).ToLocalChecked());
|
||||||
Nan::Set(target, New("startTxMon").ToLocalChecked(), GetFunction(New<FunctionTemplate>(StartTxMon)).ToLocalChecked());
|
Nan::Set(target, New("startTxMon").ToLocalChecked(), GetFunction(New<FunctionTemplate>(StartTxMon)).ToLocalChecked());
|
||||||
|
Nan::Set(target, New("startTxMonLeave").ToLocalChecked(), GetFunction(New<FunctionTemplate>(StartTxMonLeave)).ToLocalChecked());
|
||||||
Nan::Set(target, New("syncPercentage").ToLocalChecked(), GetFunction(New<FunctionTemplate>(SyncPercentage)).ToLocalChecked());
|
Nan::Set(target, New("syncPercentage").ToLocalChecked(), GetFunction(New<FunctionTemplate>(SyncPercentage)).ToLocalChecked());
|
||||||
Nan::Set(target, New("isSynced").ToLocalChecked(), GetFunction(New<FunctionTemplate>(IsSynced)).ToLocalChecked());
|
Nan::Set(target, New("isSynced").ToLocalChecked(), GetFunction(New<FunctionTemplate>(IsSynced)).ToLocalChecked());
|
||||||
Nan::Set(target, New("getBestBlockHash").ToLocalChecked(), GetFunction(New<FunctionTemplate>(GetBestBlockHash)).ToLocalChecked());
|
Nan::Set(target, New("getBestBlockHash").ToLocalChecked(), GetFunction(New<FunctionTemplate>(GetBestBlockHash)).ToLocalChecked());
|
||||||
|
|||||||
@ -144,7 +144,8 @@ describe('Bitcoin Service', function() {
|
|||||||
name.should.equal('bitcoind.node');
|
name.should.equal('bitcoind.node');
|
||||||
return {
|
return {
|
||||||
onTipUpdate: sinon.stub(),
|
onTipUpdate: sinon.stub(),
|
||||||
startTxMon: sinon.stub().callsArgWith(0, [transaction])
|
startTxMon: sinon.stub().callsArgWith(0, [transaction]),
|
||||||
|
startTxMonLeave: sinon.stub().callsArgWith(0, [transaction])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -175,7 +176,8 @@ describe('Bitcoin Service', function() {
|
|||||||
callback(height++);
|
callback(height++);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
startTxMon: sinon.stub()
|
startTxMon: sinon.stub(),
|
||||||
|
startTxMonLeave: sinon.stub()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user