From 292a9a717b4753b7ffaf1d070f34cfecc6e1311d Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 25 Aug 2018 22:45:23 -0300 Subject: [PATCH 1/4] RPC methods to scan notarisations DB --- src/notarisationdb.cpp | 27 +++++++++++++++++++++ src/notarisationdb.h | 1 + src/rpccrosschain.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 2 ++ src/rpcserver.h | 2 ++ 5 files changed, 85 insertions(+) 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/rpcserver.cpp b/src/rpcserver.cpp index 41228e71a..c24525bdc 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 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); From 124819cef50c517547aa02ee0abde1397d840d51 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Mon, 27 Aug 2018 00:48:20 +0200 Subject: [PATCH 2/4] Lots of error checking improvements and more passing tests --- qa/rpc-tests/cryptoconditions.py | 53 +++++++++++++++++++--------- src/wallet/rpcwallet.cpp | 59 +++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 24 deletions(-) diff --git a/qa/rpc-tests/cryptoconditions.py b/qa/rpc-tests/cryptoconditions.py index f133ae28a..dd6adba76 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,20 @@ 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, []) + result = rpc.diceinfo("invalid") + assert_error(result) + + result = rpc.dicefund("THISISTOOLONG", "10000", "10", "10000", "10", "5") + assert_error(result) def run_token_tests(self): rpc = self.nodes[0] @@ -156,8 +170,15 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.tokenlist() assert_equal(result, []) - result = rpc.tokencreate("DUKE", "1987.420", "duke") + result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply") + assert_error(result) + + result = rpc.tokencreate("NUKE123456789012345678901234567890", "1987420", "name too long") + assert_error(result) + + 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 +218,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 +274,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 +331,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/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1012a0205..6a0555f54 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5234,6 +5234,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 +5264,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 +5293,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 +5321,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 +5349,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 +5476,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 +5491,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 +5516,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 +5552,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 +5573,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"); } From 820043536303738d2b21e7e601997d06cfc19181 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 26 Aug 2018 22:30:28 +0200 Subject: [PATCH 3/4] Validate plan name in dicebet --- src/wallet/rpcwallet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6a0555f54..b99fffa59 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() From 6e3dc787c55249fe4e36d37b3bb5de0761849b69 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 27 Aug 2018 09:35:17 -1100 Subject: [PATCH 4/4] Fix early activation --- src/cc/CCutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index a57197537..8e8b103c8 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -259,7 +259,7 @@ 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 ) {