diff --git a/Makefile.am b/Makefile.am index d3171b206..30be7500c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,7 @@ BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ $(top_srcdir)/contrib/devtools/security-check.py + WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ $(top_srcdir)/share/pixmaps/nsis-header.bmp \ $(top_srcdir)/share/pixmaps/nsis-wizard.bmp diff --git a/doc/beefy-node-reference-komodo.conf b/doc/beefy-node-reference-komodo.conf new file mode 100644 index 000000000..455f1ee3f --- /dev/null +++ b/doc/beefy-node-reference-komodo.conf @@ -0,0 +1,12 @@ +rpcuser=dontuseweakusernameoryougetrobbed +rpcpassword=dontuseweakpasswordoryougetrobbed +txindex=1 +server=1 +rpcworkqueue=64 +addnode=5.9.102.210 +addnode=78.47.196.146 +addnode=178.63.69.164 +addnode=88.198.65.74 +addnode=5.9.122.241 +addnode=144.76.94.38 +addnode=89.248.166.91 \ No newline at end of file diff --git a/migratecoin.md b/migratecoin.md deleted file mode 100644 index 7859bdff2..000000000 --- a/migratecoin.md +++ /dev/null @@ -1,61 +0,0 @@ -# MigrateCoin protocol - - - -## ExportCoins tx: - - - -``` - -vin: - - [ any ] - -vout: - - - amount: {burnAmount} - - script: OP_RETURN "send to ledger {id} {voutsHash}" - -``` - - - -* ExportCoin is a standard tx which burns coins in an OP_RETURN - - - -## ImportCoins tx: - - - -``` - -vin: - - - txid: 0000000000000000000000000000000000000000000000000000000000000000 - - idx: 0 - - script: CC_EVAL(EVAL_IMPORTCOINS, {momoProof},{exportCoin}) OP_CHECKCRYPTOCONDITION_UNILATERAL - -vout: - - - [ vouts matching voutsHash in exportCoin ] - -``` - - - -* ImportCoin transaction has no signature - -* ImportCoin is non malleable - -* ImportCoin satisfies tx.IsCoinBase() - -* ImportCoin uses a new opcode which allows a one sided check (no scriptPubKey) - -* ImportCoin must contain CC opcode EVAL_IMPORTCOINS - -* ImportCoin fees are equal to the difference between burnAmount in exportCoins and the sum of outputs. diff --git a/migratecoin.sh b/migratecoin.sh new file mode 100644 index 000000000..6cd09ba04 --- /dev/null +++ b/migratecoin.sh @@ -0,0 +1,43 @@ +#!/usr/bin/bash + +# This script makes the neccesary transactions to migrate +# coin between 2 assetchains on the same -ac_cc id + +set -e + +source=TXSCL +target=TXSCL000 +address="RFw7byY4xZpZCrtkMk3nFuuG1NTs9rSGgQ" +amount=1 + +# Alias for running cli on source chain +cli_source="komodo-cli -ac_name=$source" + +# Raw tx that we will work with +txraw=`$cli_source createrawtransaction "[]" "{\"$address\":$amount}"` + +# Convert to an export tx +exportData=`$cli_source migrate_converttoexport $txraw $target $amount` +exportRaw=`echo $exportData | jq -r .exportTx` +exportPayouts=`echo $exportData | jq -r .payouts` + +# Fund +exportFundedData=`$cli_source fundrawtransaction $exportRaw` +exportFundedTx=`echo $exportFundedData | jq -r .hex` + +# Sign +exportSignedData=`$cli_source signrawtransaction $exportFundedTx` +exportSignedTx=`echo $exportSignedData | jq -r .hex` + +# Send +echo "Sending export tx" +$cli_source sendrawtransaction $exportSignedTx + +read -p "Wait for a notarisation to KMD, and then two more notarisations from the target chain, and then press enter to continue" + +# Create import +importTx=`$cli_source migrate_createimporttransaction $exportSignedTx $payouts` +importTx=`komodo-cli migrate_completeimporttransaction $importTx` + +# Send import +komodo-cli -ac_name=$target sendrawtransaction $importTx diff --git a/qa/rpc-tests/cryptoconditions.py b/qa/rpc-tests/cryptoconditions.py index f133ae28a..e7d3065cc 100755 --- a/qa/rpc-tests/cryptoconditions.py +++ b/qa/rpc-tests/cryptoconditions.py @@ -78,6 +78,12 @@ class CryptoConditionsTest (BitcoinTestFramework): for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress']: assert_equal(faucet[x][0], 'R') + result = rpc.faucetaddress(self.pubkey) + assert_success(result) + # test that additional CCaddress key is returned + for x in ['myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress', 'CCaddress']: + assert_equal(result[x][0], 'R') + # no funds in the faucet yet result = rpc.faucetget() assert_error(result) @@ -134,12 +140,145 @@ class CryptoConditionsTest (BitcoinTestFramework): for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress']: assert_equal(dice[x][0], 'R') + dice = rpc.diceaddress(self.pubkey) + assert_equal(dice['result'], 'success') + for x in ['myCCaddress', 'DiceCCaddress', 'Dicemarker', 'myaddress', 'CCaddress']: + assert_equal(dice[x][0], 'R') + # no dice created yet result = rpc.dicelist() assert_equal(result, []) - #result = rpc.dicefund("LUCKY",10000,1,10000,10,5) - #assert_equal(result, []) + # creating dice plan with too long name (>8 chars) + result = rpc.dicefund("THISISTOOLONG", "10000", "10", "10000", "10", "5") + assert_error(result) + + # creating dice plan with < 100 funding + result = rpc.dicefund("LUCKY","10","1","10000","10","5") + assert_error(result) + + # creating dice plan with 0 blocks timeout + result = rpc.dicefund("LUCKY","10","1","10000","10","0") + assert_error(result) + + # creating dice plan + dicefundtx = rpc.dicefund("LUCKY","1000","1","800","10","5") + diceid = self.send_and_mine(dicefundtx['hex']) + + # checking if it in plans list now + result = rpc.dicelist() + assert_equal(result[0], diceid) + + # set dice name for futher usage + dicename = "LUCKY" + + # adding zero funds to plan + result = rpc.diceaddfunds(dicename,diceid,"0") + assert_error(result) + + # adding negative funds to plan + result = rpc.diceaddfunds(dicename,diceid,"-1") + assert_error(result) + + # adding funds to plan + addfundstx = rpc.diceaddfunds(dicename,diceid,"1100") + result = self.send_and_mine(addfundstx['hex']) + + # checking if funds added to plan + result = rpc.diceinfo(diceid) + assert_equal(result["funding"], "2100.00000000") + + # not valid dice info checking + result = rpc.diceinfo("invalid") + assert_error(result) + + # placing 0 amount bet + result = rpc.dicebet(dicename,diceid,"0","1") + assert_error(result) + + # placing negative amount bet + result = rpc.dicebet(dicename,diceid,"-1","1") + assert_error(result) + + # placing bet more than maxbet + result = rpc.dicebet(dicename,diceid,"900","1") + assert_error(result) + + # placing bet with amount more than funding + result = rpc.dicebet(dicename,diceid,"3000","1") + assert_error(result) + + # placing bet with potential won more than funding + result = rpc.dicebet(dicename,diceid,"750","9") + assert_error(result) + + # placing 0 odds bet + result = rpc.dicebet(dicename,diceid,"1","0") + assert_error(result) + + # placing negative odds bet + result = rpc.dicebet(dicename,diceid,"1","-1") + assert_error(result) + + # placing bet with odds more than allowed + result = rpc.dicebet(dicename,diceid,"1","11") + assert_error(result) + + # placing bet with not correct dice name + result = rpc.dicebet("nope",diceid,"100","1") + assert_error(result) + + # placing bet with not correct dice id + result = rpc.dicebet(dicename,self.pubkey,"100","1") + assert_error(result) + + # valid bet placing + placebet = rpc.dicebet(dicename,diceid,"100","1") + betid = self.send_and_mine(placebet["hex"]) + assert result, "bet placed" + + # check bet status + result = rpc.dicestatus(dicename,diceid,betid) + assert_success(result) + + # have to make some entropy for the next test + entropytx = 0 + fundingsum = 1 + while entropytx < 10: + fundingsuminput = str(fundingsum) + fundinghex = rpc.diceaddfunds(dicename,diceid,fundingsuminput) + result = self.send_and_mine(fundinghex['hex']) + entropytx = entropytx + 1 + fundingsum = fundingsum + 1 + + rpc.generate(2) + + # note initial dice funding state at this point. + # TODO: track player balance somehow (hard to do because of mining and fees) + diceinfo = rpc.diceinfo(diceid) + funding = float(diceinfo['funding']) + + # placing same amount bets with amount 1 and odds 1:2, checking if balance changed correct + losscounter = 0 + wincounter = 0 + betcounter = 0 + + while (betcounter < 10): + placebet = rpc.dicebet(dicename,diceid,"1","1") + betid = self.send_and_mine(placebet["hex"]) + finish = rpc.dicefinish(dicename,diceid,betid) + self.send_and_mine(finish["hex"]) + betresult = rpc.dicestatus(dicename,diceid,betid) + betcounter = betcounter + 1 + if betresult["status"] == "loss": + losscounter = losscounter + 1 + elif betresult["status"] == "win": + wincounter = wincounter + 1 + + # funding balance should increase if player loss, decrease if player won + fundbalanceguess = funding + losscounter - wincounter + fundinfoactual = rpc.diceinfo(diceid) + assert_equal(round(fundbalanceguess),round(float(fundinfoactual['funding']))) def run_token_tests(self): rpc = self.nodes[0] @@ -156,8 +295,18 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.tokenlist() assert_equal(result, []) - result = rpc.tokencreate("DUKE", "1987.420", "duke") + # trying to create token with negaive supply + result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply") + assert_error(result) + + # creating token with name more than 32 chars + result = rpc.tokencreate("NUKE123456789012345678901234567890", "1987420", "name too long") + assert_error(result) + + # creating valid token + result = rpc.tokencreate("DUKE", "1987.420", "Duke's custom token") assert_success(result) + tokenid = self.send_and_mine(result['hex']) result = rpc.tokenlist() @@ -197,7 +346,7 @@ class CryptoConditionsTest (BitcoinTestFramework): assert_equal(result['owner'], self.pubkey) assert_equal(result['name'], "DUKE") assert_equal(result['supply'], 198742000000) - assert_equal(result['description'], "duke") + assert_equal(result['description'], "Duke's custom token") # invalid numtokens ask result = rpc.tokenask("-1", tokenid, "1") @@ -253,27 +402,26 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.tokenorders() assert_equal(result, []) - # invalid numtokens bid (have to add status to CC code!) + # invalid numtokens bid result = rpc.tokenbid("-1", tokenid, "1") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) - # invalid numtokens bid (have to add status to CC code!) + # invalid numtokens bid result = rpc.tokenbid("0", tokenid, "1") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) - # invalid price bid (have to add status to CC code!) + # invalid price bid result = rpc.tokenbid("1", tokenid, "-1") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) - # invalid price bid (have to add status to CC code!) + # invalid price bid result = rpc.tokenbid("1", tokenid, "0") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) - # invalid tokenid bid (have to add status to CC code!) + # invalid tokenid bid result = rpc.tokenbid("100", "deadbeef", "1") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) - # valid bid tokenbid = rpc.tokenbid("100", tokenid, "10") tokenbidhex = tokenbid['hex'] tokenbidid = self.send_and_mine(tokenbid['hex']) @@ -310,11 +458,11 @@ class CryptoConditionsTest (BitcoinTestFramework): # invalid token transfer amount (have to add status to CC code!) randompubkey = "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96" result = rpc.tokentransfer(tokenid,randompubkey,"0") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) # invalid token transfer amount (have to add status to CC code!) result = rpc.tokentransfer(tokenid,randompubkey,"-1") - assert_equal(result['error'], 'invalid parameter') + assert_error(result) # valid token transfer sendtokens = rpc.tokentransfer(tokenid,randompubkey,"1") @@ -341,14 +489,31 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.rewardsinfo("none") assert_error(result) + # creating rewards plan with name > 8 chars, should return error + result = rpc.rewardscreatefunding("STUFFSTUFF", "7777", "25", "0", "10", "10") + assert_error(result) + + # creating rewards plan with 0 funding + result = rpc.rewardscreatefunding("STUFF", "0", "25", "0", "10", "10") + assert_error(result) + + # creating rewards plan with 0 maxdays + result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "0") + assert_error(result) + + # creating rewards plan with > 25% APR + result = rpc.rewardscreatefunding("STUFF", "7777", "30", "0", "10", "10") + assert_error(result) + + # creating valid rewards plan result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10") assert result['hex'], 'got raw xtn' - txid = rpc.sendrawtransaction(result['hex']) - assert txid, 'got txid' + fundingtxid = rpc.sendrawtransaction(result['hex']) + assert fundingtxid, 'got txid' # confirm the above xtn rpc.generate(1) - result = rpc.rewardsinfo(txid) + result = rpc.rewardsinfo(fundingtxid) assert_success(result) assert_equal(result['name'], 'STUFF') assert_equal(result['APR'], "25.00000000") @@ -356,39 +521,38 @@ class CryptoConditionsTest (BitcoinTestFramework): assert_equal(result['maxseconds'], 864000) assert_equal(result['funding'], "7777.00000000") assert_equal(result['mindeposit'], "10.00000000") - assert_equal(result['fundingtxid'], txid) + assert_equal(result['fundingtxid'], fundingtxid) - # funding amount must be positive - result = rpc.rewardsaddfunding("STUFF", txid, "0") + # checking if new plan in rewardslist + result = rpc.rewardslist() + assert_equal(result[0], fundingtxid) + + # creating reward plan with already existing name, should return error + result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10") assert_error(result) - result = rpc.rewardsaddfunding("STUFF", txid, "555") - assert_success(result) - fundingtxid = result['hex'] - assert fundingtxid, "got funding txid" - - result = rpc.rewardslock("STUFF", fundingtxid, "7") + # add funding amount must be positive + result = rpc.rewardsaddfunding("STUFF", fundingtxid, "-1") assert_error(result) - # the previous xtn has not been broadcasted yet - result = rpc.rewardsunlock("STUFF", fundingtxid) + # add funding amount must be positive + result = rpc.rewardsaddfunding("STUFF", fundingtxid, "0") assert_error(result) - # wrong plan name - result = rpc.rewardsunlock("SHTUFF", fundingtxid) - assert_error(result) + # adding valid funding + result = rpc.rewardsaddfunding("STUFF", fundingtxid, "555") + addfundingtxid = self.send_and_mine(result['hex']) + assert addfundingtxid, 'got funding txid' - txid = rpc.sendrawtransaction(fundingtxid) - assert txid, 'got txid from sendrawtransaction' + # checking if funding added to rewardsplan + result = rpc.rewardsinfo(fundingtxid) + assert_equal(result['funding'], "8332.00000000") - # confirm the xtn above - rpc.generate(1) - - # amount must be positive + # trying to lock funds, locking funds amount must be positive result = rpc.rewardslock("STUFF", fundingtxid, "-5") assert_error(result) - # amount must be positive + # trying to lock funds, locking funds amount must be positive result = rpc.rewardslock("STUFF", fundingtxid, "0") assert_error(result) @@ -396,25 +560,26 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.rewardslock("STUFF", fundingtxid, "7") assert_error(result) - # not working - #result = rpc.rewardslock("STUFF", fundingtxid, "10") - #assert_success(result) - #locktxid = result['hex'] - #assert locktxid, "got lock txid" + # locking funds in rewards plan + result = rpc.rewardslock("STUFF", fundingtxid, "10") + assert_success(result) + locktxid = result['hex'] + assert locktxid, "got lock txid" # locktxid has not been broadcast yet - #result = rpc.rewardsunlock("STUFF", locktxid) - #assert_error(result) + result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid) + assert_error(result) # broadcast xtn - #txid = rpc.sendrawtransaction(locktxid) - #assert txid, 'got txid from sendrawtransaction' + txid = rpc.sendrawtransaction(locktxid) + assert txid, 'got txid from sendrawtransaction' # confirm the xtn above - #rpc.generate(1) + rpc.generate(1) - #result = rpc.rewardsunlock("STUFF", locktxid) - #assert_error(result) + # will not unlock since reward amount is less than tx fee + result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid) + assert_error(result) def run_test (self): @@ -429,6 +594,7 @@ class CryptoConditionsTest (BitcoinTestFramework): print("Importing privkey") rpc.importprivkey(self.privkey) +# self.run_faucet_tests() self.run_rewards_tests() self.run_dice_tests() self.run_token_tests() diff --git a/src/assetchains.json b/src/assetchains.json index b74d953a0..ceda4cce1 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -45,7 +45,8 @@ }, { "ac_name": "COQUI", - "ac_supply": "72000000" + "ac_supply": "72000000", + "ac_ccactivate": "200000" }, { "ac_name": "WLC", @@ -140,7 +141,9 @@ "ac_cc": "2", "addressindex": "1", "spentindex": "1", - "addnode": "142.93.136.89", - "addnode": "195.201.22.89" + "addnode": [ + "142.93.136.89", + "195.201.22.89" + ] } ] diff --git a/src/assetchains.old b/src/assetchains.old index d7a18811d..158e62cad 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -15,7 +15,7 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=MSHARK -ac_supply=1400000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=BOTS -ac_supply=999999 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=MGW -ac_supply=999999 -addnode=78.47.196.146 $1 & -./komodod -pubkey=$pubkey -ac_name=COQUI -ac_supply=72000000 -addnode=78.47.196.146 $1 & +./komodod -pubkey=$pubkey -ac_name=COQUI -ac_supply=72000000 -ac_ccactivate=200000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=WLC -ac_supply=210000000 -addnode=148.251.190.89 $1 & ./komodod -pubkey=$pubkey -ac_name=KV -ac_supply=1000000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=CEAL -ac_supply=366666666 -addnode=78.47.196.146 $1 & diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index a57197537..3c38d04b3 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -259,14 +259,14 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector param height = KOMODO_CONNECTING; if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation return(true); - if ( ASSETCHAINS_CC == 0 || height < KOMODO_CCACTIVATE ) + if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE ) return eval->Invalid("CC are disabled or not active yet"); if ( (KOMODO_CONNECTING & (1<<30)) != 0 ) { from_mempool = 1; height &= ((1<<30) - 1); } - fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d\n",height,from_mempool); + fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE); // there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example //txid = ctx.GetHash(); //if ( txid == cp->prevtxid ) diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp new file mode 100644 index 000000000..610342274 --- /dev/null +++ b/src/cc/disputepayout.cpp @@ -0,0 +1,84 @@ +#include + +#include "hash.h" +#include "chain.h" +#include "version.h" +#include "script/cc.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" + + +/* + * Crypto-Condition EVAL method that resolves a dispute of a session + * + * IN: vm - AppVM virtual machine to verify states + * IN: params - condition params + * IN: disputeTx - transaction attempting to resolve dispute + * IN: nIn - index of input of dispute tx + * + * disputeTx: attempt to resolve a dispute + * + * in 0: Spends Session TX first output, reveals DisputeHeader + * out 0: OP_RETURN hash of payouts + */ +bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransaction &disputeTx, unsigned int nIn) +{ + if (disputeTx.vout.size() == 0) return Invalid("no-vouts"); + + // get payouts hash + uint256 payoutHash; + if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash)) + return Invalid("invalid-payout-hash"); + + // load params + uint16_t waitBlocks; + std::vector vmParams; + if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams)) + return Invalid("malformed-params"); + + // ensure that enough time has passed + { + CTransaction sessionTx; + CBlockIndex sessionBlock; + + // if unconformed its too soon + if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) + return Error("couldnt-get-parent"); + + if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks) + return Invalid("dispute-too-soon"); // Not yet + } + + // get spends + std::vector spends; + if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends)) + return Error("couldnt-get-spends"); + + // verify result from VM + int maxLength = -1; + uint256 bestPayout; + for (int i=1; i vmState; + if (spends[i].vout.size() == 0) continue; + if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue; + auto out = vm.evaluate(vmParams, vmState); + uint256 resultHash = SerializeHash(out.second); + if (out.first > maxLength) { + maxLength = out.first; + bestPayout = resultHash; + } + // The below means that if for any reason there is a draw, the first dispute wins + else if (out.first == maxLength) { + if (bestPayout != payoutHash) { + fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); + bestPayout = resultHash; + } + } + } + + if (maxLength == -1) return Invalid("no-evidence"); + + return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout"); +} diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 99418f711..ffc94ac43 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -59,7 +59,7 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp // check burn amount { - uint64_t burnAmount = burnTx.vout[0].nValue; + uint64_t burnAmount = burnTx.vout.back().nValue; if (burnAmount == 0) return Invalid("invalid-burn-amount"); uint64_t totalOut = 0; diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp new file mode 100644 index 000000000..1363eb924 --- /dev/null +++ b/src/cc/importpayout.cpp @@ -0,0 +1,76 @@ +#include + +#include "main.h" +#include "chain.h" +#include "streams.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" + + +/* + * Crypto-Condition EVAL method that verifies a payout against a transaction + * notarised on another chain. + * + * IN: params - condition params + * IN: importTx - Payout transaction on value chain (KMD) + * IN: nIn - index of input of stake + * + * importTx: Spends stakeTx with payouts from asset chain + * + * in 0: Spends Stake TX and contains ImportPayout CC + * out 0: OP_RETURN MomProof, disputeTx + * out 1-: arbitrary payouts + * + * disputeTx: Spends sessionTx.0 (opener on asset chain) + * + * in 0: spends sessionTx.0 + * in 1-: anything + * out 0: OP_RETURN hash of payouts + * out 1-: anything + */ +bool Eval::ImportPayout(const std::vector params, const CTransaction &importTx, unsigned int nIn) +{ + if (importTx.vout.size() == 0) return Invalid("no-vouts"); + + // load data from vout[0] + MoMProof proof; + CTransaction disputeTx; + { + std::vector vopret; + GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); + if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx)) + return Invalid("invalid-payload"); + } + + // Check disputeTx.0 shows correct payouts + { + uint256 givenPayoutsHash; + GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash); + std::vector payouts(importTx.vout.begin() + 1, importTx.vout.end()); + if (givenPayoutsHash != SerializeHash(payouts)) + return Invalid("wrong-payouts"); + } + + // Check disputeTx spends sessionTx.0 + // condition ImportPayout params is session ID from other chain + { + uint256 sessionHash; + if (!E_UNMARSHAL(params, ss >> sessionHash)) + return Invalid("malformed-params"); + if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0)) + return Invalid("wrong-session"); + } + + // Check disputeTx solves momproof from vout[0] + { + NotarisationData data; + if (!GetNotarisationData(proof.notarisationHash, data)) + return Invalid("coudnt-load-mom"); + + if (data.MoM != proof.Exec(disputeTx.GetHash())) + return Invalid("mom-check-fail"); + } + + return Valid(); +} diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index d3d374613..8d9a9fa78 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -196,7 +196,7 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - uint256 txid,fundingtxid,hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; + uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -244,8 +244,16 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t //vout.0: funding CC change or recover normal payout //vout.1: normal output to unlock address //vout.n-1: opreturn 'U' sbits fundingtxid - if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) + //char str[65],str2[65]; + //fprintf(stderr,"funding.%s vs %s\n",uint256_str(str,fundingtxid),uint256_str(str2,tx.vin[0].prevout.hash)); + if ( fundingtxid == tx.vin[0].prevout.hash ) + return eval->Invalid("cant unlock fundingtxid"); + else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) return eval->Invalid("always should find vin.0, but didnt"); + else if ( DecodeRewardsOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid) != 'L' ) + return eval->Invalid("can only unlock locktxid"); + else if ( fundingtxid != vinfundingtxid ) + return eval->Invalid("mismatched vinfundingtxid"); for (i=0; iismyvin)(tx.vin[i].scriptSig) == 0 ) @@ -609,6 +617,12 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2 rewardspk = GetUnspendable(cp,0); mypk = pubkey2pk(Mypubkey()); sbits = stringbits(planstr); + if ( locktxid == fundingtxid ) + { + fprintf(stderr,"Rewards plan cant unlock fundingtxid\n"); + CCerror = "Rewards plan cant unlock fundingtxid"; + return(""); + } if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 ) { fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr); diff --git a/src/crosschain.cpp b/src/crosschain.cpp index 197390e59..831c7bcae 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -50,6 +50,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh int seenOwnNotarisations = 0; + bool txscl = IsTXSCL(symbol); + for (int i=0; i kmdHeight) break; NotarisationsInBlock notarisations; @@ -72,8 +74,9 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh if (seenOwnNotarisations == 1) { BOOST_FOREACH(Notarisation& nota, notarisations) { - if (nota.second.ccId == targetCCid) - moms.push_back(nota.second.MoM); + if (IsTXSCL(nota.second.symbol) == txscl) + if (nota.second.ccId == targetCCid) + moms.push_back(nota.second.MoM); } } } diff --git a/src/fiat/vote2018 b/src/fiat/vote2018 new file mode 100755 index 000000000..4e385d76f --- /dev/null +++ b/src/fiat/vote2018 @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=VOTE2018 $1 $2 $3 $4 $5 $6 diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 8b87cb535..d36943b5d 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -45,7 +45,7 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint { std::vector burnOpret; if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret); + GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); ss >> targetSymbol; ss >> payoutsHash); @@ -61,7 +61,7 @@ CAmount GetCoinImportValue(const CTransaction &tx) CTransaction burnTx; std::vector payouts; if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { - return burnTx.vout.size() ? burnTx.vout[0].nValue : 0; + return burnTx.vout.size() ? burnTx.vout.back().nValue : 0; } return 0; } diff --git a/src/komodo.h b/src/komodo.h index dff8b5ab6..4b61cafa0 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -311,7 +311,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long { if ( memread(opret,olen,filedata,&fpos,datalen) != olen ) errs++; - if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && matched != 0 ) + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && matched != 0 ) { int32_t i; for (i=0; iflags); - fprintf(stderr,"duration.%d flags.%d current.%d ht.%d keylen.%d valuesize.%d\n",duration,ptr->flags,current_height,ptr->height,ptr->keylen,ptr->valuesize); + //fprintf(stderr,"duration.%d flags.%d current.%d ht.%d keylen.%d valuesize.%d\n",duration,ptr->flags,current_height,ptr->height,ptr->keylen,ptr->valuesize); if ( current_height > (ptr->height + duration) ) { HASH_DELETE(hh,KOMODO_KV,ptr); @@ -117,7 +117,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) } valueptr = &key[keylen]; fee = komodo_kvfee(flags,opretlen,keylen); - printf("fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]); + //printf("fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]); if ( value >= fee ) { coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(keylen)+sizeof(valuesize)+keylen+valuesize+1); @@ -142,7 +142,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) { if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 ) { - fprintf(stderr,"komodo_kvsigverify error [%d]\n",coresize-13); + //fprintf(stderr,"komodo_kvsigverify error [%d]\n",coresize-13); return; } } @@ -151,7 +151,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) HASH_FIND(hh,KOMODO_KV,key,keylen,ptr); if ( ptr != 0 ) { - fprintf(stderr,"(%s) already there\n",(char *)key); + //fprintf(stderr,"(%s) already there\n",(char *)key); //if ( (ptr->flags & KOMODO_KVPROTECTED) != 0 ) { tstr = (char *)"transfer:"; diff --git a/src/main.cpp b/src/main.cpp index aa6bece16..21c803754 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -736,7 +736,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) if (!::IsStandard(txout.scriptPubKey, whichType)) { reason = "scriptpubkey"; - fprintf(stderr,">>>>>>>>>>>>>>> vout.%d nDataout.%d\n",v,nDataOut); + //fprintf(stderr,">>>>>>>>>>>>>>> vout.%d nDataout.%d\n",v,nDataOut); return false; } @@ -1306,7 +1306,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa string reason; if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight)) { - fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\n",reason.c_str()); + //fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\n",reason.c_str()); return state.DoS(0,error("AcceptToMemoryPool: nonstandard transaction: %s", reason),REJECT_NONSTANDARD, reason); } // Only accept nLockTime-using transactions that can be mined in the next @@ -1541,20 +1541,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } if ( flag != 0 ) KOMODO_CONNECTING = -1; - + // Store transaction in memory if ( komodo_is_notarytx(tx) == 0 ) KOMODO_ON_DEMAND++; pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); - // Add memory address index - if (fAddressIndex) { - pool.addAddressIndex(entry, view); - } + if (!tx.IsCoinImport()) + { + // Add memory address index + if (fAddressIndex) { + pool.addAddressIndex(entry, view); + } - // Add memory spent index - if (fSpentIndex) { - pool.addSpentIndex(entry, view); + // Add memory spent index + if (fSpentIndex) { + pool.addSpentIndex(entry, view); + } } } @@ -3367,6 +3370,15 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { CBlock block; if (!ReadBlockFromDisk(block, pindexDelete,1)) return AbortNode(state, "Failed to read block"); + { + int32_t prevMoMheight; uint256 notarizedhash,txid; + komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); + if ( block.GetHash() == notarizedhash ) + { + fprintf(stderr,"DisconnectTip trying to disconnect notarized block at ht.%d\n",(int32_t)pindexDelete->nHeight); + return(false); + } + } // Apply the block atomically to the chain state. uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor(); int64_t nStart = GetTimeMicros(); @@ -4187,11 +4199,11 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C } if ( rejects == 0 || rejects == lastrejects ) { - if ( lastrejects != 0 ) + if ( 0 && lastrejects != 0 ) fprintf(stderr,"lastrejects.%d -> all tx in mempool\n",lastrejects); break; } - fprintf(stderr,"addtomempool ht.%d for CC checking: n.%d rejects.%d last.%d\n",height,(int32_t)block.vtx.size(),rejects,lastrejects); + //fprintf(stderr,"addtomempool ht.%d for CC checking: n.%d rejects.%d last.%d\n",height,(int32_t)block.vtx.size(),rejects,lastrejects); lastrejects = rejects; rejects = 0; } diff --git a/src/notarisationdb.cpp b/src/notarisationdb.cpp index 6210d88dd..de3dd75f2 100644 --- a/src/notarisationdb.cpp +++ b/src/notarisationdb.cpp @@ -2,6 +2,7 @@ #include "notarisationdb.h" #include "uint256.h" #include "cc/eval.h" +#include "main.h" #include @@ -25,7 +26,7 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight) { NotarisationData data; if (ParseNotarisationOpReturn(tx, data)) - if (strlen(data.symbol) >= 5 && strncmp(data.symbol, "TXSCL", 5) == 0) + if (IsTXSCL(data.symbol)) isTxscl = 1; } @@ -45,6 +46,11 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight) return vNotarisations; } +bool IsTXSCL(const char* symbol) +{ + return strlen(symbol) >= 5 && strncmp(symbol, "TXSCL", 5) == 0; +} + bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs) { @@ -82,3 +88,29 @@ void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBa batch.Erase(n.second.txHash); } } + +/* + * Scan notarisationsdb backwards for blocks containing a notarisation + * for given symbol. Return height of matched notarisation or 0. + */ +int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out) +{ + if (height < 0 || height > chainActive.Height()) + return false; + + for (int i=0; i height) break; + NotarisationsInBlock notarisations; + uint256 blockHash = *chainActive[height-i]->phashBlock; + if (!GetBlockNotarisations(blockHash, notarisations)) + continue; + + BOOST_FOREACH(Notarisation& nota, notarisations) { + if (strcmp(nota.second.symbol, symbol.data()) == 0) { + out = nota; + return height-i; + } + } + } + return 0; +} diff --git a/src/notarisationdb.h b/src/notarisationdb.h index ce5360e7d..f01a5a587 100644 --- a/src/notarisationdb.h +++ b/src/notarisationdb.h @@ -23,5 +23,7 @@ bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs); bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n); void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); +int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out); +bool IsTXSCL(const char* symbol); #endif /* NOTARISATIONDB_H */ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 7f01c862f..fce949c4a 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -31,6 +31,7 @@ using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); +int32_t komodo_longestchain(); double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty) { @@ -819,7 +820,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp) "}\n" "\nExamples:\n" + HelpExampleCli("kvsearch", "examplekey") - + HelpExampleRpc("kvsearch", "examplekey") + + HelpExampleRpc("kvsearch", "\"examplekey\"") ); LOCK(cs_main); if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 ) @@ -1297,14 +1298,20 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) ); LOCK(cs_main); - + double progress; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { + progress = Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip()); + } else { + int32_t longestchain = komodo_longestchain(); + progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0; + } UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); - obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip()))); + obj.push_back(Pair("verificationprogress", progress)); obj.push_back(Pair("chainwork", chainActive.LastTip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); diff --git a/src/rpccrosschain.cpp b/src/rpccrosschain.cpp index ea8e13aee..09f1b21d1 100644 --- a/src/rpccrosschain.cpp +++ b/src/rpccrosschain.cpp @@ -3,6 +3,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "crosschain.h" +#include "notarisationdb.h" #include "importcoin.h" #include "base58.h" #include "consensus/validation.h" @@ -251,3 +252,55 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) return HexStr(E_MARSHAL(ss << importTx)); } + + +UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error("getNotarisationsForBlock blockHash\n\n" + "Takes a block hash and returns notarisation transactions " + "within the block"); + + uint256 blockHash = uint256S(params[0].get_str()); + + NotarisationsInBlock nibs; + GetBlockNotarisations(blockHash, nibs); + UniValue out(UniValue::VARR); + BOOST_FOREACH(const Notarisation& n, nibs) + { + UniValue item(UniValue::VARR); + item.push_back(n.first.GetHex()); + item.push_back(HexStr(E_MARSHAL(ss << n.second))); + out.push_back(item); + } + return out; +} + + +UniValue scanNotarisationsDB(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error("scanNotarisationsDB blockHeight symbol [blocksLimit=1440]\n\n" + "Scans notarisationsdb backwards from height for a notarisation" + " of given symbol"); + int height = atoi(params[0].get_str().c_str()); + std::string symbol = params[1].get_str().c_str(); + + int limit = 1440; + if (params.size() > 2) { + limit = atoi(params[2].get_str().c_str()); + } + + if (height == 0) { + height = chainActive.Height(); + } + + Notarisation nota; + int matchedHeight = ScanNotarisationsDB(height, symbol, limit, nota); + if (!matchedHeight) return NullUniValue; + UniValue out(UniValue::VOBJ); + out.pushKV("height", matchedHeight); + out.pushKV("hash", nota.first.GetHex()); + out.pushKV("opreturn", HexStr(E_MARSHAL(ss << nota.second))); + return out; +} diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index df58a5573..0a2b56ca9 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -915,7 +915,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp) "}\n" "\nExamples:\n" + HelpExampleCli("getblocksubsidy", "1000") - + HelpExampleRpc("getblockubsidy", "1000") + + HelpExampleRpc("getblocksubsidy", "1000") ); LOCK(cs_main); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index cd99d531d..a42afbb61 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -55,7 +55,7 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t komodo_segid32(char *coinaddr); int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); -#define KOMODO_VERSION "0.2.0" +#define KOMODO_VERSION "0.2.1" extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint32_t ASSETCHAINS_CC; extern uint32_t ASSETCHAINS_MAGIC; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 41228e71a..0cac14c8b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -303,6 +303,8 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "paxpending", &paxpending, true }, { "blockchain", "paxprices", &paxprices, true }, { "blockchain", "notaries", ¬aries, true }, + //{ "blockchain", "height_MoM", &height_MoM, true }, + //{ "blockchain", "txMoMproof", &txMoMproof, true }, { "blockchain", "minerids", &minerids, true }, { "blockchain", "kvsearch", &kvsearch, true }, { "blockchain", "kvupdate", &kvupdate, true }, @@ -313,6 +315,8 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "height_MoM", &height_MoM, true }, { "crosschain", "assetchainproof", &assetchainproof, true }, { "crosschain", "crosschainproof", &crosschainproof, true }, + { "crosschain", "getNotarisationsForBlock", &getNotarisationsForBlock, true }, + { "crosschain", "scanNotarisationsDB", &scanNotarisationsDB, true }, { "crosschain", "migrate_converttoexport", &migrate_converttoexport, true }, { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index f88f1e571..336595156 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -361,6 +361,8 @@ extern UniValue calc_MoM(const UniValue& params, bool fHelp); extern UniValue height_MoM(const UniValue& params, bool fHelp); extern UniValue assetchainproof(const UniValue& params, bool fHelp); extern UniValue crosschainproof(const UniValue& params, bool fHelp); +extern UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp); +extern UniValue scanNotarisationsDB(const UniValue& params, bool fHelp); extern UniValue migrate_converttoexport(const UniValue& params, bool fHelp); extern UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp); extern UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b86dfef15..58d2bc701 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -167,7 +167,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector nMaxDatacarrierBytes) { - fprintf(stderr,"size.%d > nMaxDatacarrier.%d\n",(int32_t)vch1.size(),(int32_t)nMaxDatacarrierBytes); + //fprintf(stderr,"size.%d > nMaxDatacarrier.%d\n",(int32_t)vch1.size(),(int32_t)nMaxDatacarrierBytes); break; } } diff --git a/src/test-komodo/test_coinimport.cpp b/src/test-komodo/test_coinimport.cpp index eac21428a..8c1d8b0f8 100644 --- a/src/test-komodo/test_coinimport.cpp +++ b/src/test-komodo/test_coinimport.cpp @@ -180,7 +180,7 @@ TEST_F(TestCoinImport, testInvalidBurnOutputs) TEST_F(TestCoinImport, testInvalidBurnParams) { - burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid)); + burnTx.vout.back().scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid)); MoMoM = burnTx.GetHash(); // TODO: an actual branch CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); TestRunCCEval(tx); @@ -198,7 +198,7 @@ TEST_F(TestCoinImport, testWrongChainId) TEST_F(TestCoinImport, testInvalidBurnAmount) { - burnTx.vout[0].nValue = 0; + burnTx.vout.back().nValue = 0; MoMoM = burnTx.GetHash(); // TODO: an actual branch CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); TestRunCCEval(tx); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1012a0205..6765d94b2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -55,6 +55,9 @@ std::string CCerror; // Private method: UniValue z_getoperationstatus_IMPL(const UniValue&, bool); +#define PLAN_NAME_MAX 8 +#define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX) + std::string HelpRequiringPassphrase() { return pwalletMain && pwalletMain->IsCrypted() @@ -539,7 +542,7 @@ UniValue kvupdate(const UniValue& params, bool fHelp) "}\n" "\nExamples:\n" + HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase") - + HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase") + + HelpExampleRpc("kvupdate", "\"examplekey\",\"examplevalue\",\"2\",\"examplepassphrase\"") ); if (!EnsureWalletIsAvailable(fHelp)) return 0; @@ -1249,13 +1252,13 @@ UniValue sendmany(const UniValue& params, bool fHelp) " the number of addresses.\n" "\nExamples:\n" "\nSend two amounts to two different addresses:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") + + + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\"") + "\nSend two amounts to two different addresses setting the confirmation and comment:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") + + + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\" 6 \"testing\"") + "\nSend two amounts to two different addresses, subtract fee from amount:\n" - + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") + + + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\":0.01,\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\\\",\\\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\\\"]\"") + "\nAs a json rpc call\n" - + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"") + + HelpExampleRpc("sendmany", "\"\", {\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY\":0.01,\"RRyyejME7LRTuvdziWsXkAbSW1fdiohGwK\":0.02}, 6, \"testing\"") ); if ( ASSETCHAINS_PRIVATE != 0 ) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); @@ -4982,6 +4985,11 @@ UniValue rewardscreatefunding(const UniValue& params, bool fHelp) name = (char *)params[0].get_str().c_str(); funds = atof(params[1].get_str().c_str()) * COIN; + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } + if ( funds <= 0 ) { ERR_RESULT("funds must be positive"); return result; @@ -5043,6 +5051,11 @@ UniValue rewardslock(const UniValue& params, bool fHelp) fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; hex = RewardsLock(0,name,fundingtxid,amount); + + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } if ( CCerror != "" ){ ERR_RESULT(CCerror); } else if ( amount > 0 ) { @@ -5068,6 +5081,11 @@ UniValue rewardsaddfunding(const UniValue& params, bool fHelp) fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; hex = RewardsAddfunding(0,name,fundingtxid,amount); + + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } if (CCerror != "") { ERR_RESULT(CCerror); } else if (amount > 0) { @@ -5096,6 +5114,11 @@ UniValue rewardsunlock(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); + + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } if ( params.size() > 2 ) txid = Parseuint256((char *)params[2].get_str().c_str()); else memset(&txid,0,sizeof(txid)); @@ -5234,6 +5257,12 @@ UniValue dicefund(const UniValue& params, bool fHelp) maxbet = atof(params[3].get_str().c_str()) * COIN; maxodds = atol(params[4].get_str().c_str()); timeoutblocks = atol(params[5].get_str().c_str()); + + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } + hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,timeoutblocks); if (CCerror != "") { ERR_RESULT(CCerror); @@ -5258,6 +5287,10 @@ UniValue diceaddfunds(const UniValue& params, bool fHelp) name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } if ( amount > 0 ) { hex = DiceAddfunding(0,name,fundingtxid,amount); if (CCerror != "") { @@ -5283,6 +5316,11 @@ UniValue dicebet(const UniValue& params, bool fHelp) fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; odds = atol(params[3].get_str().c_str()); + + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } if (amount > 0 && odds > 0) { hex = DiceBet(0,name,fundingtxid,amount,odds); if ( hex.size() > 0 ) @@ -5306,6 +5344,10 @@ UniValue dicefinish(const UniValue& params, bool fHelp) const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); bettxid = Parseuint256((char *)params[2].get_str().c_str()); hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1); @@ -5330,6 +5372,10 @@ UniValue dicestatus(const UniValue& params, bool fHelp) const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); + if (!VALID_PLAN_NAME(name)) { + ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX)); + return(result); + } fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); memset(&bettxid,0,sizeof(bettxid)); if ( params.size() == 3 ) @@ -5453,9 +5499,14 @@ UniValue tokencreate(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); name = params[0].get_str(); supply = atof(params[1].get_str().c_str()) * COIN; - if ( name.size() == 0 || supply <= 0 ) + if ( name.size() == 0 || name.size() > 32) { - result.push_back(Pair("error", "invalid parameter")); + ERR_RESULT("Token name must not be empty and up to 32 characters"); + return(result); + } + if ( supply <= 0 ) + { + ERR_RESULT("Token supply must be positive"); return(result); } if ( params.size() == 3 ) @@ -5463,7 +5514,7 @@ UniValue tokencreate(const UniValue& params, bool fHelp) description = params[2].get_str(); if ( description.size() > 4096 ) { - result.push_back(Pair("error", "token description longer than 4096")); + ERR_RESULT("Token description must be <= 4096 characters"); return(result); } } @@ -5488,9 +5539,14 @@ UniValue tokentransfer(const UniValue& params, bool fHelp) tokenid = Parseuint256((char *)params[0].get_str().c_str()); std::vector pubkey(ParseHex(params[1].get_str().c_str())); amount = atol(params[2].get_str().c_str()); - if ( tokenid == zeroid || amount <= 0 ) + if ( tokenid == zeroid ) { - result.push_back(Pair("error", "invalid parameter")); + ERR_RESULT("invalid tokenid"); + return(result); + } + if ( amount <= 0 ) + { + ERR_RESULT("amount must be positive"); return(result); } hex = AssetTransfer(0,tokenid,pubkey,amount); @@ -5519,9 +5575,19 @@ UniValue tokenbid(const UniValue& params, bool fHelp) tokenid = Parseuint256((char *)params[1].get_str().c_str()); price = atof(params[2].get_str().c_str()); bidamount = (price * numtokens) * COIN + 0.0000000049999; - if ( tokenid == zeroid || tokenid == zeroid || price <= 0 || bidamount <= 0 ) + if ( price <= 0 ) { - result.push_back(Pair("error", "invalid parameter")); + ERR_RESULT("price must be positive"); + return(result); + } + if ( tokenid == zeroid ) + { + ERR_RESULT("invalid tokenid"); + return(result); + } + if ( bidamount <= 0 ) + { + ERR_RESULT("bid amount must be positive"); return(result); } hex = CreateBuyOffer(0,bidamount,tokenid,numtokens); @@ -5530,7 +5596,7 @@ UniValue tokenbid(const UniValue& params, bool fHelp) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); - } else result.push_back(Pair("error", "couldnt create bid")); + } else ERR_RESULT("couldnt create bid"); } else { ERR_RESULT("price and numtokens must be positive"); } diff --git a/zcutil/fetch-params.sh b/zcutil/fetch-params.sh index 10bade7cb..1e2fe8b81 100755 --- a/zcutil/fetch-params.sh +++ b/zcutil/fetch-params.sh @@ -2,7 +2,11 @@ set -eu -PARAMS_DIR="$HOME/.zcash-params" +if [[ "$OSTYPE" == "darwin"* ]]; then + PARAMS_DIR="$HOME/Library/Application Support/ZcashParams" +else + PARAMS_DIR="$HOME/.zcash-params" +fi SPROUT_PKEY_NAME='sprout-proving.key' SPROUT_VKEY_NAME='sprout-verifying.key'