Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add async rpc call z_sendmany #1271

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7c929cf
Add support for spending keys to the basic key store
str4d Aug 9, 2016
f88f51f
Implemented RPC calls z_importkey, z_exportkey, z_getnewaddress.
bitcartel Aug 10, 2016
62eea0d
Add z_importwallet and z_exportwallet to handle keys for both
bitcartel Aug 10, 2016
84ce3a5
Implemented z_listaddresses to return all the zaddr in the wallet.
bitcartel Aug 10, 2016
65c02f9
Add gtest to cover new methods in:
bitcartel Aug 11, 2016
9155cc6
Don't mark wallet as dirty if key already exists.
bitcartel Aug 11, 2016
e57e5e3
Added wallet rpc tests to cover:
bitcartel Aug 13, 2016
4df3999
Merge AddSpendingKeyPaymentAddress into AddSpendingKey to simplify API
str4d Aug 12, 2016
8cec3de
Consistent parameter naming
str4d Aug 12, 2016
d78026d
Add separate lock for SpendingKey key store operations
str4d Aug 16, 2016
9a3a427
Add async RPC queue and operation classes.
bitcartel Aug 16, 2016
e2898aa
Fixes #1193 so that during verification benchmarking it does not
bitcartel Aug 8, 2016
2c27fb2
Update variable.
bitcartel Aug 8, 2016
c90e1f0
Update equihash.cpp
Aug 10, 2016
6701699
Update test_equihash.cpp
Aug 11, 2016
54c9d68
Disable hardening when building for coverage reports.
defuse Aug 11, 2016
aa06d4a
Rework test to check for failure to return a spending key
str4d Aug 18, 2016
b51672e
ASSERT -> EXPECT in test to get more info per test run about future r…
str4d Aug 18, 2016
761d2a8
Add wallet method for finding spendable Notes in a CTransaction
str4d Aug 11, 2016
a423578
Store mapping between Notes and PaymentAddresses in CWalletTx
str4d Aug 11, 2016
f91ea7a
Cache ZCNoteDecryption objects for efficiency
str4d Aug 12, 2016
2a263db
Keep track of spent Notes, and detect and report conflicts
str4d Aug 12, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ BITCOIN_CORE_H = \
alert.h \
amount.h \
arith_uint256.h \
asyncrpcoperation.h \
asyncrpcqueue.h \
base58.h \
bloom.h \
chain.h \
Expand Down Expand Up @@ -162,6 +164,7 @@ BITCOIN_CORE_H = \
utiltime.h \
validationinterface.h \
version.h \
wallet/asyncrpcoperation_sendmany.h \
wallet/crypter.h \
wallet/db.h \
wallet/wallet.h \
Expand Down Expand Up @@ -191,6 +194,8 @@ libbitcoin_server_a_SOURCES = \
sendalert.cpp \
addrman.cpp \
alert.cpp \
asyncrpcoperation.cpp \
asyncrpcqueue.cpp \
bloom.cpp \
chain.cpp \
checkpoints.cpp \
Expand Down Expand Up @@ -224,6 +229,7 @@ libbitcoin_server_a_SOURCES = \
libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_SOURCES = \
zcbenchmarks.cpp \
wallet/asyncrpcoperation_sendmany.cpp \
wallet/crypter.cpp \
wallet/db.cpp \
wallet/rpcdump.cpp \
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.gtest.include
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ zcash_gtest_SOURCES = \
gtest/test_checktransaction.cpp \
gtest/test_equihash.cpp \
gtest/test_joinsplit.cpp \
gtest/test_keystore.cpp \
gtest/test_noteencryption.cpp \
gtest/test_merkletree.cpp \
gtest/test_circuit.cpp \
gtest/test_txid.cpp \
gtest/test_wallet.cpp \
gtest/test_wallet_zkeys.cpp \
gtest/test_libzcash_utils.cpp

zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC
Expand Down
147 changes: 147 additions & 0 deletions src/asyncrpcoperation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright (c) 2016 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "asyncrpcoperation.h"

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <string>
#include <ctime>
#include <chrono>

using namespace std;
using namespace json_spirit;

static boost::uuids::random_generator uuidgen;

std::map<OperationStatus, std::string> OperationStatusMap = {
{OperationStatus::READY, "queued"},
{OperationStatus::EXECUTING, "executing"},
{OperationStatus::CANCELLED, "cancelled"},
{OperationStatus::FAILED, "failed"},
{OperationStatus::SUCCESS, "success"}
};

AsyncRPCOperation::AsyncRPCOperation() : errorCode(0), errorMessage() {
// Set a unique reference for each operation
boost::uuids::uuid uuid = uuidgen();
std::string s = boost::uuids::to_string(uuid);
setId(s);

setState(OperationStatus::READY);
creationTime = (int64_t)time(NULL);
}

AsyncRPCOperation::AsyncRPCOperation(const AsyncRPCOperation& o) : id(o.id), creationTime(o.creationTime), state(o.state.load())
{
}


AsyncRPCOperation& AsyncRPCOperation::operator=( const AsyncRPCOperation& other ) {
this->id = other.getId();
this->creationTime = other.creationTime;
this->state.store(other.state.load());
return *this;
}


AsyncRPCOperation::~AsyncRPCOperation() {
}

void AsyncRPCOperation::cancel() {
if (isReady())
setState(OperationStatus::CANCELLED);
}


void AsyncRPCOperation::startExecutionClock() {
startTime = std::chrono::system_clock::now();
}

void AsyncRPCOperation::stopExecutionClock() {
endTime = std::chrono::system_clock::now();
}


// Implement this method in any subclass.
// This is just an example implementation.


void AsyncRPCOperation::main() {
if (isCancelled())
return;

setState(OperationStatus::EXECUTING);

//
// Do some work here...
//

startExecutionClock();

//std::this_thread::sleep_for(std::chrono::milliseconds(10000));

stopExecutionClock();


// If there was an error...
// setErrorCode(123);
// setErrorMessage("Murphy's law");
// setState(OperationStatus::FAILED);


// Otherwise
Value v("We have a result!");
setResult(v);
setState(OperationStatus::SUCCESS);
}

Value AsyncRPCOperation::getError() const {
if (!isFailed())
return Value::null;

Object error;
error.push_back(Pair("code", this->errorCode));
error.push_back(Pair("message", this->errorMessage));
return Value(error);
}

Value AsyncRPCOperation::getResult() const {
if (!isSuccess())
return Value::null;

return this->resultValue;
}


/*
* Returns a status Value object.
* If the operation has failed, it will include an error object.
* If the operation has succeeded, it will include the result value.
*/
Value AsyncRPCOperation::getStatus() const {
OperationStatus status = this->getState();
Object obj;
obj.push_back(Pair("id", this->getId()));
obj.push_back(Pair("status", OperationStatusMap[status]));
obj.push_back(Pair("creation_time", this->creationTime));
// creation, exec time, duration, exec end, etc.
Value err = this->getError();
if (!err.is_null()) {
obj.push_back(Pair("error", err.get_obj()));
}
Value result = this->getResult();
if (!result.is_null()) {
obj.push_back(Pair("result", result));

// Include execution time for successful operation
std::chrono::duration<double> elapsed_seconds = endTime - startTime;
obj.push_back(Pair("execution_secs", elapsed_seconds.count()));

}
return Value(obj);
}

148 changes: 148 additions & 0 deletions src/asyncrpcoperation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) 2016 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.


#ifndef ASYNCRPCOPERATION_H
#define ASYNCRPCOPERATION_H

#include <string>
#include <atomic>
#include <map>
#include <chrono>

#include "json/json_spirit_value.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"

using namespace std;
using namespace json_spirit;

/**
* AsyncRPCOperations are given to the AsyncRPCQueue for processing.
*
* How to subclass:
* Implement the main() method, this is where work is performed.
* Update the operation status as work is underway and completes.
*/

typedef std::string AsyncRPCOperationId;

typedef enum class operationStateEnum {
READY = 0,
EXECUTING,
CANCELLED,
FAILED,
SUCCESS
} OperationStatus;

class AsyncRPCOperation {
public:
AsyncRPCOperation();

// Todo: keep or delete copy constructors and assignment?
AsyncRPCOperation(const AsyncRPCOperation& orig);
AsyncRPCOperation& operator=( const AsyncRPCOperation& other );

virtual ~AsyncRPCOperation();

// Implement this method in your subclass.
virtual void main();

void cancel();

// Getters and setters

OperationStatus getState() const {
return state.load();
}

AsyncRPCOperationId getId() const {
return id;
}

int64_t getCreationTime() const {
return creationTime;
}

Value getStatus() const;

Value getError() const;

Value getResult() const;

int getErrorCode() const {
return errorCode;
}

std::string getErrorMessage() const {
return errorMessage;
}

bool isCancelled() const {
return OperationStatus::CANCELLED==getState();
}

bool isExecuting() const {
return OperationStatus::EXECUTING==getState();
}

bool isReady() const {
return OperationStatus::READY==getState();
}

bool isFailed() const {
return OperationStatus::FAILED==getState();
}

bool isSuccess() const {
return OperationStatus::SUCCESS==getState();
}

protected:

Value resultValue;
int errorCode;
std::string errorMessage;
std::atomic<OperationStatus> state;
std::chrono::time_point<std::chrono::system_clock> startTime, endTime;

void startExecutionClock();
void stopExecutionClock();

void setState(OperationStatus state) {
this->state.store(state);
}

void setErrorCode(int errorCode) {
this->errorCode = errorCode;
}

void setErrorMessage(std::string errorMessage) {
this->errorMessage = errorMessage;
}

void setResult(Value v) {
this->resultValue = v;
}

private:

// Todo: Private for now. If copying an operation is possible, should it
// receive a new id and a new creation time?
void setId(AsyncRPCOperationId id) {
this->id = id;
}

// Todo: Ditto above.
void setCreationTime(int64_t creationTime) {
this->creationTime = creationTime;
}

AsyncRPCOperationId id;
int64_t creationTime;
};

#endif /* ASYNCRPCOPERATION_H */