40
README.md
40
README.md
@@ -180,4 +180,44 @@ mv ~/.komodo ~/.komodo.old && mkdir ~/.komodo && cp ~/.komodo.old/komodo.conf ~/
|
||||
./komodod -exchange -exportdir=/tmp &
|
||||
./komodo-cli importwallet /tmp/example
|
||||
|
||||
############## JUMBLR
|
||||
|
||||
komodod now has jumblr_deposit and jumblr_secret RPC calls.
|
||||
|
||||
Jumblr works like described previously where all the nodes with jumblr active synchronize their tx activity during the same block to maximize the mixing effect. However, unlike all other mixers/tumblers, you never give up control of your coins to anybody else. JUMBLR uses a one to many allocation of funds, ie. one deposit address and many secret addresses. You can always run multiple komodod daemons to get multiple active deposit addresses.
|
||||
|
||||
JUMBLR implements t -> z, z -> z and z -> t transactions to maximize privacy of the destination t (transparent) address. So while it is transparent, its first activity is funds coming from an untracable z address.
|
||||
|
||||
Which of the three stages is done is randomly selected at each turn. Also when there are more than one possible transaction at the selected stage, a random one is selected. This randomization prevents analyzing incoming z ->t transactions by its size to correlate it to the originating address.
|
||||
|
||||
jumblr_deposit <depositaddr> designates the deposit address as the jumblr deposit address for that session. You can select an address that already has funds in it and it will immediately start jumblr process. If there are no funds, it will wait until you send funds to it.
|
||||
|
||||
There are three sizes of a jumblr transaction: 10 KMD, 100 KMD and 1000 KMD. There is also a fixed interval of blocks where all jumblr nodes are active. Currently it is set to be 10, but this is subject to change. Only during every 10*10 blocks are the largest 1000 KMD transactions processed, so this concentrates all the large transactions every N*N blocks.
|
||||
|
||||
jumblr_secret <secretaddress> notifies JUMBLR where to send the final z -> t transactions. In order to allow larger accounts to obtain privacy, up to 777 secret addresses are supported. Whenever a z -> t stage is activated, a random secret address from the list of the then active secret addresses is selected.
|
||||
|
||||
Practical Advice:
|
||||
Obtaining privacy used to be very difficult. JUMBLR makes it as simple as issuing two command line calls. Higher level layers can be added to help manage the addresses, ie. linking them at the passphrase level. Such things are left to each implementation.
|
||||
|
||||
Once obtained, it is very easy to lose all the privacy. With a single errant transaction that combines some previously used address and the secretaddress, well, the secretaddress is no longer so private.
|
||||
|
||||
The advice is to setup a totally separate node!
|
||||
|
||||
This might seem a bit drastic, but if you want to maintain privacy, it is best to make it look like all the transactions are coming from a different node. The easiest way for most people to do this is to actually have a different node.
|
||||
|
||||
It can be a dedicated laptop (recommended) or a VPS (for not so big amounts) with a totally fresh komodod wallet. Generate an address on this wallet and use that as the jumblr_secret address on your main node. As the JUMBLR operates funds will teleport into your secret node's address. If you are careful and never use the same IP address for both your nodes, you will be able to maintain very good privacy.
|
||||
|
||||
Of course, dont be sending emails that link the two accounts together! Dont use secret address funds for home delivery purchases!! Etc. There are many ways to lose the privacy, just think about what linkages can be dont at the IP and blockchain level and that should be a useful preparation.
|
||||
|
||||
What if you have 100,000 KMD and you dont want others to know you are such a whale?
|
||||
|
||||
Instead of generating 1 secret address, generate 100 and make a script file with:
|
||||
|
||||
./komodo-cli jumblr_secret <addr0>
|
||||
./komodo-cli jumblr_secret <addr1>
|
||||
...
|
||||
./komodo-cli jumblr_secret <addr99>
|
||||
|
||||
And make sure to delete all traces of this when the JUMBLR is finished. You will end up with 100 addresses that have an average of 1000 KMD each. So as long as you are careful and dont do a 10,000 KMD transaction (that will link 10 of your secret addresses together), you can appear as 100 different people each with 1000 KMD.
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block);
|
||||
|
||||
int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char *dest);
|
||||
#include "komodo_kv.h"
|
||||
#include "komodo_jumblr.h"
|
||||
#include "komodo_gateway.h"
|
||||
#include "komodo_events.h"
|
||||
|
||||
|
||||
@@ -1363,7 +1363,10 @@ void komodo_passport_iteration()
|
||||
}
|
||||
refsp = komodo_stateptr(symbol,dest);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
{
|
||||
refid = 33;
|
||||
jumblr_iteration();
|
||||
}
|
||||
else
|
||||
{
|
||||
refid = komodo_baseid(ASSETCHAINS_SYMBOL)+1; // illegal base -> baseid.-1 -> 0
|
||||
|
||||
772
src/komodo_jumblr.h
Executable file
772
src/komodo_jumblr.h
Executable file
@@ -0,0 +1,772 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2017 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
z_exportkey "zaddr"
|
||||
z_exportwallet "filename"
|
||||
z_getoperationstatus (["operationid", ... ])
|
||||
z_gettotalbalance ( minconf )
|
||||
z_importkey "zkey" ( rescan )
|
||||
z_importwallet "filename"
|
||||
z_listaddresses
|
||||
z_sendmany "fromaddress" [{"address":... ,"amount":..., "memo":"<hex>"},...] ( minconf ) ( fee )
|
||||
*/
|
||||
|
||||
#define JUMBLR_ADDR "RGhxXpXSSBTBm9EvNsXnTQczthMCxHX91t"
|
||||
#define JUMBLR_BTCADDR "18RmTJe9qMech8siuhYfMtHo8RtcN1obC6"
|
||||
#define JUMBLR_MAXSECRETADDRS 777
|
||||
#define JUMBLR_SYNCHRONIZED_BLOCKS 10
|
||||
#define JUMBLR_INCR 9.965
|
||||
#define JUMBLR_FEE 0.001
|
||||
#define JUMBLR_TXFEE 0.01
|
||||
#define SMALLVAL 0.000000000000001
|
||||
|
||||
#define JUMBLR_ERROR_DUPLICATEDEPOSIT -1
|
||||
#define JUMBLR_ERROR_SECRETCANTBEDEPOSIT -2
|
||||
#define JUMBLR_ERROR_TOOMANYSECRETS -3
|
||||
#define JUMBLR_ERROR_NOTINWALLET -4
|
||||
|
||||
struct jumblr_item
|
||||
{
|
||||
UT_hash_handle hh;
|
||||
int64_t amount,fee,txfee; // fee and txfee not really used (yet)
|
||||
uint32_t spent,pad;
|
||||
char opid[66],src[128],dest[128],status;
|
||||
} *Jumblrs;
|
||||
|
||||
char Jumblr_secretaddrs[JUMBLR_MAXSECRETADDRS][64],Jumblr_deposit[64];
|
||||
int32_t Jumblr_numsecretaddrs; // if 0 -> run silent mode
|
||||
|
||||
char *jumblr_issuemethod(char *userpass,char *method,char *params,uint16_t port)
|
||||
{
|
||||
cJSON *retjson,*resjson = 0; char *retstr;
|
||||
if ( (retstr= komodo_issuemethod(userpass,method,params,port)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( jobj(retjson,(char *)"result") != 0 )
|
||||
resjson = jduplicate(jobj(retjson,(char *)"result"));
|
||||
else if ( jobj(retjson,(char *)"error") != 0 )
|
||||
resjson = jduplicate(jobj(retjson,(char *)"error"));
|
||||
else
|
||||
{
|
||||
resjson = cJSON_CreateObject();
|
||||
jaddstr(resjson,(char *)"error",(char *)"cant parse return");
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
if ( resjson != 0 )
|
||||
return(jprint(resjson,1));
|
||||
else return(clonestr((char *)"{\"error\":\"unknown error\"}"));
|
||||
}
|
||||
|
||||
char *jumblr_importaddress(char *address)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", \"%s\", false]",address,address);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"importaddress",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_validateaddress(char *addr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\"]",addr);
|
||||
printf("validateaddress.%s\n",params);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"validateaddress",params,7771));
|
||||
}
|
||||
|
||||
int32_t Jumblr_secretaddrfind(char *searchaddr)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<Jumblr_numsecretaddrs; i++)
|
||||
{
|
||||
if ( strcmp(searchaddr,Jumblr_secretaddrs[i]) == 0 )
|
||||
return(i);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int32_t Jumblr_secretaddradd(char *secretaddr) // external
|
||||
{
|
||||
int32_t ind;
|
||||
if ( secretaddr != 0 && secretaddr[0] != 0 )
|
||||
{
|
||||
if ( Jumblr_numsecretaddrs < JUMBLR_MAXSECRETADDRS )
|
||||
{
|
||||
if ( strcmp(Jumblr_deposit,secretaddr) != 0 )
|
||||
{
|
||||
if ( (ind= Jumblr_secretaddrfind(secretaddr)) < 0 )
|
||||
{
|
||||
ind = Jumblr_numsecretaddrs++;
|
||||
safecopy(Jumblr_secretaddrs[ind],secretaddr,64);
|
||||
}
|
||||
return(ind);
|
||||
} else return(JUMBLR_ERROR_SECRETCANTBEDEPOSIT);
|
||||
} else return(JUMBLR_ERROR_TOOMANYSECRETS);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Jumblr_secretaddrs,0,sizeof(Jumblr_secretaddrs));
|
||||
Jumblr_numsecretaddrs = 0;
|
||||
}
|
||||
return(Jumblr_numsecretaddrs);
|
||||
}
|
||||
|
||||
int32_t Jumblr_depositaddradd(char *depositaddr) // external
|
||||
{
|
||||
int32_t ind,retval = JUMBLR_ERROR_DUPLICATEDEPOSIT; char *retstr; cJSON *retjson,*ismine;
|
||||
if ( depositaddr == 0 )
|
||||
depositaddr = (char *)"";
|
||||
if ( (ind= Jumblr_secretaddrfind(depositaddr)) < 0 )
|
||||
{
|
||||
if ( (retstr= jumblr_validateaddress(depositaddr)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (ismine= jobj(retjson,(char *)"ismine")) != 0 && is_cJSON_True(ismine) != 0 )
|
||||
{
|
||||
retval = 0;
|
||||
safecopy(Jumblr_deposit,depositaddr,sizeof(Jumblr_deposit));
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = JUMBLR_ERROR_NOTINWALLET;
|
||||
printf("%s not in wallet: ismine.%p %d %s\n",depositaddr,ismine,is_cJSON_True(ismine),jprint(retjson,0));
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
int32_t Jumblr_secretaddr(char *secretaddr)
|
||||
{
|
||||
uint32_t r;
|
||||
if ( Jumblr_numsecretaddrs > 0 )
|
||||
{
|
||||
OS_randombytes((uint8_t *)&r,sizeof(r));
|
||||
r %= Jumblr_numsecretaddrs;
|
||||
safecopy(secretaddr,Jumblr_secretaddrs[r],64);
|
||||
}
|
||||
return(r);
|
||||
}
|
||||
|
||||
int32_t jumblr_addresstype(char *addr)
|
||||
{
|
||||
if ( addr[0] == '"' && addr[strlen(addr)-1] == '"' )
|
||||
{
|
||||
addr[strlen(addr)-1] = 0;
|
||||
addr++;
|
||||
}
|
||||
if ( addr[0] == 'z' && addr[1] == 'c' && strlen(addr) >= 40 )
|
||||
return('z');
|
||||
else if ( strlen(addr) < 40 )
|
||||
return('t');
|
||||
printf("strange.(%s)\n",addr);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
struct jumblr_item *jumblr_opidfind(char *opid)
|
||||
{
|
||||
struct jumblr_item *ptr;
|
||||
HASH_FIND(hh,Jumblrs,opid,(int32_t)strlen(opid),ptr);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
struct jumblr_item *jumblr_opidadd(char *opid)
|
||||
{
|
||||
struct jumblr_item *ptr = 0;
|
||||
if ( opid != 0 && (ptr= jumblr_opidfind(opid)) == 0 )
|
||||
{
|
||||
ptr = (struct jumblr_item *)calloc(1,sizeof(*ptr));
|
||||
safecopy(ptr->opid,opid,sizeof(ptr->opid));
|
||||
HASH_ADD_KEYPTR(hh,Jumblrs,ptr->opid,(int32_t)strlen(ptr->opid),ptr);
|
||||
if ( ptr != jumblr_opidfind(opid) )
|
||||
printf("jumblr_opidadd.(%s) ERROR, couldnt find after add\n",opid);
|
||||
}
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
char *jumblr_zgetnewaddress()
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[]");
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getnewaddress",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zlistoperationids()
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[]");
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listoperationids",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zgetoperationresult(char *opid)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[[\"%s\"]]",opid);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationresult",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zgetoperationstatus(char *opid)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[[\"%s\"]]",opid);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationstatus",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_sendt_to_z(char *taddr,char *zaddr,double amount)
|
||||
{
|
||||
char params[1024]; double fee = ((amount-3*JUMBLR_TXFEE) * JUMBLR_FEE) * 1.5;
|
||||
if ( jumblr_addresstype(zaddr) != 'z' || jumblr_addresstype(taddr) != 't' )
|
||||
return(clonestr((char *)"{\"error\":\"illegal address in t to z\"}"));
|
||||
sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",taddr,zaddr,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE);
|
||||
printf("t -> z: %s\n",params);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_sendz_to_z(char *zaddrS,char *zaddrD,double amount)
|
||||
{
|
||||
char params[1024]; double fee = (amount-2*JUMBLR_TXFEE) * JUMBLR_FEE;
|
||||
if ( jumblr_addresstype(zaddrS) != 'z' || jumblr_addresstype(zaddrD) != 'z' )
|
||||
return(clonestr((char *)"{\"error\":\"illegal address in z to z\"}"));
|
||||
//sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddrS,zaddrD,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE);
|
||||
sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddrS,zaddrD,amount-fee-JUMBLR_TXFEE,JUMBLR_TXFEE);
|
||||
printf("z -> z: %s\n",params);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_sendz_to_t(char *zaddr,char *taddr,double amount)
|
||||
{
|
||||
char params[1024]; double fee = ((amount-JUMBLR_TXFEE) * JUMBLR_FEE) * 1.5;
|
||||
if ( jumblr_addresstype(zaddr) != 'z' || jumblr_addresstype(taddr) != 't' )
|
||||
return(clonestr((char *)"{\"error\":\"illegal address in z to t\"}"));
|
||||
sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddr,taddr,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE);
|
||||
printf("z -> t: %s\n",params);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zlistaddresses()
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[]");
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listaddresses",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zlistreceivedbyaddress(char *addr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", 1]",addr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listreceivedbyaddress",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_getreceivedbyaddress(char *addr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", 1]",addr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"getreceivedbyaddress",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_importprivkey(char *wifstr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", \"\", false]",wifstr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"importprivkey",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_zgetbalance(char *addr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", 1]",addr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getbalance",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_listunspent(char *coinaddr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[1, 99999999, [\"%s\"]]",coinaddr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"listunspent",params,7771));
|
||||
}
|
||||
|
||||
char *jumblr_gettransaction(char *txidstr)
|
||||
{
|
||||
char params[1024];
|
||||
sprintf(params,"[\"%s\", 1]",txidstr);
|
||||
return(jumblr_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,7771));
|
||||
}
|
||||
|
||||
int32_t jumblr_numvins(bits256 txid)
|
||||
{
|
||||
char txidstr[65],params[1024],*retstr; cJSON *retjson,*vins; int32_t n,numvins = -1;
|
||||
bits256_str(txidstr,txid);
|
||||
if ( (retstr= jumblr_gettransaction(txidstr)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( jobj(retjson,(char *)"vin") != 0 && ((vins= jarray(&n,retjson,(char *)"vin")) == 0 || n == 0) )
|
||||
{
|
||||
numvins = n;
|
||||
//printf("numvins.%d\n",n);
|
||||
} //else printf("no vin.(%s)\n",retstr);
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
return(numvins);
|
||||
}
|
||||
|
||||
int64_t jumblr_receivedby(char *addr)
|
||||
{
|
||||
char *retstr; int64_t total = 0;
|
||||
if ( (retstr= jumblr_getreceivedbyaddress(addr)) != 0 )
|
||||
{
|
||||
total = atof(retstr) * SATOSHIDEN;
|
||||
free(retstr);
|
||||
}
|
||||
return(total);
|
||||
}
|
||||
|
||||
int64_t jumblr_balance(char *addr)
|
||||
{
|
||||
char *retstr; double val; int64_t balance = 0; //cJSON *retjson; int32_t i,n;
|
||||
/*if ( jumblr_addresstype(addr) == 't' )
|
||||
{
|
||||
if ( (retstr= jumblr_listunspent(addr)) != 0 )
|
||||
{
|
||||
//printf("jumblr.[%s].(%s)\n","KMD",retstr);
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (n= cJSON_GetArraySize(retjson)) > 0 && is_cJSON_Array(retjson) != 0 )
|
||||
for (i=0; i<n; i++)
|
||||
balance += SATOSHIDEN * jdouble(jitem(retjson,i),(char *)"amount");
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
else*/ if ( (retstr= jumblr_zgetbalance(addr)) != 0 )
|
||||
{
|
||||
if ( (val= atof(retstr)) > SMALLVAL )
|
||||
balance = val * SATOSHIDEN;
|
||||
free(retstr);
|
||||
}
|
||||
return(balance);
|
||||
}
|
||||
|
||||
int32_t jumblr_itemset(struct jumblr_item *ptr,cJSON *item,char *status)
|
||||
{
|
||||
cJSON *params,*amounts,*dest; char *from,*addr; int32_t i,n; int64_t amount;
|
||||
/*"params" : {
|
||||
"fromaddress" : "RDhEGYScNQYetCyG75Kf8Fg61UWPdwc1C5",
|
||||
"amounts" : [
|
||||
{
|
||||
"address" : "zc9s3UdkDFTnnwHrMCr1vYy2WmkjhmTxXNiqC42s7BjeKBVUwk766TTSsrRPKfnX31Bbu8wbrTqnjDqskYGwx48FZMPHvft",
|
||||
"amount" : 3.00000000
|
||||
}
|
||||
],
|
||||
"minconf" : 1,
|
||||
"fee" : 0.00010000
|
||||
}*/
|
||||
if ( (params= jobj(item,(char *)"params")) != 0 )
|
||||
{
|
||||
//printf("params.(%s)\n",jprint(params,0));
|
||||
if ( (from= jstr(params,(char *)"fromaddress")) != 0 )
|
||||
{
|
||||
safecopy(ptr->src,from,sizeof(ptr->src));
|
||||
}
|
||||
if ( (amounts= jarray(&n,params,(char *)"amounts")) != 0 )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
dest = jitem(amounts,i);
|
||||
//printf("%s ",jprint(dest,0));
|
||||
if ( (addr= jstr(dest,(char *)"address")) != 0 && (amount= jdouble(dest,(char *)"amount")*SATOSHIDEN) > 0 )
|
||||
{
|
||||
if ( strcmp(addr,JUMBLR_ADDR) == 0 )
|
||||
ptr->fee = amount;
|
||||
else
|
||||
{
|
||||
ptr->amount = amount;
|
||||
safecopy(ptr->dest,addr,sizeof(ptr->dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr->txfee = jdouble(params,(char *)"fee") * SATOSHIDEN;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
void jumblr_opidupdate(struct jumblr_item *ptr)
|
||||
{
|
||||
char *retstr,*status; cJSON *retjson,*item;
|
||||
if ( ptr->status == 0 )
|
||||
{
|
||||
if ( (retstr= jumblr_zgetoperationstatus(ptr->opid)) != 0 )
|
||||
{
|
||||
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( cJSON_GetArraySize(retjson) == 1 && is_cJSON_Array(retjson) != 0 )
|
||||
{
|
||||
item = jitem(retjson,0);
|
||||
//printf("%s\n",jprint(item,0));
|
||||
if ( (status= jstr(item,(char *)"status")) != 0 )
|
||||
{
|
||||
if ( strcmp(status,(char *)"success") == 0 )
|
||||
{
|
||||
ptr->status = jumblr_itemset(ptr,item,status);
|
||||
if ( (jumblr_addresstype(ptr->src) == 't' && jumblr_addresstype(ptr->src) == 'z' && strcmp(ptr->src,Jumblr_deposit) != 0) || (jumblr_addresstype(ptr->src) == 'z' && jumblr_addresstype(ptr->src) == 't' && Jumblr_secretaddrfind(ptr->dest) < 0) )
|
||||
{
|
||||
printf("a non-jumblr t->z pruned\n");
|
||||
free(jumblr_zgetoperationresult(ptr->opid));
|
||||
ptr->status = -1;
|
||||
}
|
||||
|
||||
}
|
||||
else if ( strcmp(status,(char *)"failed") == 0 )
|
||||
{
|
||||
printf("jumblr_opidupdate %s failed\n",ptr->opid);
|
||||
free(jumblr_zgetoperationresult(ptr->opid));
|
||||
ptr->status = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
free_json(retjson);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jumblr_prune(struct jumblr_item *ptr)
|
||||
{
|
||||
struct jumblr_item *tmp; char oldsrc[128]; int32_t flag = 1;
|
||||
if ( is_hexstr(ptr->opid,0) == 64 )
|
||||
return;
|
||||
printf("jumblr_prune %s\n",ptr->opid);
|
||||
strcpy(oldsrc,ptr->src);
|
||||
free(jumblr_zgetoperationresult(ptr->opid));
|
||||
while ( flag != 0 )
|
||||
{
|
||||
flag = 0;
|
||||
HASH_ITER(hh,Jumblrs,ptr,tmp)
|
||||
{
|
||||
if ( strcmp(oldsrc,ptr->dest) == 0 )
|
||||
{
|
||||
if ( is_hexstr(ptr->opid,0) != 64 )
|
||||
{
|
||||
printf("jumblr_prune %s (%s -> %s) matched oldsrc\n",ptr->opid,ptr->src,ptr->dest);
|
||||
free(jumblr_zgetoperationresult(ptr->opid));
|
||||
strcpy(oldsrc,ptr->src);
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jumblr_zaddrinit(char *zaddr)
|
||||
{
|
||||
struct jumblr_item *ptr; char *retstr,*totalstr; cJSON *item,*array; double total; bits256 txid; char txidstr[65],t_z,z_z;
|
||||
if ( (totalstr= jumblr_zgetbalance(zaddr)) != 0 )
|
||||
{
|
||||
if ( (total= atof(totalstr)) > SMALLVAL )
|
||||
{
|
||||
if ( (retstr= jumblr_zlistreceivedbyaddress(zaddr)) != 0 )
|
||||
{
|
||||
if ( (array= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
t_z = z_z = 0;
|
||||
if ( cJSON_GetArraySize(array) == 1 && is_cJSON_Array(array) != 0 )
|
||||
{
|
||||
item = jitem(array,0);
|
||||
if ( (uint64_t)((total+0.0000000049) * SATOSHIDEN) == (uint64_t)((jdouble(item,(char *)"amount")+0.0000000049) * SATOSHIDEN) )
|
||||
{
|
||||
txid = jbits256(item,(char *)"txid");
|
||||
bits256_str(txidstr,txid);
|
||||
if ( (ptr= jumblr_opidadd(txidstr)) != 0 )
|
||||
{
|
||||
ptr->amount = (total * SATOSHIDEN);
|
||||
ptr->status = 1;
|
||||
strcpy(ptr->dest,zaddr);
|
||||
if ( jumblr_addresstype(ptr->dest) != 'z' )
|
||||
printf("error setting dest type to Z: %s\n",jprint(item,0));
|
||||
if ( jumblr_numvins(txid) == 0 )
|
||||
{
|
||||
z_z = 1;
|
||||
strcpy(ptr->src,zaddr);
|
||||
ptr->src[3] = '0';
|
||||
ptr->src[4] = '0';
|
||||
ptr->src[5] = '0';
|
||||
if ( jumblr_addresstype(ptr->src) != 'z' )
|
||||
printf("error setting address type to Z: %s\n",jprint(item,0));
|
||||
}
|
||||
else
|
||||
{
|
||||
t_z = 1;
|
||||
strcpy(ptr->src,"taddr");
|
||||
if ( jumblr_addresstype(ptr->src) != 't' )
|
||||
printf("error setting address type to T: %s\n",jprint(item,0));
|
||||
}
|
||||
printf("%s %s %.8f t_z.%d z_z.%d\n",zaddr,txidstr,total,t_z,z_z); // cant be z->t from spend
|
||||
}
|
||||
} else printf("mismatched %s %s total %.8f vs %.8f -> %lld\n",zaddr,totalstr,dstr(SATOSHIDEN * total),dstr(SATOSHIDEN * jdouble(item,(char *)"amount")),(long long)((uint64_t)(total * SATOSHIDEN) - (uint64_t)(jdouble(item,(char *)"amount") * SATOSHIDEN)));
|
||||
}
|
||||
free_json(array);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
free(totalstr);
|
||||
}
|
||||
}
|
||||
|
||||
void jumblr_opidsupdate()
|
||||
{
|
||||
char *retstr; cJSON *array; int32_t i,n; struct jumblr_item *ptr;
|
||||
if ( (retstr= jumblr_zlistoperationids()) != 0 )
|
||||
{
|
||||
if ( (array= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (n= cJSON_GetArraySize(array)) > 0 && is_cJSON_Array(array) != 0 )
|
||||
{
|
||||
//printf("%s -> n%d\n",retstr,n);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
if ( (ptr= jumblr_opidadd(jstri(array,i))) != 0 )
|
||||
{
|
||||
if ( ptr->status == 0 )
|
||||
jumblr_opidupdate(ptr);
|
||||
//printf("%d: %s -> %s %.8f\n",ptr->status,ptr->src,ptr->dest,dstr(ptr->amount));
|
||||
if ( jumblr_addresstype(ptr->src) == 'z' && jumblr_addresstype(ptr->dest) == 't' )
|
||||
jumblr_prune(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_json(array);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t jumblr_increment(uint8_t r,int32_t height,uint64_t total,uint64_t biggest,uint64_t medium, uint64_t smallest)
|
||||
{
|
||||
int32_t i,n; uint64_t incrs[1000],remains = total;
|
||||
height /= JUMBLR_SYNCHRONIZED_BLOCKS;
|
||||
if ( (height % JUMBLR_SYNCHRONIZED_BLOCKS) == 0 || total >= 100*biggest )
|
||||
{
|
||||
if ( total >= biggest )
|
||||
return(biggest);
|
||||
else if ( total >= medium )
|
||||
return(medium);
|
||||
else if ( total >= smallest )
|
||||
return(smallest);
|
||||
else return(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = 0;
|
||||
while ( remains > smallest && n < sizeof(incrs)/sizeof(*incrs) )
|
||||
{
|
||||
if ( remains >= biggest )
|
||||
incrs[n] = biggest;
|
||||
else if ( remains >= medium )
|
||||
incrs[n] = medium;
|
||||
else if ( remains >= smallest )
|
||||
incrs[n] = smallest;
|
||||
else break;
|
||||
remains -= incrs[n];
|
||||
n++;
|
||||
}
|
||||
if ( n > 0 )
|
||||
{
|
||||
r %= n;
|
||||
for (i=0; i<n; i++)
|
||||
printf("%.8f ",dstr(incrs[i]));
|
||||
printf("n.%d incrs r.%d -> %.8f\n",n,r,dstr(incrs[r]));
|
||||
return(incrs[r]);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void jumblr_iteration()
|
||||
{
|
||||
static int32_t lastheight; static uint32_t lasttime;
|
||||
char *zaddr,*addr,*retstr,secretaddr[64]; cJSON *array; int32_t i,iter,height,counter,chosen_one,n; uint64_t smallest,medium,biggest,amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint16_t r,s;
|
||||
if ( lasttime == 0 )
|
||||
{
|
||||
if ( (retstr= jumblr_zlistaddresses()) != 0 )
|
||||
{
|
||||
if ( (array= cJSON_Parse(retstr)) != 0 )
|
||||
{
|
||||
if ( (n= cJSON_GetArraySize(array)) > 0 && is_cJSON_Array(array) != 0 )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
jumblr_zaddrinit(jstri(array,i));
|
||||
}
|
||||
free_json(array);
|
||||
}
|
||||
free(retstr);
|
||||
}
|
||||
}
|
||||
height = (int32_t)chainActive.Tip()->nHeight;
|
||||
if ( time(NULL) < lasttime+40 )
|
||||
return;
|
||||
lasttime = (uint32_t)time(NULL);
|
||||
if ( lastheight == height )
|
||||
return;
|
||||
lastheight = height;
|
||||
if ( (height % JUMBLR_SYNCHRONIZED_BLOCKS) != JUMBLR_SYNCHRONIZED_BLOCKS-3 )
|
||||
return;
|
||||
fee = JUMBLR_INCR * JUMBLR_FEE;
|
||||
smallest = SATOSHIDEN * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE);
|
||||
medium = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE);
|
||||
biggest = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*777 + 3*JUMBLR_TXFEE);
|
||||
OS_randombytes((uint8_t *)&r,sizeof(r));
|
||||
s = (r % 3);
|
||||
printf("jumblr_iteration r.%u s.%u\n",r,s);
|
||||
switch ( s )
|
||||
{
|
||||
case 0: // t -> z
|
||||
default:
|
||||
if ( Jumblr_deposit[0] != 0 && (total= jumblr_balance(Jumblr_deposit)) >= smallest )
|
||||
{
|
||||
if ( (zaddr= jumblr_zgetnewaddress()) != 0 )
|
||||
{
|
||||
if ( zaddr[0] == '"' && zaddr[strlen(zaddr)-1] == '"' )
|
||||
{
|
||||
zaddr[strlen(zaddr)-1] = 0;
|
||||
addr = zaddr+1;
|
||||
} else addr = zaddr;
|
||||
amount = jumblr_increment(r/3,height,total,biggest,medium,smallest);
|
||||
/*
|
||||
amount = 0;
|
||||
if ( (height % (JUMBLR_SYNCHRONIZED_BLOCKS*JUMBLR_SYNCHRONIZED_BLOCKS)) == 0 && total >= SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE) )
|
||||
amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE);
|
||||
else if ( (r & 3) == 0 && total >= SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE) )
|
||||
amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE);
|
||||
else amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE);*/
|
||||
if ( amount > 0 && (retstr= jumblr_sendt_to_z(Jumblr_deposit,addr,dstr(amount))) != 0 )
|
||||
{
|
||||
printf("sendt_to_z.(%s)\n",retstr);
|
||||
free(retstr);
|
||||
}
|
||||
free(zaddr);
|
||||
} else printf("no zaddr from jumblr_zgetnewaddress\n");
|
||||
}
|
||||
else if ( Jumblr_deposit[0] != 0 )
|
||||
printf("%s total %.8f vs %.8f\n",Jumblr_deposit,dstr(total),(JUMBLR_INCR + 3*(fee+JUMBLR_TXFEE)));
|
||||
break;
|
||||
case 1: // z -> z
|
||||
jumblr_opidsupdate();
|
||||
chosen_one = -1;
|
||||
for (iter=counter=0; iter<2; iter++)
|
||||
{
|
||||
counter = n = 0;
|
||||
HASH_ITER(hh,Jumblrs,ptr,tmp)
|
||||
{
|
||||
if ( ptr->spent == 0 && ptr->status > 0 && jumblr_addresstype(ptr->src) == 't' && jumblr_addresstype(ptr->dest) == 'z' )
|
||||
{
|
||||
if ( (total= jumblr_balance(ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN )
|
||||
{
|
||||
if ( iter == 1 && counter == chosen_one )
|
||||
{
|
||||
if ( (zaddr= jumblr_zgetnewaddress()) != 0 )
|
||||
{
|
||||
if ( zaddr[0] == '"' && zaddr[strlen(zaddr)-1] == '"' )
|
||||
{
|
||||
zaddr[strlen(zaddr)-1] = 0;
|
||||
addr = zaddr+1;
|
||||
} else addr = zaddr;
|
||||
if ( (retstr= jumblr_sendz_to_z(ptr->dest,addr,dstr(total))) != 0 )
|
||||
{
|
||||
printf("n.%d counter.%d chosen_one.%d send z_to_z.(%s)\n",n,counter,chosen_one,retstr);
|
||||
free(retstr);
|
||||
}
|
||||
ptr->spent = (uint32_t)time(NULL);
|
||||
free(zaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
n++;
|
||||
}
|
||||
if ( counter == 0 )
|
||||
break;
|
||||
if ( iter == 0 )
|
||||
{
|
||||
OS_randombytes((uint8_t *)&chosen_one,sizeof(chosen_one));
|
||||
if ( chosen_one < 0 )
|
||||
chosen_one = -chosen_one;
|
||||
chosen_one %= counter;
|
||||
printf("jumblr z->z chosen_one.%d of %d, from %d\n",chosen_one,counter,n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // z -> t
|
||||
if ( Jumblr_numsecretaddrs > 0 )
|
||||
{
|
||||
jumblr_opidsupdate();
|
||||
chosen_one = -1;
|
||||
for (iter=0; iter<2; iter++)
|
||||
{
|
||||
counter = n = 0;
|
||||
HASH_ITER(hh,Jumblrs,ptr,tmp)
|
||||
{
|
||||
//printf("status.%d %c %c %.8f\n",ptr->status,jumblr_addresstype(ptr->src),jumblr_addresstype(ptr->dest),dstr(ptr->amount));
|
||||
if ( ptr->spent == 0 && ptr->status > 0 && jumblr_addresstype(ptr->src) == 'z' && jumblr_addresstype(ptr->dest) == 'z' )
|
||||
{
|
||||
if ( (total= jumblr_balance(ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN )
|
||||
{
|
||||
if ( iter == 1 && counter == chosen_one )
|
||||
{
|
||||
Jumblr_secretaddr(secretaddr);
|
||||
if ( (retstr= jumblr_sendz_to_t(ptr->dest,secretaddr,dstr(total))) != 0 )
|
||||
{
|
||||
printf("%s send z_to_t.(%s)\n",secretaddr,retstr);
|
||||
free(retstr);
|
||||
} else printf("null return from jumblr_sendz_to_t\n");
|
||||
ptr->spent = (uint32_t)time(NULL);
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
} //else printf("z->t spent.%u total %.8f error\n",ptr->spent,dstr(total));
|
||||
}
|
||||
n++;
|
||||
}
|
||||
if ( counter == 0 )
|
||||
break;
|
||||
if ( iter == 0 )
|
||||
{
|
||||
OS_randombytes((uint8_t *)&chosen_one,sizeof(chosen_one));
|
||||
if ( chosen_one < 0 )
|
||||
chosen_one = -chosen_one;
|
||||
chosen_one %= counter;
|
||||
printf("jumblr z->t chosen_one.%d of %d, from %d\n",chosen_one,counter,n);
|
||||
} //else printf("n.%d counter.%d chosen.%d\n",n,counter,chosen_one);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,7 +798,9 @@ void static BitcoinMiner()
|
||||
if ( gpucount > j/2 )
|
||||
{
|
||||
double delta;
|
||||
i = ((Mining_height + notaryid) % 64);
|
||||
if ( notaryid < 0 )
|
||||
i = (rand() % 64);
|
||||
else i = ((Mining_height + notaryid) % 64);
|
||||
delta = sqrt((double)gpucount - j/2) / 2.;
|
||||
roundrobin_delay += ((delta * i) / 64) - delta;
|
||||
//fprintf(stderr,"delta.%f %f %f\n",delta,(double)(gpucount - j/3) / 2,(delta * i) / 64);
|
||||
@@ -869,7 +871,9 @@ void static BitcoinMiner()
|
||||
MilliSleep((rand() % 1700) + 1);
|
||||
}
|
||||
else if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
sleep(3);
|
||||
{
|
||||
sleep(rand() % 30);
|
||||
}
|
||||
KOMODO_CHOSEN_ONE = 1;
|
||||
// Found a solution
|
||||
SetThreadPriority(THREAD_PRIORITY_NORMAL);
|
||||
|
||||
@@ -41,6 +41,8 @@ using namespace std;
|
||||
* Or alternatively, create a specific query method for the information.
|
||||
**/
|
||||
|
||||
int32_t Jumblr_depositaddradd(char *depositaddr);
|
||||
int32_t Jumblr_secretaddradd(char *secretaddr);
|
||||
uint64_t komodo_interestsum();
|
||||
int32_t komodo_longestchain();
|
||||
int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp);
|
||||
@@ -48,7 +50,7 @@ int32_t komodo_whoami(char *pubkeystr,int32_t height);
|
||||
extern int32_t KOMODO_LASTMINED;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp);
|
||||
#define KOMODO_VERSION "0.1.0"
|
||||
#define KOMODO_VERSION "0.1.1"
|
||||
|
||||
UniValue getinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
@@ -188,6 +190,40 @@ public:
|
||||
};
|
||||
#endif
|
||||
|
||||
UniValue jumblr_deposit(const UniValue& params, bool fHelp)
|
||||
{
|
||||
int32_t retval; UniValue result(UniValue::VOBJ);
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error("jumblr_deposit \"depositaddress\"\n");
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
bool isValid = address.IsValid();
|
||||
if ( isValid != 0 )
|
||||
{
|
||||
string addr = params[0].get_str();
|
||||
if ( (retval= Jumblr_depositaddradd((char *)addr.c_str())) >= 0 )
|
||||
result.push_back(Pair("result", retval));
|
||||
else result.push_back(Pair("error", retval));
|
||||
} else result.push_back(Pair("error", "invalid address"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue jumblr_secret(const UniValue& params, bool fHelp)
|
||||
{
|
||||
int32_t retval; UniValue result(UniValue::VOBJ);
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error("jumblr_secret \"secretaddress\"\n");
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
bool isValid = address.IsValid();
|
||||
if ( isValid != 0 )
|
||||
{
|
||||
string addr = params[0].get_str();
|
||||
retval = Jumblr_secretaddradd((char *)addr.c_str());
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("num", retval));
|
||||
} else result.push_back(Pair("error", "invalid address"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue validateaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
|
||||
@@ -336,6 +336,8 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "util", "estimatefee", &estimatefee, true },
|
||||
{ "util", "estimatepriority", &estimatepriority, true },
|
||||
{ "util", "z_validateaddress", &z_validateaddress, true }, /* uses wallet if enabled */
|
||||
{ "util", "jumblr_deposit", &jumblr_deposit, true },
|
||||
{ "util", "jumblr_secret", &jumblr_secret, true },
|
||||
|
||||
/* Not shown in help */
|
||||
{ "hidden", "invalidateblock", &invalidateblock, true },
|
||||
|
||||
@@ -246,6 +246,9 @@ extern UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp);
|
||||
extern UniValue zc_raw_receive(const UniValue& params, bool fHelp);
|
||||
extern UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue jumblr_deposit(const UniValue& params, bool fHelp);
|
||||
extern UniValue jumblr_secret(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp
|
||||
extern UniValue listunspent(const UniValue& params, bool fHelp);
|
||||
extern UniValue lockunspent(const UniValue& params, bool fHelp);
|
||||
|
||||
@@ -1048,14 +1048,14 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
BOOST_CHECK(tx.vout.size() == 0);
|
||||
|
||||
CAmount amount = 123.456;
|
||||
proxy.add_taddr_change_output_to_tx(amount);
|
||||
proxy.add_taddr_change_output_to_tx(0,amount);
|
||||
tx = proxy.getTx();
|
||||
BOOST_CHECK(tx.vout.size() == 1);
|
||||
CTxOut out = tx.vout[0];
|
||||
BOOST_CHECK_EQUAL(out.nValue, amount);
|
||||
|
||||
amount = 1.111;
|
||||
proxy.add_taddr_change_output_to_tx(amount);
|
||||
proxy.add_taddr_change_output_to_tx(0,amount);
|
||||
tx = proxy.getTx();
|
||||
BOOST_CHECK(tx.vout.size() == 2);
|
||||
out = tx.vout[1];
|
||||
|
||||
@@ -292,6 +292,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
CTxIn in(COutPoint(txid, vout));
|
||||
rawTx.vin.push_back(in);
|
||||
}
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
tx_ = CTransaction(rawTx);
|
||||
}
|
||||
|
||||
@@ -318,7 +319,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
CAmount change = funds - fundsSpent;
|
||||
|
||||
if (change > 0) {
|
||||
add_taddr_change_output_to_tx(change);
|
||||
add_taddr_change_output_to_tx(0,change);
|
||||
|
||||
LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
getId(),
|
||||
@@ -341,6 +342,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
mtx.nVersion = 2;
|
||||
crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_);
|
||||
mtx.joinSplitPubKey = joinSplitPubKey_;
|
||||
mtx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
tx_ = CTransaction(mtx);
|
||||
|
||||
// Copy zinputs and zoutputs to more flexible containers
|
||||
@@ -395,7 +397,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
"allow any change as there is currently no way to specify a change address "
|
||||
"in z_sendmany.", FormatMoney(change)));
|
||||
} else {
|
||||
add_taddr_change_output_to_tx(change);
|
||||
add_taddr_change_output_to_tx(&fromtaddr_,change);
|
||||
LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
getId(),
|
||||
FormatMoney(change)
|
||||
@@ -1098,26 +1100,33 @@ void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() {
|
||||
CTxOut out(nAmount, scriptPubKey);
|
||||
rawTx.vout.push_back(out);
|
||||
}
|
||||
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
tx_ = CTransaction(rawTx);
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CAmount amount) {
|
||||
void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CBitcoinAddress *fromaddress,CAmount amount) {
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
CScript scriptPubKey;
|
||||
CReserveKey keyChange(pwalletMain);
|
||||
CPubKey vchPubKey;
|
||||
bool ret = keyChange.GetReservedKey(vchPubKey);
|
||||
if (!ret) {
|
||||
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Could not generate a taddr to use as a change address"); // should never fail, as we just unlocked
|
||||
if ( fromaddress != 0 )
|
||||
scriptPubKey = GetScriptForDestination(fromaddress->Get());
|
||||
else
|
||||
{
|
||||
bool ret = keyChange.GetReservedKey(vchPubKey);
|
||||
if (!ret) {
|
||||
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Could not generate a taddr to use as a change address"); // should never fail, as we just unlocked
|
||||
}
|
||||
scriptPubKey = GetScriptForDestination(vchPubKey.GetID());
|
||||
}
|
||||
CScript scriptPubKey = GetScriptForDestination(vchPubKey.GetID());
|
||||
CTxOut out(amount, scriptPubKey);
|
||||
|
||||
CMutableTransaction rawTx(tx_);
|
||||
rawTx.vout.push_back(out);
|
||||
rawTx.nLockTime = (uint32_t)time(NULL) - 60; // jl777
|
||||
tx_ = CTransaction(rawTx);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
|
||||
CTransaction tx_;
|
||||
|
||||
void add_taddr_change_output_to_tx(CAmount amount);
|
||||
void add_taddr_change_output_to_tx(CBitcoinAddress *fromaddress,CAmount amount);
|
||||
void add_taddr_outputs_to_tx();
|
||||
bool find_unspent_notes();
|
||||
bool find_utxos(bool fAcceptCoinbase);
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
// Delegated methods
|
||||
|
||||
void add_taddr_change_output_to_tx(CAmount amount) {
|
||||
delegate->add_taddr_change_output_to_tx(amount);
|
||||
delegate->add_taddr_change_output_to_tx(0,amount);
|
||||
}
|
||||
|
||||
void add_taddr_outputs_to_tx() {
|
||||
|
||||
Reference in New Issue
Block a user