diff --git a/qa/rpc-tests/cryptoconditions.py b/qa/rpc-tests/cryptoconditions.py index f133ae28a..fbf149780 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,146 @@ 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 +296,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 +347,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,25 +403,25 @@ 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") @@ -310,11 +460,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") diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 87d5b7672..059d70910 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -301,14 +301,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/dice.cpp b/src/cc/dice.cpp index 18daeb191..20524a84a 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -1151,7 +1151,7 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx } CCerror = "couldnt find bettx or spenttx %s\n",uint256_str(str,spenttxid); fprintf(stderr,"%s\n", CCerror.c_str()); - return(0.); + return(-1.); } else if ( scriptPubKey == fundingPubKey ) res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,1); diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 9a63e2187..23e947e52 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -194,7 +194,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; @@ -242,10 +242,20 @@ 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 +<<<<<<< HEAD if ( fundingtxid == txid ) +======= + //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 ) +>>>>>>> jl777 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 ) diff --git a/src/main.cpp b/src/main.cpp index 315b80d42..2f7e65a90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1546,7 +1546,7 @@ 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++; @@ -3427,7 +3427,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { for (int i = 0; i < block.vtx.size(); i++) { CTransaction &tx = block.vtx[i]; - if ( (i == (block.vtx.size() - 1)) && komodo_isPoS((CBlock *)&block) != 0 ) + if ( ASSETCHAINS_STAKED != 0 && (i == (block.vtx.size() - 1)) && komodo_isPoS((CBlock *)&block) != 0 ) { EraseFromWallets(tx.GetHash()); } @@ -4181,12 +4181,16 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C for (i=0; i>>>>>> jl777 rejects++; } if ( rejects == 0 || rejects == lastrejects ) diff --git a/src/notarisationdb.cpp b/src/notarisationdb.cpp index 6210d88dd..cdfbb82c1 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 @@ -82,3 +83,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..b8cd93691 100644 --- a/src/notarisationdb.h +++ b/src/notarisationdb.h @@ -23,5 +23,6 @@ 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); #endif /* NOTARISATIONDB_H */ 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/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 8b15a39c8..2545ca883 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -313,6 +313,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 ee7c962c4..e15951dbd 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -376,6 +376,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/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3327f2fcc..70a0630ff 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() @@ -5467,6 +5470,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); @@ -5491,6 +5500,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 != "") { @@ -5516,6 +5529,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 ) @@ -5539,6 +5557,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); @@ -5563,6 +5585,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 ) @@ -5686,9 +5712,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 ) @@ -5696,7 +5727,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); } } @@ -5721,9 +5752,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); @@ -5752,9 +5788,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); @@ -5763,7 +5809,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"); }