fix
This commit is contained in:
blackjok3r
2018-12-13 12:40:53 +08:00
34 changed files with 874 additions and 1875 deletions

View File

@@ -115,13 +115,163 @@ class CryptoconditionsOraclesTest(BitcoinTestFramework):
too_long_description = generate_random_string(4100) too_long_description = generate_random_string(4100)
result = rpc.oraclescreate("Test", too_long_description, "s") result = rpc.oraclescreate("Test", too_long_description, "s")
assert_error(result) assert_error(result)
# # valid creating oracles of different types # valid creating oracles of different types
# # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type) # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type)
# valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"] valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"]
# for f in valid_formats: for f in valid_formats:
# result = rpc.oraclescreate("Test", "Test", f) result = rpc.oraclescreate("Test", "Test", f)
# assert_success(result) assert_success(result)
# globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc) globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc)
# trying to register with negative datafee
for f in valid_formats:
result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "-100")
assert_error(result)
# trying to register with zero datafee
for f in valid_formats:
result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "0")
assert_error(result)
# trying to register with datafee less than txfee
for f in valid_formats:
result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "500")
assert_error(result)
# trying to register valid
for f in valid_formats:
result = rpc.oraclesregister(globals()["oracle_{}".format(f)], "10000")
assert_success(result)
register_txid = self.send_and_mine(result["hex"], rpc)
assert register_txid, "got txid"
# TODO: for most of the non valid oraclesregister and oraclessubscribe transactions generating and broadcasting now
# so trying only valid oraclessubscribe atm
for f in valid_formats:
result = rpc.oraclessubscribe(globals()["oracle_{}".format(f)], self.pubkey, "1")
assert_success(result)
subscribe_txid = self.send_and_mine(result["hex"], rpc)
assert register_txid, "got txid"
# now lets publish and read valid data for each oracle type
# s type
result = rpc.oraclesdata(globals()["oracle_{}".format("s")], "05416e746f6e")
assert_success(result)
# baton
oraclesdata_s = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("s")], oraclesdata_s, "1")
assert_equal("[u'Anton']", str(result["samples"][0]), "Data match")
# S type
result = rpc.oraclesdata(globals()["oracle_{}".format("S")], "000161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161")
assert_success(result)
# baton
oraclesdata_S = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("S")], oraclesdata_S, "1")
assert_equal("[u'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']", str(result["samples"][0]), "Data match")
# d type
result = rpc.oraclesdata(globals()["oracle_{}".format("d")], "0101")
assert_success(result)
# baton
oraclesdata_d = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("d")], oraclesdata_d, "1")
# TODO: working not correct now!
#assert_equal("[u'01']", str(result["samples"][0]), "Data match")
# D type
result = rpc.oraclesdata(globals()["oracle_{}".format("D")], "0101")
assert_success(result)
# baton
oraclesdata_D = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("D")], oraclesdata_D, "1")
# TODO: working not correct now!
#assert_equal("[u'01']", str(result["samples"][0]), "Data match")
# c type
result = rpc.oraclesdata(globals()["oracle_{}".format("c")], "ff")
assert_success(result)
# baton
oraclesdata_c = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("c")], oraclesdata_c, "1")
assert_equal("[u'-1']", str(result["samples"][0]), "Data match")
# C type
result = rpc.oraclesdata(globals()["oracle_{}".format("C")], "ff")
assert_success(result)
# baton
oraclesdata_C = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("C")], oraclesdata_C, "1")
assert_equal("[u'255']", str(result["samples"][0]), "Data match")
# t type
result = rpc.oraclesdata(globals()["oracle_{}".format("t")], "ffff")
assert_success(result)
# baton
oraclesdata_t = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("t")], oraclesdata_t, "1")
assert_equal("[u'-1']", str(result["samples"][0]), "Data match")
# T type
result = rpc.oraclesdata(globals()["oracle_{}".format("T")], "ffff")
assert_success(result)
# baton
oraclesdata_T = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("T")], oraclesdata_T, "1")
assert_equal("[u'65535']", str(result["samples"][0]), "Data match")
# i type
result = rpc.oraclesdata(globals()["oracle_{}".format("i")], "ffffffff")
assert_success(result)
# baton
oraclesdata_i = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("i")], oraclesdata_i, "1")
assert_equal("[u'-1']", str(result["samples"][0]), "Data match")
# I type
result = rpc.oraclesdata(globals()["oracle_{}".format("I")], "ffffffff")
assert_success(result)
# baton
oraclesdata_I = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("I")], oraclesdata_I, "1")
assert_equal("[u'4294967295']", str(result["samples"][0]), "Data match")
# l type
result = rpc.oraclesdata(globals()["oracle_{}".format("l")], "00000000ffffffff")
assert_success(result)
# baton
oraclesdata_l = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("l")], oraclesdata_l, "1")
# TODO: working not correct now!
#assert_equal("[u'-4294967296']", str(result["samples"][0]), "Data match")
# L type
result = rpc.oraclesdata(globals()["oracle_{}".format("L")], "00000000ffffffff")
assert_success(result)
# baton
oraclesdata_L = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("L")], oraclesdata_L, "1")
assert_equal("[u'18446744069414584320']", str(result["samples"][0]), "Data match")
# h type
result = rpc.oraclesdata(globals()["oracle_{}".format("h")], "00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff")
assert_success(result)
# baton
oraclesdata_h = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("h")], oraclesdata_h, "1")
assert_equal("[u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]), "Data match")
# Ihh type
result = rpc.oraclesdata(globals()["oracle_{}".format("Ihh")], "00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff")
assert_success(result)
# baton
oraclesdata_Ihh = self.send_and_mine(result["hex"], rpc)
result = rpc.oraclessamples(globals()["oracle_{}".format("Ihh")], oraclesdata_Ihh, "1")
assert_equal("[u'0']", str(result["samples"][0]), "Data match")
assert_equal("[u'00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff']", str(result["samples"][1]), "Data match")
assert_equal("[u'00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff']", str(result["samples"][2]), "Data match")
def run_test(self): def run_test(self):
print("Mining blocks...") print("Mining blocks...")
@@ -138,5 +288,6 @@ class CryptoconditionsOraclesTest(BitcoinTestFramework):
rpc1.importprivkey(self.privkey1) rpc1.importprivkey(self.privkey1)
self.run_oracles_tests() self.run_oracles_tests()
if __name__ == '__main__': if __name__ == '__main__':
CryptoconditionsOraclesTest().main() CryptoconditionsOraclesTest().main()

View File

@@ -28,7 +28,7 @@ class ListReceivedTest (BitcoinTestFramework):
self.sync_all() self.sync_all()
assert_equal(new_height, self.nodes[0].getblockcount()) assert_equal(new_height, self.nodes[0].getblockcount())
def run_test_release(self, release, expected_memo, height): def run_test_release(self, release, height):
self.generate_and_sync(height+1) self.generate_and_sync(height+1)
taddr = self.nodes[1].getnewaddress() taddr = self.nodes[1].getnewaddress()
zaddr1 = self.nodes[1].z_getnewaddress(release) zaddr1 = self.nodes[1].z_getnewaddress(release)
@@ -61,7 +61,7 @@ class ListReceivedTest (BitcoinTestFramework):
# Generate some change by sending part of zaddr1 to zaddr2 # Generate some change by sending part of zaddr1 to zaddr2
zaddr2 = self.nodes[1].z_getnewaddress(release) zaddr2 = self.nodes[1].z_getnewaddress(release)
opid = self.nodes[1].z_sendmany(zaddr1, opid = self.nodes[1].z_sendmany(zaddr1,
[{'address': zaddr2, 'amount': 0.6, 'memo': my_memo}]) [{'address': zaddr2, 'amount': 0.6}])
txid = wait_and_assert_operationid_status(self.nodes[1], opid) txid = wait_and_assert_operationid_status(self.nodes[1], opid)
self.sync_all() self.sync_all()
self.generate_and_sync(height+4) self.generate_and_sync(height+4)
@@ -74,12 +74,12 @@ class ListReceivedTest (BitcoinTestFramework):
assert_equal(txid, r[0]['txid']) assert_equal(txid, r[0]['txid'])
assert_equal(Decimal('0.4')-fee, r[0]['amount']) assert_equal(Decimal('0.4')-fee, r[0]['amount'])
assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change") assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change")
assert_equal(expected_memo, r[0]['memo']) assert_equal(no_memo, r[0]['memo'])
# The old note still exists (it's immutable), even though it is spent # The old note still exists (it's immutable), even though it is spent
assert_equal(Decimal('1.0'), r[1]['amount']) assert_equal(Decimal('1.0'), r[1]['amount'])
assert_false(r[1]['change'], "Note valued at 1.0 should not be change") assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
assert_equal(expected_memo, r[0]['memo']) assert_equal(my_memo, r[1]['memo'])
# zaddr2 should not have change # zaddr2 should not have change
r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0) r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
@@ -88,11 +88,11 @@ class ListReceivedTest (BitcoinTestFramework):
assert_equal(txid, r[0]['txid']) assert_equal(txid, r[0]['txid'])
assert_equal(Decimal('0.6'), r[0]['amount']) assert_equal(Decimal('0.6'), r[0]['amount'])
assert_false(r[0]['change'], "Note valued at 0.6 should not be change") assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
assert_equal(my_memo, r[0]['memo']) assert_equal(no_memo, r[0]['memo'])
def run_test(self): def run_test(self):
self.run_test_release('sprout', no_memo, 200) self.run_test_release('sprout', 200)
self.run_test_release('sapling', no_memo, 204) self.run_test_release('sapling', 204)
if __name__ == '__main__': if __name__ == '__main__':
ListReceivedTest().main() ListReceivedTest().main()

View File

@@ -68,12 +68,22 @@ class WalletPersistenceTest (BitcoinTestFramework):
# Verify shielded balance # Verify shielded balance
assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20'))
# Verify size of shielded pools
pools = self.nodes[0].getblockchaininfo()['valuePools']
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
# Restart the nodes # Restart the nodes
stop_nodes(self.nodes) stop_nodes(self.nodes)
wait_bitcoinds() wait_bitcoinds()
self.setup_network() self.setup_network()
# Verify size of shielded pools
pools = self.nodes[0].getblockchaininfo()['valuePools']
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
# Node 0 sends some shielded funds to Node 1 # Node 0 sends some shielded funds to Node 1
dest_addr = self.nodes[1].z_getnewaddress('sapling') dest_addr = self.nodes[1].z_getnewaddress('sapling')
recipients = [] recipients = []
@@ -128,4 +138,4 @@ class WalletPersistenceTest (BitcoinTestFramework):
assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
if __name__ == '__main__': if __name__ == '__main__':
WalletPersistenceTest().main() WalletPersistenceTest().main()

View File

@@ -262,7 +262,6 @@ BITCOIN_CORE_H = \
wallet/wallet.h \ wallet/wallet.h \
wallet/wallet_ismine.h \ wallet/wallet_ismine.h \
wallet/walletdb.h \ wallet/walletdb.h \
veruslaunch.h \
zmq/zmqabstractnotifier.h \ zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\ zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \ zmq/zmqnotificationinterface.h \
@@ -486,7 +485,6 @@ libbitcoin_common_a_SOURCES = \
script/script_error.cpp \ script/script_error.cpp \
script/sign.cpp \ script/sign.cpp \
script/standard.cpp \ script/standard.cpp \
veruslaunch.cpp \
transaction_builder.cpp \ transaction_builder.cpp \
$(BITCOIN_CORE_H) \ $(BITCOIN_CORE_H) \
$(LIBZCASH_H) $(LIBZCASH_H)

View File

@@ -11,7 +11,7 @@ if [ -z "$delay" ]; then delay=20; fi
./listassetchainparams | while read args; do ./listassetchainparams | while read args; do
gen="" gen=""
if [ $[RANDOM % 10] == 1 ]; then if [ $[RANDOM % 10] == 1 ]; then
gen=" -gen" gen=" -gen -genproclimit=1"
fi fi
./komodod $gen $args $overide_args -pubkey=$pubkey -addnode=$seed_ip & ./komodod $gen $args $overide_args -pubkey=$pubkey -addnode=$seed_ip &

View File

@@ -94,7 +94,8 @@
}, },
{ {
"ac_name": "OOT", "ac_name": "OOT",
"ac_supply": "216000000" "ac_supply": "216000000",
"ac_sapling": "5000000"
}, },
{ {
"ac_name": "BNTN", "ac_name": "BNTN",

View File

@@ -27,7 +27,7 @@ echo $pubkey
./komodod -pubkey=$pubkey -ac_name=BEER -ac_supply=100000000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=BEER -ac_supply=100000000 -addnode=78.47.196.146 &
./komodod -pubkey=$pubkey -ac_name=PIZZA -ac_supply=100000000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=PIZZA -ac_supply=100000000 -addnode=78.47.196.146 &
./komodod -pubkey=$pubkey -ac_name=NINJA -ac_supply=100000000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=NINJA -ac_supply=100000000 -addnode=78.47.196.146 &
./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000 -addnode=174.138.107.226 & ./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000 -ac_saplinig=5000000 -addnode=174.138.107.226 &
./komodod -pubkey=$pubkey -ac_name=BNTN -ac_supply=500000000 -addnode=94.130.169.205 & ./komodod -pubkey=$pubkey -ac_name=BNTN -ac_supply=500000000 -addnode=94.130.169.205 &
./komodod -pubkey=$pubkey -ac_name=CHAIN -ac_supply=999999 -addnode=78.47.146.222 & ./komodod -pubkey=$pubkey -ac_name=CHAIN -ac_supply=999999 -addnode=78.47.146.222 &
./komodod -pubkey=$pubkey -ac_name=PRLPAY -ac_supply=500000000 -addnode=13.250.226.125 & ./komodod -pubkey=$pubkey -ac_name=PRLPAY -ac_supply=500000000 -addnode=13.250.226.125 &

View File

@@ -62,8 +62,26 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
GetCCaddress(cp,myaddr,mypk); GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk); mycond = MakeCCcond1(cp->evalcode,mypk);
GetCCaddress(cp,unspendable,unspendablepk); GetCCaddress(cp,unspendable,unspendablepk);
othercond = MakeCCcond1(cp->evalcode,unspendablepk); othercond = MakeCCcond1(cp->evalcode,unspendablepk);
//fprintf(stderr,"myCCaddr.(%s) %p vs unspendable.(%s) %p\n",myaddr,mycond,unspendable,othercond); //Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
for (i=0; i<n; i++)
{
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout[mtx.vin[i].prevout.n].scriptPubKey.IsPayToCryptoCondition() == 0 && ccvins==0)
normalvins++;
else ccvins++;
}
}
if (normalvins>1 && ccvins)
{
for(i=1;i<normalvins;i++)
{
mtx.vin.push_back(mtx.vin[1]);
mtx.vin.erase(mtx.vin.begin() + 1);
}
}
memset(utxovalues,0,sizeof(utxovalues)); memset(utxovalues,0,sizeof(utxovalues));
for (i=0; i<n; i++) for (i=0; i<n; i++)
{ {
@@ -74,14 +92,12 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
totalinputs += utxovalues[i]; totalinputs += utxovalues[i];
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 ) if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{ {
//fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN); //fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN);
if (ccvins==0) normalvins++;
normalinputs += utxovalues[i]; normalinputs += utxovalues[i];
vinimask |= (1LL << i); vinimask |= (1LL << i);
} }
else else
{ {
ccvins++;
mask |= (1LL << i); mask |= (1LL << i);
} }
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str()); } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
@@ -98,16 +114,6 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
mtx.vout.push_back(CTxOut(0,opret)); mtx.vout.push_back(CTxOut(0,opret));
PrecomputedTransactionData txdata(mtx); PrecomputedTransactionData txdata(mtx);
n = mtx.vin.size(); n = mtx.vin.size();
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
if (normalvins>1)
{
for(i=1;i<normalvins;i++)
{
mtx.vin.push_back(mtx.vin[1]);
mtx.vin.erase(mtx.vin.begin() + 1);
}
}
for (i=0; i<n; i++) for (i=0; i<n; i++)
{ {
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 ) if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )

View File

@@ -906,7 +906,7 @@ int32_t main(int32_t argc,char **argv)
zsaddr = clonestr(argv[2]); zsaddr = clonestr(argv[2]);
printf("%s: %s %s\n",REFCOIN_CLI,coinstr,zsaddr); printf("%s: %s %s\n",REFCOIN_CLI,coinstr,zsaddr);
uint32_t lastopid; char coinaddr[64],zcaddr[128],opidstr[128]; int32_t finished; int64_t amount,stdamount,txfee; uint32_t lastopid; char coinaddr[64],zcaddr[128],opidstr[128]; int32_t finished; int64_t amount,stdamount,txfee;
stdamount = 10000 * SATOSHIDEN; stdamount = 1000 * SATOSHIDEN;
txfee = 10000; txfee = 10000;
again: again:
printf("start processing zmigrate\n"); printf("start processing zmigrate\n");

View File

@@ -427,11 +427,11 @@ void *dicefinish(void *_ptr)
if ( vin0_needed > 0 ) if ( vin0_needed > 0 )
{ {
num = 0; num = 0;
//fprintf(stderr,"iter.%d vin0_needed.%d\n",iter,vin0_needed); //fprintf(stderr,"iter.%d vin0_needed.%d\n",iter,vin0_needed);
utxos = (struct dicefinish_utxo *)calloc(vin0_needed,sizeof(*utxos)); utxos = (struct dicefinish_utxo *)calloc(vin0_needed,sizeof(*utxos));
if ( (n= dicefinish_utxosget(num,utxos,vin0_needed,coinaddr)) > 0 ) if ( (n= dicefinish_utxosget(num,utxos,vin0_needed,coinaddr)) > 0 )
{ {
//fprintf(stderr,"iter.%d vin0_needed.%d got %d, num 0.0002 %d\n",iter,vin0_needed,n,num); //fprintf(stderr,"iter.%d vin0_needed.%d got %d, num 0.0002 %d\n",iter,vin0_needed,n,num);
m = 0; m = 0;
DL_FOREACH_SAFE(DICEFINISH_LIST,ptr,tmp) DL_FOREACH_SAFE(DICEFINISH_LIST,ptr,tmp)
{ {
@@ -484,7 +484,8 @@ void *dicefinish(void *_ptr)
//fprintf(stderr,"error ready.%d dicefinish %d of %d process %s %s using need %.8f finish.%s size.%d betspent.%d\n",ptr->bettxid_ready,m,n,iter<0?"loss":"win",ptr->bettxid.GetHex().c_str(),(double)(iter<0 ? 0 : ptr->winamount)/COIN,ptr->txid.GetHex().c_str(),(int32_t)ptr->rawtx.size(),dice_betspent((char *)"dicefinish",ptr->bettxid)); //fprintf(stderr,"error ready.%d dicefinish %d of %d process %s %s using need %.8f finish.%s size.%d betspent.%d\n",ptr->bettxid_ready,m,n,iter<0?"loss":"win",ptr->bettxid.GetHex().c_str(),(double)(iter<0 ? 0 : ptr->winamount)/COIN,ptr->txid.GetHex().c_str(),(int32_t)ptr->rawtx.size(),dice_betspent((char *)"dicefinish",ptr->bettxid));
} }
} }
} } else if ( system("cc/dapps/sendmany100") != 0 )
fprintf(stderr,"error issing cc/dapps/sendmany100\n");
free(utxos); free(utxos);
} }
} }
@@ -533,7 +534,7 @@ void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid,
else else
{ {
//fprintf(stderr,"DiceQueue status bettxid.%s already in list\n",bettxid.GetHex().c_str()); //fprintf(stderr,"DiceQueue status bettxid.%s already in list\n",bettxid.GetHex().c_str());
_dicehash_clear(bettxid); //_dicehash_clear(bettxid);
} }
pthread_mutex_unlock(&DICE_MUTEX); pthread_mutex_unlock(&DICE_MUTEX);
} }

View File

@@ -557,7 +557,7 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& input) const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& input)
{ {
assert(coins); assert(coins);
if (coins->nHeight < 6400 && !strcmp(ASSETCHAINS_SYMBOL, "VRSC")) /*if (coins->nHeight < 6400 && !strcmp(ASSETCHAINS_SYMBOL, "VRSC"))
{ {
std::string hc = input.prevout.hash.ToString(); std::string hc = input.prevout.hash.ToString();
if (LaunchMap().lmap.count(hc)) if (LaunchMap().lmap.count(hc))
@@ -568,7 +568,7 @@ const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& in
return txData.scriptPubKey; return txData.scriptPubKey;
} }
} }
} }*/
return coins->vout[input.prevout.n].scriptPubKey; return coins->vout[input.prevout.n].scriptPubKey;
} }

View File

@@ -24,7 +24,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "zcash/IncrementalMerkleTree.hpp" #include "zcash/IncrementalMerkleTree.hpp"
#include "veruslaunch.h" //#include "veruslaunch.h"
/** /**
* Pruned version of CTransaction: only retains metadata and unspent transaction outputs * Pruned version of CTransaction: only retains metadata and unspent transaction outputs
@@ -456,7 +456,7 @@ class CTransactionExceptionData
CTransactionExceptionData() : scriptPubKey(), voutMask() {} CTransactionExceptionData() : scriptPubKey(), voutMask() {}
}; };
class CLaunchMap /*class CLaunchMap
{ {
public: public:
std::unordered_map<std::string, CTransactionExceptionData> lmap; std::unordered_map<std::string, CTransactionExceptionData> lmap;
@@ -477,7 +477,7 @@ class CLaunchMap
} }
} }
}; };
static CLaunchMap launchMap = CLaunchMap(); static CLaunchMap launchMap = CLaunchMap();*/
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */ /** CCoinsView that adds a memory cache for transactions to another CCoinsView */
class CCoinsViewCache : public CCoinsViewBacked class CCoinsViewCache : public CCoinsViewBacked
@@ -507,7 +507,7 @@ public:
~CCoinsViewCache(); ~CCoinsViewCache();
// Standard CCoinsView methods // Standard CCoinsView methods
static CLaunchMap &LaunchMap() { return launchMap; } //static CLaunchMap &LaunchMap() { return launchMap; }
bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;

View File

@@ -69,7 +69,6 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
destNotarisationTxid = nota.first; destNotarisationTxid = nota.first;
else if (seenOwnNotarisations == 2) else if (seenOwnNotarisations == 2)
goto end; goto end;
fprintf(stderr, "kmd heigt notarisation added: %d\n",kmdHeight-i);
//break; //break;
} }
} }
@@ -167,8 +166,6 @@ TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_
if (MoMoM.IsNull()) if (MoMoM.IsNull())
throw std::runtime_error("No MoMs found"); throw std::runtime_error("No MoMs found");
printf("[%s] GetCrossChainProof MoMoM: %s\n", targetSymbol,MoMoM.GetHex().data());
// Find index of source MoM in MoMoM // Find index of source MoM in MoMoM
int nIndex; int nIndex;
for (nIndex=0; nIndex<moms.size(); nIndex++) { for (nIndex=0; nIndex<moms.size(); nIndex++) {

View File

@@ -291,7 +291,7 @@ TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesRejectOtherTx) {
{ {
SCOPED_TRACE("BlockOverwinterRulesRejectSaplingTx"); SCOPED_TRACE("BlockOverwinterRulesRejectSaplingTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-overwinter-tx-version-group-id"); ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "bad-overwinter-tx-version-group-id");
} }
} }
@@ -319,6 +319,6 @@ TEST_F(ContextualCheckBlockTest, BlockSaplingRulesRejectOtherTx) {
{ {
SCOPED_TRACE("BlockSaplingRulesRejectOverwinterTx"); SCOPED_TRACE("BlockSaplingRulesRejectOverwinterTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-sapling-tx-version-group-id"); ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "bad-sapling-tx-version-group-id");
} }
} }

View File

@@ -844,7 +844,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
// Set this early so that experimental features are correctly enabled/disabled // Set this early so that experimental features are correctly enabled/disabled
fExperimentalMode = GetBoolArg("-experimentalfeatures", false); fExperimentalMode = GetBoolArg("-experimentalfeatures", true);
// Fail early if user has set experimental options without the global flag // Fail early if user has set experimental options without the global flag
if (!fExperimentalMode) { if (!fExperimentalMode) {

View File

@@ -1833,6 +1833,22 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
else return(0); else return(0);
} }
int32_t komodo_acpublic(uint32_t tiptime)
{
int32_t acpublic = ASSETCHAINS_PUBLIC; CBlockIndex *pindex;
if ( acpublic == 0 )
{
if ( tiptime == 0 )
{
if ( (pindex= chainActive.LastTip()) != 0 )
tiptime = pindex->nTime;
}
if ( (ASSETCHAINS_SYMBOL[0] == 0 || strcmp(ASSETCHAINS_SYMBOL,"ZEX") == 0) && tiptime >= KOMODO_SAPLING_DEADLINE )
acpublic = 1;
}
return(acpublic);
}
int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock) int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
{ {
CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0; CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;

View File

@@ -78,7 +78,7 @@ static int64_t nTimeBestReceived = 0;
CWaitableCriticalSection csBestBlock; CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange; CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0; int nScriptCheckThreads = 0;
bool fExperimentalMode = false; bool fExperimentalMode = true;
bool fImporting = false; bool fImporting = false;
bool fReindex = false; bool fReindex = false;
bool fTxIndex = false; bool fTxIndex = false;
@@ -1035,9 +1035,12 @@ bool ContextualCheckTransaction(
} }
// Reject transactions with non-Sapling version group ID // Reject transactions with non-Sapling version group ID
if (tx.fOverwintered && tx.nVersionGroupId != SAPLING_VERSION_GROUP_ID) { if (tx.fOverwintered && tx.nVersionGroupId != SAPLING_VERSION_GROUP_ID)
return state.DoS(dosLevel, error("CheckTransaction(): invalid Sapling tx version"), {
REJECT_INVALID, "bad-sapling-tx-version-group-id"); //return state.DoS(dosLevel, error("CheckTransaction(): invalid Sapling tx version"),REJECT_INVALID, "bad-sapling-tx-version-group-id");
return state.DoS(isInitBlockDownload() ? 0 : dosLevel,
error("CheckTransaction(): invalid Sapling tx version"),
REJECT_INVALID, "bad-sapling-tx-version-group-id");
} }
// Reject transactions with invalid version // Reject transactions with invalid version
@@ -1059,9 +1062,12 @@ bool ContextualCheckTransaction(
} }
// Reject transactions with non-Overwinter version group ID // Reject transactions with non-Overwinter version group ID
if (tx.fOverwintered && tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) { if (tx.fOverwintered && tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID)
return state.DoS(dosLevel, error("CheckTransaction(): invalid Overwinter tx version"), {
REJECT_INVALID, "bad-overwinter-tx-version-group-id"); //return state.DoS(dosLevel, error("CheckTransaction(): invalid Overwinter tx version"),REJECT_INVALID, "bad-overwinter-tx-version-group-id");
return state.DoS(isInitBlockDownload() ? 0 : dosLevel,
error("CheckTransaction(): invalid Overwinter tx version"),
REJECT_INVALID, "bad-overwinter-tx-version-group-id");
} }
// Reject transactions with invalid version // Reject transactions with invalid version
@@ -1268,10 +1274,12 @@ int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only
return(0); return(0);
} }
int32_t komodo_acpublic(uint32_t tiptime);
bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransaction& tx, CValidationState &state) bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransaction& tx, CValidationState &state)
{ {
// Basic checks that don't depend on any context // Basic checks that don't depend on any context
int32_t invalid_private_taddr=0,z_z=0,z_t=0,t_z=0,acpublic = ASSETCHAINS_PUBLIC; int32_t invalid_private_taddr=0,z_z=0,z_t=0,t_z=0,acpublic = komodo_acpublic(tiptime);
/** /**
* Previously: * Previously:
* 1. The consensus rule below was: * 1. The consensus rule below was:
@@ -1376,8 +1384,6 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio
return state.DoS(100, error("CheckTransaction(): tx.valueBalance has no sources or sinks"), return state.DoS(100, error("CheckTransaction(): tx.valueBalance has no sources or sinks"),
REJECT_INVALID, "bad-txns-valuebalance-nonzero"); REJECT_INVALID, "bad-txns-valuebalance-nonzero");
} }
if ( (ASSETCHAINS_SYMBOL[0] == 0 || strcmp(ASSETCHAINS_SYMBOL,"ZEX") == 0) && tiptime >= KOMODO_SAPLING_DEADLINE )
acpublic = 1;
if ( acpublic != 0 && (tx.vShieldedSpend.empty() == 0 || tx.vShieldedOutput.empty() == 0) ) if ( acpublic != 0 && (tx.vShieldedSpend.empty() == 0 || tx.vShieldedOutput.empty() == 0) )
{ {
return state.DoS(100, error("CheckTransaction(): this is a public chain, no sapling allowed"), return state.DoS(100, error("CheckTransaction(): this is a public chain, no sapling allowed"),
@@ -1758,8 +1764,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{ {
if (pfMissingInputs) if (pfMissingInputs)
*pfMissingInputs = true; *pfMissingInputs = true;
//fprintf(stderr,"missing inputs in %s\n",tx.GetHash().ToString().c_str()); //fprintf(stderr,"missing inputs\n");
return state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing"); //return state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing");
return(false);
} }
} }
@@ -4745,6 +4752,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
mempool.remove(tx, removed, false); mempool.remove(tx, removed, false);
} }
// add all the txs in the block to the empty mempool. // add all the txs in the block to the empty mempool.
// CC validation shouldnt (cant) depend on the state of mempool!
while ( 1 ) while ( 1 )
{ {
for (i=0; i<block.vtx.size(); i++) for (i=0; i<block.vtx.size(); i++)
@@ -4814,18 +4822,28 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
{ {
// here we add back all txs from the temp mempool to the main mempool. // here we add back all txs from the temp mempool to the main mempool.
// which removes any tx locally that were invalid after the block arrives. // which removes any tx locally that were invalid after the block arrives.
int invalidtxs = 0; int numadded,numiters = 0;
CValidationState state; bool fMissingInputs,fOverrideFees = false;
list<CTransaction> removed;
LOCK(mempool.cs); LOCK(mempool.cs);
BOOST_FOREACH(const CTxMemPoolEntry& e, tmpmempool.mapTx) { while ( 1 )
CTransaction tx = e.GetTx(); {
CValidationState state; bool fMissingInputs,fOverrideFees = false; numiters++;
numadded = 0;
if (AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees) == false ) BOOST_FOREACH(const CTxMemPoolEntry& e, tmpmempool.mapTx)
invalidtxs++; {
//else fprintf(stderr, "added mempool tx back to mempool\n"); CTransaction tx = e.GetTx();
if (AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees) == true )
{
numadded++;
tmpmempool.remove(tx, removed, false);
}
}
if ( numadded == 0 )
break;
} }
if ( 0 && invalidtxs > 0 ) if ( 0 && numadded > 0 )
fprintf(stderr, "number of invalid txs: %d\n",invalidtxs ); fprintf(stderr, "CC mempool add: numiters.%d numadded.%d remains.%d\n",numiters,numadded,(int32_t)tmpmempool.size());
// empty the temp mempool for next time. // empty the temp mempool for next time.
tmpmempool.clear(); tmpmempool.clear();
} }

View File

@@ -762,7 +762,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
} else } else
{ {
if (!isStake || ASSETCHAINS_STAKED != 0) //if ( !isStake || ASSETCHAINS_STAKED != 0 )
{ {
if (!reservekey.GetReservedKey(pubkey)) if (!reservekey.GetReservedKey(pubkey))
{ {

View File

@@ -139,7 +139,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "z_shieldcoinbase", 3}, { "z_shieldcoinbase", 3},
{ "z_getoperationstatus", 0}, { "z_getoperationstatus", 0},
{ "z_getoperationresult", 0}, { "z_getoperationresult", 0},
{ "z_importkey", 1 },
{ "paxprice", 4 }, { "paxprice", 4 },
{ "paxprices", 3 }, { "paxprices", 3 },
{ "paxpending", 0 }, { "paxpending", 0 },

View File

@@ -58,7 +58,7 @@ uint32_t komodo_segid32(char *coinaddr);
int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height); int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height);
int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp);
int8_t StakedNotaryID(std::string &notaryname, char *Raddress); int8_t StakedNotaryID(std::string &notaryname, char *Raddress);
#define KOMODO_VERSION "0.3.2" #define KOMODO_VERSION "0.3.1"
#define VERUS_VERSION "0.4.0g" #define VERUS_VERSION "0.4.0g"
extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
extern uint32_t ASSETCHAINS_CC; extern uint32_t ASSETCHAINS_CC;

View File

@@ -1167,12 +1167,12 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
if ( txConst.IsCoinBase() != 0 ) if ( txConst.IsCoinBase() != 0 )
{ {
if ( (txpow & 2) == 0 ) if ( (txpow & 2) == 0 )
txpow == 0; txpow = 0;
} }
else else
{ {
if ( (txpow & 1) == 0 ) if ( (txpow & 1) == 0 )
txpow == 0; txpow = 0;
} }
} }
while ( 1 ) while ( 1 )

View File

@@ -33,7 +33,10 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
int32_t komodo_longestchain(); int32_t komodo_longestchain();
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
<<<<<<< HEAD:src/rpcblockchain.old
extern int32_t KOMODO_LONGESTCHAIN; extern int32_t KOMODO_LONGESTCHAIN;
=======
>>>>>>> master:src/rpcblockchain.cpp
double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty) double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty)
{ {

View File

@@ -673,6 +673,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nCachedBranchId = diskindex.nCachedBranchId; pindexNew->nCachedBranchId = diskindex.nCachedBranchId;
pindexNew->nTx = diskindex.nTx; pindexNew->nTx = diskindex.nTx;
pindexNew->nSproutValue = diskindex.nSproutValue; pindexNew->nSproutValue = diskindex.nSproutValue;
pindexNew->nSaplingValue = diskindex.nSaplingValue;
// Consistency checks // Consistency checks
auto header = pindexNew->GetBlockHeader(); auto header = pindexNew->GetBlockHeader();

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
// Copyright (c) 2018 The Verus developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef VERUS_LAUNCH_H
#define VERUS_LAUNCH_H
#include <string>
#define WHITELIST_COUNT 704
extern const char *whitelist_ids[WHITELIST_COUNT];
extern const char *whitelist_address;
extern uint64_t whitelist_masks[WHITELIST_COUNT];
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@
#include "asyncrpcoperation.h" #include "asyncrpcoperation.h"
#include "paymentdisclosure.h" #include "paymentdisclosure.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "transaction_builder.h"
#include "wallet.h" #include "wallet.h"
#include "zcash/Address.hpp" #include "zcash/Address.hpp"
#include "zcash/JoinSplit.hpp" #include "zcash/JoinSplit.hpp"
@@ -24,11 +25,13 @@
using namespace libzcash; using namespace libzcash;
// Input UTXO is a tuple of txid, vout, amount // Input UTXO is a tuple of txid, vout, amount, script
typedef std::tuple<COutPoint, CAmount> MergeToAddressInputUTXO; typedef std::tuple<COutPoint, CAmount, CScript> MergeToAddressInputUTXO;
// Input JSOP is a tuple of JSOutpoint, note, amount, spending key // Input JSOP is a tuple of JSOutpoint, note, amount, spending key
typedef std::tuple<JSOutPoint, SproutNote, CAmount, SpendingKey> MergeToAddressInputNote; typedef std::tuple<JSOutPoint, SproutNote, CAmount, SproutSpendingKey> MergeToAddressInputSproutNote;
typedef std::tuple<SaplingOutPoint, SaplingNote, CAmount, SaplingExpandedSpendingKey> MergeToAddressInputSaplingNote;
// A recipient is a tuple of address, memo (optional if zaddr) // A recipient is a tuple of address, memo (optional if zaddr)
typedef std::tuple<std::string, std::string> MergeToAddressRecipient; typedef std::tuple<std::string, std::string> MergeToAddressRecipient;
@@ -53,33 +56,36 @@ class AsyncRPCOperation_mergetoaddress : public AsyncRPCOperation
{ {
public: public:
AsyncRPCOperation_mergetoaddress( AsyncRPCOperation_mergetoaddress(
CMutableTransaction contextualTx, boost::optional<TransactionBuilder> builder,
std::vector<MergeToAddressInputUTXO> utxoInputs, CMutableTransaction contextualTx,
std::vector<MergeToAddressInputNote> noteInputs, std::vector<MergeToAddressInputUTXO> utxoInputs,
MergeToAddressRecipient recipient, std::vector<MergeToAddressInputSproutNote> sproutNoteInputs,
CAmount fee = MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE, std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs,
UniValue contextInfo = NullUniValue); MergeToAddressRecipient recipient,
CAmount fee = MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE,
UniValue contextInfo = NullUniValue);
virtual ~AsyncRPCOperation_mergetoaddress(); virtual ~AsyncRPCOperation_mergetoaddress();
// We don't want to be copied or moved around // We don't want to be copied or moved around
AsyncRPCOperation_mergetoaddress(AsyncRPCOperation_mergetoaddress const&) = delete; // Copy construct AsyncRPCOperation_mergetoaddress(AsyncRPCOperation_mergetoaddress const&) = delete; // Copy construct
AsyncRPCOperation_mergetoaddress(AsyncRPCOperation_mergetoaddress&&) = delete; // Move construct AsyncRPCOperation_mergetoaddress(AsyncRPCOperation_mergetoaddress&&) = delete; // Move construct
AsyncRPCOperation_mergetoaddress& operator=(AsyncRPCOperation_mergetoaddress const&) = delete; // Copy assign AsyncRPCOperation_mergetoaddress& operator=(AsyncRPCOperation_mergetoaddress const&) = delete; // Copy assign
AsyncRPCOperation_mergetoaddress& operator=(AsyncRPCOperation_mergetoaddress&&) = delete; // Move assign AsyncRPCOperation_mergetoaddress& operator=(AsyncRPCOperation_mergetoaddress&&) = delete; // Move assign
virtual void main(); virtual void main();
virtual UniValue getStatus() const; virtual UniValue getStatus() const;
bool testmode = false; // Set to true to disable sending txs and generating proofs bool testmode = false; // Set to true to disable sending txs and generating proofs
bool paymentDisclosureMode = false; // Set to true to save esk for encrypted notes in payment disclosure database. bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database.
private: private:
friend class TEST_FRIEND_AsyncRPCOperation_mergetoaddress; // class for unit testing friend class TEST_FRIEND_AsyncRPCOperation_mergetoaddress; // class for unit testing
UniValue contextinfo_; // optional data to include in return value from getStatus() UniValue contextinfo_; // optional data to include in return value from getStatus()
bool isUsingBuilder_; // Indicates that no Sprout addresses are involved
uint32_t consensusBranchId_; uint32_t consensusBranchId_;
CAmount fee_; CAmount fee_;
int mindepth_; int mindepth_;
@@ -88,43 +94,45 @@ private:
bool isToZaddr_; bool isToZaddr_;
CTxDestination toTaddr_; CTxDestination toTaddr_;
PaymentAddress toPaymentAddress_; PaymentAddress toPaymentAddress_;
uint256 joinSplitPubKey_; uint256 joinSplitPubKey_;
unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES]; unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES];
// The key is the result string from calling JSOutPoint::ToString() // The key is the result string from calling JSOutPoint::ToString()
std::unordered_map<std::string, MergeToAddressWitnessAnchorData> jsopWitnessAnchorMap; std::unordered_map<std::string, MergeToAddressWitnessAnchorData> jsopWitnessAnchorMap;
std::vector<MergeToAddressInputUTXO> utxoInputs_; std::vector<MergeToAddressInputUTXO> utxoInputs_;
std::vector<MergeToAddressInputNote> noteInputs_; std::vector<MergeToAddressInputSproutNote> sproutNoteInputs_;
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs_;
TransactionBuilder builder_;
CTransaction tx_; CTransaction tx_;
std::array<unsigned char, ZC_MEMO_SIZE> get_memo_from_hex_string(std::string s); std::array<unsigned char, ZC_MEMO_SIZE> get_memo_from_hex_string(std::string s);
bool main_impl(); bool main_impl();
// JoinSplit without any input notes to spend // JoinSplit without any input notes to spend
UniValue perform_joinsplit(MergeToAddressJSInfo&); UniValue perform_joinsplit(MergeToAddressJSInfo&);
// JoinSplit with input notes to spend (JSOutPoints)) // JoinSplit with input notes to spend (JSOutPoints))
UniValue perform_joinsplit(MergeToAddressJSInfo&, std::vector<JSOutPoint>&); UniValue perform_joinsplit(MergeToAddressJSInfo&, std::vector<JSOutPoint>&);
// JoinSplit where you have the witnesses and anchor // JoinSplit where you have the witnesses and anchor
UniValue perform_joinsplit( UniValue perform_joinsplit(
MergeToAddressJSInfo& info, MergeToAddressJSInfo& info,
std::vector<boost::optional<SproutWitness>> witnesses, std::vector<boost::optional<SproutWitness>> witnesses,
uint256 anchor); uint256 anchor);
void sign_send_raw_transaction(UniValue obj); // throws exception if there was an error void sign_send_raw_transaction(UniValue obj); // throws exception if there was an error
void lock_utxos(); void lock_utxos();
void unlock_utxos(); void unlock_utxos();
void lock_notes(); void lock_notes();
void unlock_notes(); void unlock_notes();
// payment disclosure! // payment disclosure!
std::vector<PaymentDisclosureKeyInfo> paymentDisclosureData_; std::vector<PaymentDisclosureKeyInfo> paymentDisclosureData_;
}; };
@@ -135,54 +143,54 @@ class TEST_FRIEND_AsyncRPCOperation_mergetoaddress
{ {
public: public:
std::shared_ptr<AsyncRPCOperation_mergetoaddress> delegate; std::shared_ptr<AsyncRPCOperation_mergetoaddress> delegate;
TEST_FRIEND_AsyncRPCOperation_mergetoaddress(std::shared_ptr<AsyncRPCOperation_mergetoaddress> ptr) : delegate(ptr) {} TEST_FRIEND_AsyncRPCOperation_mergetoaddress(std::shared_ptr<AsyncRPCOperation_mergetoaddress> ptr) : delegate(ptr) {}
CTransaction getTx() CTransaction getTx()
{ {
return delegate->tx_; return delegate->tx_;
} }
void setTx(CTransaction tx) void setTx(CTransaction tx)
{ {
delegate->tx_ = tx; delegate->tx_ = tx;
} }
// Delegated methods // Delegated methods
std::array<unsigned char, ZC_MEMO_SIZE> get_memo_from_hex_string(std::string s) std::array<unsigned char, ZC_MEMO_SIZE> get_memo_from_hex_string(std::string s)
{ {
return delegate->get_memo_from_hex_string(s); return delegate->get_memo_from_hex_string(s);
} }
bool main_impl() bool main_impl()
{ {
return delegate->main_impl(); return delegate->main_impl();
} }
UniValue perform_joinsplit(MergeToAddressJSInfo& info) UniValue perform_joinsplit(MergeToAddressJSInfo& info)
{ {
return delegate->perform_joinsplit(info); return delegate->perform_joinsplit(info);
} }
UniValue perform_joinsplit(MergeToAddressJSInfo& info, std::vector<JSOutPoint>& v) UniValue perform_joinsplit(MergeToAddressJSInfo& info, std::vector<JSOutPoint>& v)
{ {
return delegate->perform_joinsplit(info, v); return delegate->perform_joinsplit(info, v);
} }
UniValue perform_joinsplit( UniValue perform_joinsplit(
MergeToAddressJSInfo& info, MergeToAddressJSInfo& info,
std::vector<boost::optional<SproutWitness>> witnesses, std::vector<boost::optional<SproutWitness>> witnesses,
uint256 anchor) uint256 anchor)
{ {
return delegate->perform_joinsplit(info, witnesses, anchor); return delegate->perform_joinsplit(info, witnesses, anchor);
} }
void sign_send_raw_transaction(UniValue obj) void sign_send_raw_transaction(UniValue obj)
{ {
delegate->sign_send_raw_transaction(obj); delegate->sign_send_raw_transaction(obj);
} }
void set_state(OperationStatus state) void set_state(OperationStatus state)
{ {
delegate->state_.store(state); delegate->state_.store(state);

View File

@@ -123,7 +123,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
// Enable payment disclosure if requested // Enable payment disclosure if requested
paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true);
} }
AsyncRPCOperation_sendmany::~AsyncRPCOperation_sendmany() { AsyncRPCOperation_sendmany::~AsyncRPCOperation_sendmany() {
@@ -1366,7 +1366,8 @@ void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CBitcoinAddress *
} }
std::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_from_hex_string(std::string s) { std::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_from_hex_string(std::string s) {
std::array<unsigned char, ZC_MEMO_SIZE> memo = {{0x00}}; // initialize to default memo (no_memo), see section 5.5 of the protocol spec
std::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}};
std::vector<unsigned char> rawMemo = ParseHex(s.c_str()); std::vector<unsigned char> rawMemo = ParseHex(s.c_str());

View File

@@ -75,7 +75,7 @@ public:
bool testmode = false; // Set to true to disable sending txs and generating proofs bool testmode = false; // Set to true to disable sending txs and generating proofs
bool paymentDisclosureMode = false; // Set to true to save esk for encrypted notes in payment disclosure database. bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database.
private: private:
friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing

View File

@@ -93,7 +93,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
lock_utxos(); lock_utxos();
// Enable payment disclosure if requested // Enable payment disclosure if requested
paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true);
} }
AsyncRPCOperation_shieldcoinbase::~AsyncRPCOperation_shieldcoinbase() { AsyncRPCOperation_shieldcoinbase::~AsyncRPCOperation_shieldcoinbase() {

View File

@@ -65,7 +65,7 @@ public:
bool testmode = false; // Set to true to disable sending txs and generating proofs bool testmode = false; // Set to true to disable sending txs and generating proofs
bool cheatSpend = false; // set when this is shielding a cheating coinbase bool cheatSpend = false; // set when this is shielding a cheating coinbase
bool paymentDisclosureMode = false; // Set to true to save esk for encrypted notes in payment disclosure database. bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database.
private: private:
friend class ShieldToAddress; friend class ShieldToAddress;

View File

@@ -42,7 +42,7 @@ UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
string enableArg = "paymentdisclosure"; string enableArg = "paymentdisclosure";
auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, false); auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, true);
string strPaymentDisclosureDisabledMsg = ""; string strPaymentDisclosureDisabledMsg = "";
if (!fEnablePaymentDisclosure) { if (!fEnablePaymentDisclosure) {
strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_getpaymentdisclosure", enableArg); strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_getpaymentdisclosure", enableArg);
@@ -149,7 +149,7 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
string enableArg = "paymentdisclosure"; string enableArg = "paymentdisclosure";
auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, false); auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, true);
string strPaymentDisclosureDisabledMsg = ""; string strPaymentDisclosureDisabledMsg = "";
if (!fEnablePaymentDisclosure) { if (!fEnablePaymentDisclosure) {
strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_validatepaymentdisclosure", enableArg); strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_validatepaymentdisclosure", enableArg);

View File

@@ -112,7 +112,6 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
} else entry.push_back(Pair("confirmations", confirms)); } else entry.push_back(Pair("confirmations", confirms));
uint256 hash = wtx.GetHash(); uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex())); entry.push_back(Pair("txid", hash.GetHex()));
UniValue conflicts(UniValue::VARR); UniValue conflicts(UniValue::VARR);
@@ -1769,6 +1768,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
BOOST_FOREACH(const COutputEntry& r, listReceived) BOOST_FOREACH(const COutputEntry& r, listReceived)
{ {
string account; string account;
//fprintf(stderr,"recv iter %s\n",wtx.GetHash().GetHex().c_str());
if (pwalletMain->mapAddressBook.count(r.destination)) if (pwalletMain->mapAddressBook.count(r.destination))
account = pwalletMain->mapAddressBook[r.destination].name; account = pwalletMain->mapAddressBook[r.destination].name;
if (fAllAccounts || (account == strAccount)) if (fAllAccounts || (account == strAccount))
@@ -1919,7 +1919,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
{ {
CWalletTx *const pwtx = (*it).second.first; CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0) if (pwtx != 0)
{
//fprintf(stderr,"pwtx iter.%d %s\n",(int32_t)pwtx->nOrderPos,pwtx->GetHash().GetHex().c_str());
ListTransactions(*pwtx, strAccount, 0, true, ret, filter); ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
} //else fprintf(stderr,"null pwtx\n");
CAccountingEntry *const pacentry = (*it).second.second; CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0) if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, ret); AcentryToJSON(*pacentry, strAccount, ret);
@@ -2445,6 +2448,7 @@ UniValue walletlock(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
} }
int32_t komodo_acpublic(uint32_t tiptime);
UniValue encryptwallet(const UniValue& params, bool fHelp) UniValue encryptwallet(const UniValue& params, bool fHelp)
{ {
@@ -2452,7 +2456,8 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
string enableArg = "developerencryptwallet"; string enableArg = "developerencryptwallet";
auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-" + enableArg, false); int32_t flag = (komodo_acpublic(0) || ASSETCHAINS_SYMBOL[0] == 0);
auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-" + enableArg, flag);
std::string strWalletEncryptionDisabledMsg = ""; std::string strWalletEncryptionDisabledMsg = "";
if (!fEnableWalletEncryption) { if (!fEnableWalletEncryption) {
@@ -2952,8 +2957,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
"\nExamples\n" "\nExamples\n"
+ HelpExampleCli("z_listunspent", "") + HelpExampleCli("z_listunspent", "")
+ HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"") + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"")
+ HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"") + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\",\\\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\\\"]\"")
); );
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR));
@@ -3789,8 +3794,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
" \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n" " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
"}\n" "}\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + HelpExampleCli("z_listreceivedbyaddress", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
+ HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + HelpExampleRpc("z_listreceivedbyaddress", "\"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -4122,8 +4127,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
"\nResult:\n" "\nResult:\n"
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'") + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]'")
+ HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]") + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -4213,15 +4218,10 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
} }
// If we are sending from a shielded address, all recipient // If we are sending from a shielded address, all recipient
// shielded addresses must be of the same type. // shielded addresses must be of the same type.
if (fromSprout && toSapling) { if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
throw JSONRPCError( throw JSONRPCError(
RPC_INVALID_PARAMETER, RPC_INVALID_PARAMETER,
"Cannot send from a Sprout address to a Sapling address using z_sendmany"); "Cannot send between Sprout and Sapling addresses using z_sendmany");
}
if (fromSapling && toSprout) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"Cannot send from a Sapling address to a Sprout address using z_sendmany");
} }
} else { } else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
@@ -4433,8 +4433,8 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
" \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
"}\n" "}\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
+ HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -4622,11 +4622,13 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
return o; return o;
} }
#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
#define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10 #define MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT 10
#define MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT 90
#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION) #define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION)
#define OUTPUTDESCRIPTION_SIZE GetSerializeSize(OutputDescription(), SER_NETWORK, PROTOCOL_VERSION)
#define SPENDDESCRIPTION_SIZE GetSerializeSize(SpendDescription(), SER_NETWORK, PROTOCOL_VERSION)
UniValue z_mergetoaddress(const UniValue& params, bool fHelp) UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
{ {
@@ -4634,11 +4636,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
string enableArg = "zmergetoaddress"; string enableArg = "zmergetoaddress";
auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, false); auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true);
std::string strDisabledMsg = ""; std::string strDisabledMsg = "";
if (!fEnableMergeToAddress) { if (!fEnableMergeToAddress) {
strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg); strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
} }
<<<<<<< HEAD
if (fHelp || params.size() < 2 || params.size() > 7) if (fHelp || params.size() < 2 || params.size() > 7)
throw runtime_error( throw runtime_error(
@@ -4691,20 +4694,70 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
+ HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
); );
=======
if (fHelp || params.size() < 2 || params.size() > 6)
throw runtime_error(
"z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
+ strDisabledMsg +
"\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
"\nto combine those into a single note."
"\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
"\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
"\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
"\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the"
"\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of"
+ strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. fromaddresses (string, required) A JSON array with addresses.\n"
" The following special strings are accepted inside the array:\n"
" - \"ANY_TADDR\": Merge UTXOs from any t-addrs belonging to the wallet.\n"
" - \"ANY_SPROUT\": Merge notes from any Sprout z-addrs belonging to the wallet.\n"
" - \"ANY_SAPLING\": Merge notes from any Sapling z-addrs belonging to the wallet.\n"
" If a special string is given, any given addresses of that type will be ignored.\n"
" [\n"
" \"address\" (string) Can be a t-addr or a z-addr\n"
" ,...\n"
" ]\n"
"2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
"3. fee (numeric, optional, default="
+ strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
"4. transparent_limit (numeric, optional, default="
+ strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
"4. shielded_limit (numeric, optional, default="
+ strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
"5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
"\nResult:\n"
"{\n"
" \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
" \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
" \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
" \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
" \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
" \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
" \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
" \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
" \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
+ HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
);
>>>>>>> e719e666307adb77fb4b79c7737256ea959fe188
if (!fEnableMergeToAddress) { if (!fEnableMergeToAddress) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled."); throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
} }
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
bool useAny = false;
bool useAnyUTXO = false; bool useAnyUTXO = false;
bool useAnyNote = false; bool useAnySprout = false;
bool useAnySapling = false;
std::set<CTxDestination> taddrs = {}; std::set<CTxDestination> taddrs = {};
std::set<libzcash::PaymentAddress> zaddrs = {}; std::set<libzcash::PaymentAddress> zaddrs = {};
uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
UniValue addresses = params[0].get_array(); UniValue addresses = params[0].get_array();
if (addresses.size()==0) if (addresses.size()==0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty."); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
@@ -4713,39 +4766,28 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
std::set<std::string> setAddress; std::set<std::string> setAddress;
// Sources // Sources
bool containsSaplingZaddrSource = false;
for (const UniValue& o : addresses.getValues()) { for (const UniValue& o : addresses.getValues()) {
if (!o.isStr()) if (!o.isStr())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
std::string address = o.get_str(); std::string address = o.get_str();
if (address == "*") {
useAny = true; if (address == "ANY_TADDR") {
} else if (address == "ANY_TADDR") {
useAnyUTXO = true; useAnyUTXO = true;
} else if (address == "ANY_ZADDR") { } else if (address == "ANY_SPROUT") {
useAnyNote = true; useAnySprout = true;
} else if (address == "ANY_SAPLING") {
useAnySapling = true;
} else { } else {
CTxDestination taddr = DecodeDestination(address); CTxDestination taddr = DecodeDestination(address);
if (IsValidDestination(taddr)) { if (IsValidDestination(taddr)) {
// Ignore any listed t-addrs if we are using all of them taddrs.insert(taddr);
if (!(useAny || useAnyUTXO)) {
taddrs.insert(taddr);
}
} else { } else {
auto zaddr = DecodePaymentAddress(address); auto zaddr = DecodePaymentAddress(address);
if (IsValidPaymentAddress(zaddr, branchId)) { if (IsValidPaymentAddress(zaddr)) {
// Ignore listed z-addrs if we are using all of them zaddrs.insert(zaddr);
if (!(useAny || useAnyNote)) {
zaddrs.insert(zaddr);
}
// Check if z-addr is Sapling
bool isSapling = boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr;
containsSaplingZaddrSource |= isSapling;
} else { } else {
throw JSONRPCError( throw JSONRPCError(RPC_INVALID_PARAMETER, string("Unknown address format: ") + address);
RPC_INVALID_PARAMETER,
string("Invalid parameter, unknown address format: ") + address);
} }
} }
} }
@@ -4755,28 +4797,38 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
setAddress.insert(address); setAddress.insert(address);
} }
if (useAnyUTXO && taddrs.size() > 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\"");
}
if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\"");
}
const int nextBlockHeight = chainActive.Height() + 1;
const bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
const bool saplingActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING);
// Validate the destination address // Validate the destination address
auto destaddress = params[1].get_str(); auto destaddress = params[1].get_str();
bool isToZaddr = false; bool isToSproutZaddr = false;
bool isToSaplingZaddr = false; bool isToSaplingZaddr = false;
CTxDestination taddr = DecodeDestination(destaddress); CTxDestination taddr = DecodeDestination(destaddress);
if (!IsValidDestination(taddr)) { if (!IsValidDestination(taddr)) {
if (IsValidPaymentAddressString(destaddress, branchId)) { auto decodeAddr = DecodePaymentAddress(destaddress);
isToZaddr = true; if (IsValidPaymentAddress(decodeAddr)) {
if (boost::get<libzcash::SaplingPaymentAddress>(&decodeAddr) != nullptr) {
// Is this a Sapling address? isToSaplingZaddr = true;
auto res = DecodePaymentAddress(destaddress); // If Sapling is not active, do not allow sending to a sapling addresses.
if (IsValidPaymentAddress(res)) { if (!saplingActive) {
isToSaplingZaddr = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr; throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
} else { } else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); isToSproutZaddr = true;
} }
} else { } else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
} }
} }
else if ( ASSETCHAINS_PRIVATE != 0 )
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
// Convert fee from currency format to zatoshis // Convert fee from currency format to zatoshis
CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE; CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
@@ -4796,12 +4848,15 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
} }
} }
int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT; int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT;
int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
if (params.size() > 4) { if (params.size() > 4) {
nNoteLimit = params[4].get_int(); int nNoteLimit = params[4].get_int();
if (nNoteLimit < 0) { if (nNoteLimit < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
} }
sproutNoteLimit = nNoteLimit;
saplingNoteLimit = nNoteLimit;
} }
CAmount maximum_utxo_size; CAmount maximum_utxo_size;
@@ -4817,7 +4872,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
std::string memo; std::string memo;
if (params.size() > 6) { if (params.size() > 6) {
memo = params[6].get_str(); memo = params[6].get_str();
if (!isToZaddr) { if (!(isToSproutZaddr || isToSaplingZaddr)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr."); throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
} else if (!IsHex(memo)) { } else if (!IsHex(memo)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format."); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
@@ -4829,50 +4884,29 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
MergeToAddressRecipient recipient(destaddress, memo); MergeToAddressRecipient recipient(destaddress, memo);
int nextBlockHeight = chainActive.Height() + 1;
bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
}
// This RPC does not support Sapling yet.
if (isToSaplingZaddr || containsSaplingZaddrSource) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling is not supported yet by z_mergetoadress");
}
// If this RPC does support Sapling...
// If Sapling is not active, do not allow sending from or sending to Sapling addresses.
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
if (isToSaplingZaddr || containsSaplingZaddrSource) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
}
// Prepare to get UTXOs and notes // Prepare to get UTXOs and notes
std::vector<MergeToAddressInputUTXO> utxoInputs; std::vector<MergeToAddressInputUTXO> utxoInputs;
std::vector<MergeToAddressInputNote> noteInputs; std::vector<MergeToAddressInputSproutNote> sproutNoteInputs;
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs;
CAmount mergedUTXOValue = 0; CAmount mergedUTXOValue = 0;
CAmount mergedNoteValue = 0; CAmount mergedNoteValue = 0;
CAmount remainingUTXOValue = 0; CAmount remainingUTXOValue = 0;
CAmount remainingNoteValue = 0; CAmount remainingNoteValue = 0;
#ifdef __LP64__
uint64_t utxoCounter = 0;
uint64_t noteCounter = 0;
#else
size_t utxoCounter = 0; size_t utxoCounter = 0;
size_t noteCounter = 0; size_t noteCounter = 0;
#endif
bool maxedOutUTXOsFlag = false; bool maxedOutUTXOsFlag = false;
bool maxedOutNotesFlag = false; bool maxedOutNotesFlag = false;
size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0)); size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
size_t estimatedTxSize = 200; // tx overhead + wiggle room size_t estimatedTxSize = 200; // tx overhead + wiggle room
if (isToZaddr) { if (isToSproutZaddr) {
estimatedTxSize += JOINSPLIT_SIZE; estimatedTxSize += JOINSPLIT_SIZE;
} else if (isToSaplingZaddr) {
estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
} }
if (useAny || useAnyUTXO || taddrs.size() > 0) { if (useAnyUTXO || taddrs.size() > 0) {
// Get available utxos // Get available utxos
vector<COutput> vecOutputs; vector<COutput> vecOutputs;
pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
@@ -4883,8 +4917,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
continue; continue;
} }
CScript scriptPubKey = out.tx->vout[out.i].scriptPubKey;
CTxDestination address; CTxDestination address;
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { if (!ExtractDestination(scriptPubKey, address)) {
continue; continue;
} }
// If taddr is not wildcard "*", filter utxos // If taddr is not wildcard "*", filter utxos
@@ -4915,7 +4951,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
} else { } else {
estimatedTxSize += increase; estimatedTxSize += increase;
COutPoint utxo(out.tx->GetHash(), out.i); COutPoint utxo(out.tx->GetHash(), out.i);
utxoInputs.emplace_back(utxo, nValue); utxoInputs.emplace_back(utxo, nValue, scriptPubKey);
mergedUTXOValue += nValue; mergedUTXOValue += nValue;
} }
} }
@@ -4926,23 +4962,40 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
} }
} }
if (useAny || useAnyNote || zaddrs.size() > 0) { if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
// Get available notes // Get available notes
std::vector<CSproutNotePlaintextEntry> sproutEntries; std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries; std::vector<SaplingNoteEntry> saplingEntries;
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs); pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
// If Sapling is not active, do not allow sending from a sapling addresses.
if (!saplingActive && saplingEntries.size() > 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
}
// Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress
if (sproutEntries.size() > 0 && saplingEntries.size() > 0) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
}
// If sending between shielded addresses, they must be the same type
if ((saplingEntries.size() > 0 && isToSproutZaddr) || (sproutEntries.size() > 0 && isToSaplingZaddr)) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"Cannot send between Sprout and Sapling addresses using z_mergetoaddress");
}
// Find unspent notes and update estimated size // Find unspent notes and update estimated size
for (CSproutNotePlaintextEntry& entry : sproutEntries) { for (const CSproutNotePlaintextEntry& entry : sproutEntries) {
noteCounter++; noteCounter++;
CAmount nValue = entry.plaintext.value(); CAmount nValue = entry.plaintext.value();
if (!maxedOutNotesFlag) { if (!maxedOutNotesFlag) {
// If we haven't added any notes yet and the merge is to a // If we haven't added any notes yet and the merge is to a
// z-address, we have already accounted for the first JoinSplit. // z-address, we have already accounted for the first JoinSplit.
size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0; size_t increase = (sproutNoteInputs.empty() && !isToSproutZaddr) || (sproutNoteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
if (estimatedTxSize + increase >= max_tx_size || if (estimatedTxSize + increase >= max_tx_size ||
(nNoteLimit > 0 && noteCounter > nNoteLimit)) (sproutNoteLimit > 0 && noteCounter > sproutNoteLimit))
{ {
maxedOutNotesFlag = true; maxedOutNotesFlag = true;
} else { } else {
@@ -4950,7 +5003,32 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
auto zaddr = entry.address; auto zaddr = entry.address;
SproutSpendingKey zkey; SproutSpendingKey zkey;
pwalletMain->GetSproutSpendingKey(zaddr, zkey); pwalletMain->GetSproutSpendingKey(zaddr, zkey);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey); sproutNoteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey);
mergedNoteValue += nValue;
}
}
if (maxedOutNotesFlag) {
remainingNoteValue += nValue;
}
}
for (const SaplingNoteEntry& entry : saplingEntries) {
noteCounter++;
CAmount nValue = entry.note.value();
if (!maxedOutNotesFlag) {
size_t increase = SPENDDESCRIPTION_SIZE;
if (estimatedTxSize + increase >= max_tx_size ||
(saplingNoteLimit > 0 && noteCounter > saplingNoteLimit))
{
maxedOutNotesFlag = true;
} else {
estimatedTxSize += increase;
libzcash::SaplingExtendedSpendingKey extsk;
if (!pwalletMain->GetSaplingExtendedSpendingKey(entry.address, extsk)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find spending key for payment address.");
}
saplingNoteInputs.emplace_back(entry.op, entry.note, nValue, extsk.expsk);
mergedNoteValue += nValue; mergedNoteValue += nValue;
} }
} }
@@ -4959,17 +5037,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
remainingNoteValue += nValue; remainingNoteValue += nValue;
} }
} }
// TODO: Add Sapling support
} }
#ifdef __LP64__
uint64_t numUtxos = utxoInputs.size(); //ca333
uint64_t numNotes = noteInputs.size();
#else
size_t numUtxos = utxoInputs.size(); size_t numUtxos = utxoInputs.size();
size_t numNotes = noteInputs.size(); size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size();
#endif
if (numUtxos < 2 && numNotes == 0) { if (numUtxos < 2 && numNotes == 0) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge."); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
@@ -4986,8 +5057,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
CAmount mergedValue = mergedUTXOValue + mergedNoteValue; CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
if (mergedValue < nFee) { if (mergedValue < nFee) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
strprintf("Insufficient funds, have %s, which is less than miners fee %s", strprintf("Insufficient funds, have %s, which is less than miners fee %s",
FormatMoney(mergedValue), FormatMoney(nFee))); FormatMoney(mergedValue), FormatMoney(nFee)));
} }
// Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee) // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
@@ -5004,17 +5075,22 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
// Contextual transaction we will build on // Contextual transaction we will build on
CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction( CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
Params().GetConsensus(), Params().GetConsensus(),
nextBlockHeight); nextBlockHeight);
bool isShielded = numNotes > 0 || isToZaddr; bool isSproutShielded = sproutNoteInputs.size() > 0 || isToSproutZaddr;
if (contextualTx.nVersion == 1 && isShielded) { if (contextualTx.nVersion == 1 && isSproutShielded) {
contextualTx.nVersion = 2; // Tx format should support vjoinsplit contextualTx.nVersion = 2; // Tx format should support vjoinsplit
} }
// Builder (used if Sapling addresses are involved)
boost::optional<TransactionBuilder> builder;
if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
}
// Create operation and add to global queue // Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue(); std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation( std::shared_ptr<AsyncRPCOperation> operation(
new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) ); new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
q->addOperation(operation); q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId(); AsyncRPCOperationId operationId = operation->getId();

View File

@@ -1304,6 +1304,7 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries,
{ {
CWalletTx* wtx = &((*it).second); CWalletTx* wtx = &((*it).second);
txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
//fprintf(stderr,"ordered iter.%d %s\n",(int32_t)wtx->nOrderPos,wtx->GetHash().GetHex().c_str());
} }
acentries.clear(); acentries.clear();
walletdb.ListAccountCreditDebit(strAccount, acentries); walletdb.ListAccountCreditDebit(strAccount, acentries);
@@ -2594,6 +2595,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
} }
// Sent/received. // Sent/received.
int32_t oneshot = 0;
for (unsigned int i = 0; i < vout.size(); ++i) for (unsigned int i = 0; i < vout.size(); ++i)
{ {
const CTxOut& txout = vout[i]; const CTxOut& txout = vout[i];
@@ -2605,11 +2607,19 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
{ {
// Don't report 'change' txouts // Don't report 'change' txouts
if (!(filter & ISMINE_CHANGE) && pwallet->IsChange(txout)) if (!(filter & ISMINE_CHANGE) && pwallet->IsChange(txout))
continue; {
if ( oneshot++ > 1 )
{
//fprintf(stderr,"skip change vout\n");
continue;
}
}
} }
else if (!(fIsMine & filter)) else if (!(fIsMine & filter))
{
//fprintf(stderr,"skip filtered vout %d %d\n",(int32_t)fIsMine,(int32_t)filter);
continue; continue;
}
// In either case, we need to get the destination address // In either case, we need to get the destination address
CTxDestination address; CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address)) if (!ExtractDestination(txout.scriptPubKey, address))
@@ -2623,10 +2633,12 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// If we are debited by the transaction, add the output as a "sent" entry // If we are debited by the transaction, add the output as a "sent" entry
if (nDebit > 0) if (nDebit > 0)
listSent.push_back(output); listSent.push_back(output);
//else fprintf(stderr,"not sent vout %d %d\n",(int32_t)fIsMine,(int32_t)filter);
// If we are receiving the output, add it as a "received" entry // If we are receiving the output, add it as a "received" entry
if (fIsMine & filter) if (fIsMine & filter)
listReceived.push_back(output); listReceived.push_back(output);
//else fprintf(stderr,"not received vout %d %d\n",(int32_t)fIsMine,(int32_t)filter);
} }
} }
@@ -3688,7 +3700,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING; max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
} }
/*
// Discourage fee sniping. // Discourage fee sniping.
// //
// However because of a off-by-one-error in previous versions we need to // However because of a off-by-one-error in previous versions we need to
@@ -3709,7 +3721,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD); assert(txNew.nLockTime < LOCKTIME_THRESHOLD);*/
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
@@ -5033,10 +5045,10 @@ void CWallet::GetFilteredNotes(
} }
// skip locked notes // skip locked notes
// TODO: Add locking for Sapling notes // TODO: Add locking for Sapling notes -> done
// if (ignoreLocked && IsLockedNote(op)) { if (ignoreLocked && IsLockedNote(op)) {
// continue; continue;
// } }
auto note = notePt.note(nd.ivk).get(); auto note = notePt.note(nd.ivk).get();
saplingEntries.push_back(SaplingNoteEntry { saplingEntries.push_back(SaplingNoteEntry {