Auto merge of #1911 - bitcartel:1823_witness_does_not_have_same_anchor_as_change_input, r=str4d

With chained joinsplits, witness anchors for input notes no longer cross block boundaries

Closes #1823
This commit is contained in:
zkbot
2016-12-08 01:23:40 +00:00
4 changed files with 165 additions and 8 deletions

View File

@@ -323,7 +323,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
zOutputsDeque.push_back(o);
}
// When spending notes, take a snapshot of note witnesses and anchors as the treestate will
// change upon arrival of new blocks which contain joinsplit transactions. This is likely
// to happen as creating a chained joinsplit transaction can take longer than the block interval.
if (z_inputs_.size() > 0) {
LOCK2(cs_main, pwalletMain->cs_wallet);
for (auto t : z_inputs_) {
JSOutPoint jso = std::get<0>(t);
std::vector<JSOutPoint> vOutPoints = { jso };
uint256 inputAnchor;
std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
pwalletMain->GetNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor);
jsopWitnessAnchorMap[ jso.ToString() ] = WitnessAnchorData{ vInputWitnesses[0], inputAnchor };
}
}
/**
* SCENARIO #2
*
@@ -573,6 +588,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
//
std::vector<Note> vInputNotes;
std::vector<JSOutPoint> vOutPoints;
std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
uint256 inputAnchor;
int numInputsNeeded = (jsChange>0) ? 1 : 0;
while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) {
@@ -582,6 +598,14 @@ bool AsyncRPCOperation_sendmany::main_impl() {
CAmount noteFunds = std::get<2>(t);
zInputsDeque.pop_front();
WitnessAnchorData wad = jsopWitnessAnchorMap[ jso.ToString() ];
vInputWitnesses.push_back(wad.witness);
if (inputAnchor.IsNull()) {
inputAnchor = wad.anchor;
} else if (inputAnchor != wad.anchor) {
throw JSONRPCError(RPC_WALLET_ERROR, "Selected input notes do not share the same anchor");
}
vOutPoints.push_back(jso);
vInputNotes.push_back(note);
@@ -598,12 +622,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
// Add history of previous commitments to witness
if (vInputNotes.size() > 0) {
std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
{
LOCK(cs_main);
pwalletMain->GetNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor);
}
if (vInputWitnesses.size()==0) {
throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment");
}

View File

@@ -14,6 +14,7 @@
#include "json/json_spirit_value.h"
#include "wallet.h"
#include <unordered_map>
#include <tuple>
// Default transaction fee if caller does not specify one.
@@ -41,6 +42,12 @@ struct AsyncJoinSplitInfo
CAmount vpub_new = 0;
};
// A struct to help us track the witness and anchor for a given JSOutPoint
struct WitnessAnchorData {
boost::optional<ZCIncrementalWitness> witness;
uint256 anchor;
};
class AsyncRPCOperation_sendmany : public AsyncRPCOperation {
public:
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE);
@@ -71,7 +78,9 @@ private:
uint256 joinSplitPubKey_;
unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES];
// The key is the result string from calling JSOutPoint::ToString()
std::unordered_map<std::string, WitnessAnchorData> jsopWitnessAnchorMap;
std::vector<SendManyRecipient> t_outputs_;
std::vector<SendManyRecipient> z_outputs_;
std::vector<SendManyInputUTXO> t_inputs_;