From 4b6b2a5540f0b4ac93b5322c45396c7e4908e113 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 26 Jan 2019 18:31:46 +0500 Subject: [PATCH 01/13] 'throw' changed to 'return result' on incorrect params tx hex name = 'hex' heirlist returns simple txid array now --- src/cc/heir.cpp | 16 ++++------- src/wallet/rpcwallet.cpp | 57 +++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index d00cab795..0e1c7d177 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -657,13 +657,7 @@ template UniValue _HeirFund(int64_t txfee, int64_t amount, std int64_t markerfee = 10000; //std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl; - - if (!heirPubkey.IsValid()) { - std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "invalid heir pubkey")); - } - + CPubKey myPubkey = pubkey2pk(Mypubkey()); if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) { @@ -714,7 +708,7 @@ template UniValue _HeirFund(int64_t txfee, int64_t amount, std Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName)); if (!rawhextx.empty()) { result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); + result.push_back(Pair("hex", rawhextx)); } else { std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; @@ -835,7 +829,7 @@ template UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, in Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); if (!rawhextx.empty()) { - result.push_back(Pair("hextx", rawhextx)); + result.push_back(Pair("hex", rawhextx)); } else { std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; @@ -1008,7 +1002,7 @@ template UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee if (!rawhextx.empty()) { result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); + result.push_back(Pair("hex", rawhextx)); } else { std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; @@ -1273,7 +1267,7 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result) // note: if it is not Heir token funcId would be equal to 0 if (funcId == 'F') { //result.push_back(Pair("fundingtxid kind name", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName)); - result.push_back( Pair("fundingtxid", txid.GetHex()) ); + result.push_back( txid.GetHex() ); } else { std::cerr << "HeirList() this is not the initial F transaction=" << txid.GetHex() << std::endl; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 14620aa0b..8a1dab638 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7382,30 +7382,45 @@ UniValue heirfund(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); txfee = atoll(params[0].get_str().c_str()); - if (txfee < 0) - throw runtime_error("incorrect txfee param\n"); + if (txfee < 0) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect txfee")); + return result; + } if(params.size() == 6) // tokens in satoshis: amount = atoll(params[1].get_str().c_str()); else // coins: amount = atof(params[1].get_str().c_str()) * COIN; - if( amount <= 0 ) - throw runtime_error("incorrect amount\n"); + if (amount <= 0) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect amount")); + return result; + } name = params[2].get_str(); pubkey = ParseHex(params[3].get_str().c_str()); - if( !pubkey2pk(pubkey).IsValid() ) - throw runtime_error("incorrect pubkey\n"); + if (!pubkey2pk(pubkey).IsValid()) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect pubkey")); + return result; + } inactivitytime = atoll(params[4].get_str().c_str()); - if (inactivitytime <= 0) - throw runtime_error("incorrect inactivity time param\n"); + if (inactivitytime <= 0) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect inactivity time")); + return result; + } if (params.size() == 6) { tokenid = Parseuint256((char*)params[5].get_str().c_str()); - if(tokenid == zeroid) - throw runtime_error("incorrect tokenid\n"); + if (tokenid == zeroid) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect tokenid")); + return result; + } } if( tokenid == zeroid ) @@ -7439,8 +7454,11 @@ UniValue heiradd(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); txfee = atoll(params[0].get_str().c_str()); - if (txfee < 0) - throw runtime_error("incorrect txfee param\n"); + if (txfee < 0) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect txfee")); + return result; + } fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); @@ -7450,7 +7468,7 @@ UniValue heiradd(const UniValue& params, bool fHelp) UniValue heirclaim(const UniValue& params, bool fHelp) { - UniValue result; // result(UniValue::VOBJ); + UniValue result; uint256 fundingtxid; int64_t txfee; int64_t inactivitytime; @@ -7458,7 +7476,6 @@ UniValue heirclaim(const UniValue& params, bool fHelp) std::vector pubkey; std::string name; - // do we need this? if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -7471,8 +7488,11 @@ UniValue heirclaim(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); txfee = atoll(params[0].get_str().c_str()); - if (txfee < 0) - throw runtime_error("incorrect txfee param\n"); + if (txfee < 0) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "incorrect txfee")); + return result; + } fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); @@ -7483,8 +7503,9 @@ UniValue heirclaim(const UniValue& params, bool fHelp) UniValue heirinfo(const UniValue& params, bool fHelp) { uint256 fundingtxid; - if (fHelp || params.size() != 1) // or 0? + if (fHelp || params.size() != 1) throw runtime_error("heirinfo fundingtxid\n"); + // if ( ensure_CCrequirements() < 0 ) // throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -7494,7 +7515,7 @@ UniValue heirinfo(const UniValue& params, bool fHelp) UniValue heirlist(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) // or 0? + if (fHelp || params.size() != 0) throw runtime_error("heirlist\n"); // if ( ensure_CCrequirements() < 0 ) From 2ac92d7d6ec87469584e89d44b731bb5feb8a081 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 26 Jan 2019 19:10:46 +0500 Subject: [PATCH 02/13] result changed to VARR --- src/cc/heir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 0e1c7d177..a148cdc3f 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -1282,7 +1282,7 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result) UniValue HeirList() { - UniValue result(UniValue::VOBJ); + UniValue result(UniValue::VARR); result.push_back(Pair("result", "success")); struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit! From 9bad115496362250102962b221d40d5823b0f902 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 26 Jan 2019 20:18:00 +0500 Subject: [PATCH 03/13] in heirlist added list header --- src/cc/heir.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index a148cdc3f..2c4a85037 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -1284,14 +1284,12 @@ UniValue HeirList() { UniValue result(UniValue::VARR); result.push_back(Pair("result", "success")); + result.push_back(Pair("name", "Heir List")); - struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit! + struct CCcontract_info *cpHeir, heirC; cpHeir = CCinit(&heirC, EVAL_HEIR); - //cpTokens = CCinit(&tokenC, EVAL_TOKENS); - _HeirList(cpHeir, result); - //_HeirList(cpTokens, result); not used anymore return result; } From 82956c357a1ef0182638707789cfe1ae07986e8d Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 26 Jan 2019 20:31:48 +0500 Subject: [PATCH 04/13] removed heir list header - simply txid array --- src/cc/heir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 2c4a85037..5861d347a 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -1283,8 +1283,8 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result) UniValue HeirList() { UniValue result(UniValue::VARR); - result.push_back(Pair("result", "success")); - result.push_back(Pair("name", "Heir List")); + //result.push_back(Pair("result", "success")); + //result.push_back(Pair("name", "Heir List")); struct CCcontract_info *cpHeir, heirC; From d963a55cc85003ac41a8d4528d9a560aae5b5b59 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Sun, 27 Jan 2019 03:16:53 +0700 Subject: [PATCH 05/13] added valid tokens heir case --- qa/rpc-tests/cryptoconditions_heir.py | 53 ++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/cryptoconditions_heir.py b/qa/rpc-tests/cryptoconditions_heir.py index 95b90b397..3aa4ee69c 100755 --- a/qa/rpc-tests/cryptoconditions_heir.py +++ b/qa/rpc-tests/cryptoconditions_heir.py @@ -98,7 +98,58 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): result = rpc.heirinfo(heir_fund_txid) assert_equal(result["funding available in coins"], "0.00000000") - # TODO: valid heirfund case with tokens + # creating tokens which we put to heir contract + token_hex = rpc.tokencreate("TEST", "1", "TESTING") + token_txid = self.send_and_mine(token_hex["hex"], rpc) + assert token_txid, "got token txid" + + # checking possesion over the tokens and balance + result = rpc.tokenbalance(token_txid, self.pubkey)["balance"] + assert_equal(result, 100000000) + + # valid heir case with tokens + token_heir_hex = rpc.heirfund("0", "100000000", "UNITHEIR", self.pubkey1, "10", token_txid) + token_heir_txid = self.send_and_mine(token_heir_hex["hextx"], rpc) + assert token_heir_txid, "got txid of heirfund with tokens" + + self.sync_all() + + # checking heirinfo + result = rpc.heirinfo(token_heir_txid) + assert_success(result) + assert_equal(result["fundingtxid"], token_heir_txid) + assert_equal(result["name"], "UNITHEIR") + assert_equal(result["owner"], self.pubkey) + assert_equal(result["heir"], self.pubkey1) + assert_equal(result["funding total in tokens"], "100000000") + assert_equal(result["funding available in tokens"], "100000000") + assert_equal(result["inactivity time setting, sec"], "10") + assert_equal(result["spending allowed for the heir"], "false") + + # waiting for 11 seconds to be sure that needed time passed for heir claiming + time.sleep(11) + rpc.generate(1) + self.sync_all() + result = rpc.heirinfo(token_heir_txid) + assert_equal(result["funding available in tokens"], "100000000") + assert_equal(result["spending allowed for the heir"], "true") + + # let's claim whole heir sum from second node + result = rpc1.heirclaim("0", "100000000", token_heir_txid) + assert_success(result) + + heir_tokens_claim_txid = self.send_and_mine(result["hextx"], rpc1) + assert heir_tokens_claim_txid, "got claim txid" + + # claiming node should have correct token balance now + result = rpc1.tokenbalance(token_txid, self.pubkey1)["balance"] + assert_equal(result, 100000000) + + self.sync_all() + + # no more funds should be available for claiming + result = rpc.heirinfo(token_heir_txid) + assert_equal(result["funding available in tokens"], "0") def run_test(self): print("Mining blocks...") From 45d35fb971d50307fc4aa916ab0caf8e6c05e536 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Sun, 27 Jan 2019 03:21:16 +0700 Subject: [PATCH 06/13] actualize comment --- qa/rpc-tests/cryptoconditions_channels.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/cryptoconditions_channels.py b/qa/rpc-tests/cryptoconditions_channels.py index b2a49b477..5ba15b572 100755 --- a/qa/rpc-tests/cryptoconditions_channels.py +++ b/qa/rpc-tests/cryptoconditions_channels.py @@ -26,6 +26,8 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] + # TODO: check channelsaddress + # getting empty channels list result = rpc.channelslist() assert_equal(len(result), 2) @@ -143,7 +145,7 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework): refund_txid = self.send_and_mine(result["hex"], rpc) assert refund_txid, "got txid" - # TODO: check if it refunded to opener address + # checking if it refunded to opener address raw_transaction = rpc.getrawtransaction(refund_txid, 1) result = raw_transaction["vout"][2]["valueSat"] From dc510cdde4ea1adcdbc624840ffc4caf9b78a7a7 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Sun, 27 Jan 2019 03:32:24 +0700 Subject: [PATCH 07/13] checking channelsaddress --- qa/rpc-tests/cryptoconditions_channels.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/cryptoconditions_channels.py b/qa/rpc-tests/cryptoconditions_channels.py index 5ba15b572..722cce66e 100755 --- a/qa/rpc-tests/cryptoconditions_channels.py +++ b/qa/rpc-tests/cryptoconditions_channels.py @@ -26,7 +26,13 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework): rpc = self.nodes[0] rpc1 = self.nodes[1] - # TODO: check channelsaddress + # checking channelsaddress call + + result = rpc.channelsaddress(self.pubkey) + assert_success(result) + # test that additional CCaddress key is returned + for x in ['myCCaddress', 'ChannelsCCaddress', 'Channelsmarker', 'myaddress', 'CCaddress']: + assert_equal(result[x][0], 'R') # getting empty channels list result = rpc.channelslist() From fdcc9d71c2c6e9fe4798f1e55256ee2b58cb96db Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 27 Jan 2019 17:03:38 +0500 Subject: [PATCH 08/13] heirinfo var names corrected memo field added --- src/cc/CCHeir.h | 8 +- src/cc/heir.cpp | 194 +++++++++++++++++---------------------- src/cc/heir_validate.h | 24 ++--- src/wallet/rpcwallet.cpp | 18 ++-- 4 files changed, 108 insertions(+), 136 deletions(-) diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index 30334f6e1..2943d747c 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -27,15 +27,11 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, class CoinHelper; class TokenHelper; -UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); -UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); +UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo); +UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid); UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount); UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount); - UniValue HeirInfo(uint256 fundingtxid); UniValue HeirList(); -//std::string Heir_MakeBadTx(uint256 fundingtxid, uint8_t funcId, int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTime, uint32_t errMask); - -//bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 assetid, const CTransaction &tx); #endif diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 5861d347a..8e7f3f08b 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -255,11 +255,11 @@ template int64_t IsHeirFundingVout(struct CCcontract_info* cp, co } // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) +CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { uint8_t evalcode = EVAL_HEIR; - return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); + return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName << memo); } // makes coin additional tx opret @@ -273,7 +273,7 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe // decode opret vout for Heir contract -uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { uint8_t evalCodeInOpret = 0; uint8_t heirFuncId = 0; @@ -287,13 +287,13 @@ uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPub uint8_t heirFuncId = 0; hasHeirSpendingBegun = 0; - bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \ - if (heirFuncId == 'F') { \ - ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \ - } \ - else { \ - ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ - } \ + bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \ + if (heirFuncId == 'F') { \ + ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; ss >> memo; \ + } \ + else { \ + ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ + } \ }); if (!result) { @@ -322,84 +322,49 @@ uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPub return (uint8_t)0; } -/* not used, see DecodeHeirOpRet(vopret,...) - // overload for 'F' opret - uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) - { - uint256 dummytxid; - uint8_t dummyHasHeirSpendingBegun; - std::vector vopret; - - GetOpReturnData(scriptPubKey, vopret); - if (vopret.size() == 0) { - if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; - return (uint8_t)0; - } - return _DecodeHeirOpRet(vopret, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); - }*/ - - -/* not used, see DecodeHeirOpRet(vopret,...) - // overload for A, C oprets and AddHeirContractInputs - uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) - { - CPubKey dummyOwnerPubkey, dummyHeirPubkey; - int64_t dummyInactivityTime; - std::string dummyHeirName; - std::vector vopret; - - GetOpReturnData(scriptPubKey, vopret); - if (vopret.size() == 0) { - if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; - return (uint8_t)0; - } - - return _DecodeHeirOpRet(vopret, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); - } */ - // decode combined opret: -uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { - uint8_t evalCodeTokens = 0; - std::vector voutPubkeysDummy; - std::vector vopretExtra, vopretStripped; - - if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) { - if (vopretExtra.size() > 1) { - // restore the second opret: - - if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size - if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; - return (uint8_t)0; - } - } - else { - if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl; - return (uint8_t)0; - } - } - else - GetOpReturnData(scriptPubKey, vopretStripped); - - return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); + uint8_t evalCodeTokens = 0; + std::vector voutPubkeysDummy; + std::vector vopretExtra, vopretStripped; + + if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) { + if (vopretExtra.size() > 1) { + // restore the second opret: + + if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size + if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; + return (uint8_t)0; + } + } + else { + if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl; + return (uint8_t)0; + } + } + else { + GetOpReturnData(scriptPubKey, vopretStripped); + } + return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); } // overload to decode opret in fundingtxid: -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { +uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging) { uint256 dummyFundingTxidInOpret; uint8_t dummyHasHeirSpendingBegun; - return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); + return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); } // overload to decode opret in A and C heir tx: uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; - std::string dummyHeirName; + std::string dummyHeirName, dummyMemo; - return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); + return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, dummyMemo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); } // check if pubkey is in vins @@ -423,7 +388,7 @@ void CheckVinPubkey(std::vector vins, CPubKey pubkey, bool &hasPubkey, bo * find the latest funding tx: it may be the first F tx or one of A or C tx's * Note: this function is also called from validation code (use non-locking calls) */ -uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) +uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) { CTransaction fundingtx; uint256 hashBlock; @@ -440,7 +405,7 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); if (funcId != 0) { // found at least funding tx! //std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; @@ -522,17 +487,17 @@ uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRe CPubKey ownerPubkey; CPubKey heirPubkey; int64_t inactivityTime; - std::string heirName; + std::string heirName, memo; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun); } // overload for transaction creation code -uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun) +uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint8_t &hasHeirSpendingBegun) { CScript opRetScript; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun); } // add inputs of 1 of 2 cc address @@ -561,7 +526,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, // no need to prevent dup // dimxy: maybe it is good to put tx's in cache? - std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl; + //std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl; if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; @@ -644,7 +609,7 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info * and also for setting spending plan for the funds' owner and heir * @return fundingtxid handle for subsequent references to this heir funding plan */ -template UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) +template UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) { UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -705,7 +670,7 @@ template UniValue _HeirFund(int64_t txfee, int64_t amount, std // add change for txfee and opreturn vouts and sign tx: std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName)); + Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName, memo)); if (!rawhextx.empty()) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", rawhextx)); @@ -731,12 +696,12 @@ template UniValue _HeirFund(int64_t txfee, int64_t amount, std } // if no these callers - it could not link -UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){ - return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid); +UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){ + return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, zeroid); } -UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { - return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid); +UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) { + return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, tokenid); } /** @@ -744,7 +709,7 @@ UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirNa * creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir * @return result object with raw tx or error text */ -template UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) +template UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun) { UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -862,10 +827,10 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount uint256 latesttxid, tokenid = zeroid; uint8_t funcId; - std::string heirName; + std::string heirName, memo; uint8_t hasHeirSpendingBegun = 0; - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) { if (tokenid == zeroid) { int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN); if (amount <= 0) { @@ -874,8 +839,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount result.push_back(Pair("error", "invalid amount")); return result; } - - return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); } else { int64_t amount = atoll(strAmount.c_str()); @@ -885,7 +849,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount result.push_back(Pair("error", "invalid amount")); return result; } - return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); } } else { @@ -904,7 +868,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount * creates tx to spend funds from cryptocondition address by either funds' owner or heir * @return result object with raw tx or error text */ -template UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) +template UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun) { UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -1032,10 +996,10 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou uint256 latesttxid, tokenid = zeroid; uint8_t funcId; - std::string heirName; + std::string heirName, memo; uint8_t hasHeirSpendingBegun = 0; - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) { if (tokenid == zeroid) { int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN); if (amount < 0) { @@ -1044,7 +1008,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou result.push_back(Pair("error", "invalid amount")); return result; } - return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); } else { int64_t amount = atoll(strAmount.c_str()); @@ -1054,7 +1018,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou result.push_back(Pair("error", "invalid amount")); return result; } - return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun); } } @@ -1093,7 +1057,7 @@ UniValue HeirInfo(uint256 fundingtxid) CPubKey ownerPubkey, heirPubkey; uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid - std::string heirName; + std::string heirName, memo; int64_t inactivityTimeSec; const bool noLogging = false; uint8_t funcId; @@ -1112,7 +1076,7 @@ UniValue HeirInfo(uint256 fundingtxid) uint8_t hasHeirSpendingBegun = 0; - uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun); if (latestFundingTxid != zeroid) { int32_t numblocks; @@ -1153,12 +1117,22 @@ UniValue HeirInfo(uint256 fundingtxid) else total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); + msg = "type"; + if (tokenid == zeroid) { + stream << "coins"; + } + else { + stream << "tokens"; + } + result.push_back(Pair(msg, stream.str().c_str())); + stream.str(""); + stream.clear(); + + msg = "lifetime"; if (tokenid == zeroid) { - msg = "funding total in coins"; stream << std::fixed << std::setprecision(8) << (double)total / COIN; } else { - msg = "funding total in tokens"; stream << total; } result.push_back(Pair(msg, stream.str().c_str())); @@ -1171,12 +1145,11 @@ UniValue HeirInfo(uint256 fundingtxid) else inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); + msg = "available"; if (tokenid == zeroid) { - msg = "funding available in coins"; stream << std::fixed << std::setprecision(8) << (double)inputs / COIN; } else { - msg = "funding available in tokens"; stream << inputs; } result.push_back(Pair(msg, stream.str().c_str())); @@ -1186,14 +1159,14 @@ UniValue HeirInfo(uint256 fundingtxid) if (tokenid != zeroid) { int64_t ownerInputs = TokenHelper::addOwnerInputs(tokenid, mtx, ownerPubkey, 0, (int32_t)64); stream << ownerInputs; - msg = "owner funding available in tokens"; + msg = "OwnerRemainderTokens"; result.push_back(Pair(msg, stream.str().c_str())); stream.str(""); stream.clear(); } stream << inactivityTimeSec; - result.push_back(Pair("inactivity time setting, sec", stream.str().c_str())); + result.push_back(Pair("InactivityTimeSetting", stream.str().c_str())); stream.str(""); stream.clear(); @@ -1203,18 +1176,20 @@ UniValue HeirInfo(uint256 fundingtxid) } stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec); - result.push_back(Pair("spending allowed for the heir", stream.str().c_str())); + result.push_back(Pair("IsHeirSpendingAllowed", stream.str().c_str())); stream.str(""); stream.clear(); // adding owner current inactivity time: if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) { stream << durationSec; - result.push_back(Pair("owner inactivity time, sec", stream.str().c_str())); + result.push_back(Pair("InactivityTime", stream.str().c_str())); stream.str(""); stream.clear(); } - + + result.push_back(Pair("memo", memo.c_str())); + result.push_back(Pair("result", "success")); } else { @@ -1256,13 +1231,13 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result) CTransaction fundingtx; if (GetTransaction(txid, fundingtx, hashBlock, false)) { CPubKey ownerPubkey, heirPubkey; - std::string heirName; + std::string heirName, memo; int64_t inactivityTimeSec; const bool noLogging = true; uint256 tokenid; CScript opret = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, true); // note: if it is not Heir token funcId would be equal to 0 if (funcId == 'F') { @@ -1293,4 +1268,3 @@ UniValue HeirList() return result; } - diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index df58e3bf1..15ab133e4 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -7,13 +7,13 @@ #define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); +CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo); CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan); //uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false); //uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); +uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging = false); uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false); inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } @@ -28,8 +28,8 @@ public: return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); } - static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { + return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo); } static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { return EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan); @@ -66,9 +66,9 @@ public: return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs); } - static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { + static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName)); + EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo)); } static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { return EncodeTokenOpRet(tokenid, voutTokenPubkeys, @@ -407,10 +407,10 @@ public: //std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl; CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; - std::string heirName; + std::string heirName, memo; uint256 tokenid; - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); if (funcId == 0) { message = m_customMessage + std::string(" invalid opreturn format"); std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; @@ -462,13 +462,13 @@ public: CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; - std::string heirName; + std::string heirName, memo; uint256 tokenid; ///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl; // get both pubkeys: - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); if (funcId == 0) { message = std::string("invalid opreturn format"); return false; @@ -522,11 +522,11 @@ public: CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; - std::string heirName; + std::string heirName, memo; uint256 tokenid; // get heir pubkey: - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); if (funcId == 0) { message = std::string("invalid opreturn format"); return false; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8a1dab638..2adf931bb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7368,13 +7368,13 @@ UniValue heirfund(const UniValue& params, bool fHelp) int64_t inactivitytime; std::string hex; std::vector pubkey; - std::string name; + std::string name, memo; if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() != 5 && params.size() != 6) - throw runtime_error("heirfund txfee funds heirname heirpubkey inactivitytime [tokenid]\n"); + if (fHelp || params.size() != 6 && params.size() != 7) + throw runtime_error("heirfund txfee funds heirname heirpubkey inactivitytime memo [tokenid]\n"); if (ensure_CCrequirements() < 0) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -7392,7 +7392,6 @@ UniValue heirfund(const UniValue& params, bool fHelp) amount = atoll(params[1].get_str().c_str()); else // coins: amount = atof(params[1].get_str().c_str()) * COIN; - if (amount <= 0) { result.push_back(Pair("result", "error")); result.push_back(Pair("error", "incorrect amount")); @@ -7400,6 +7399,7 @@ UniValue heirfund(const UniValue& params, bool fHelp) } name = params[2].get_str(); + pubkey = ParseHex(params[3].get_str().c_str()); if (!pubkey2pk(pubkey).IsValid()) { result.push_back(Pair("result", "error")); @@ -7414,8 +7414,10 @@ UniValue heirfund(const UniValue& params, bool fHelp) return result; } - if (params.size() == 6) { - tokenid = Parseuint256((char*)params[5].get_str().c_str()); + memo = params[5].get_str(); + + if (params.size() == 7) { + tokenid = Parseuint256((char*)params[6].get_str().c_str()); if (tokenid == zeroid) { result.push_back(Pair("result", "error")); result.push_back(Pair("error", "incorrect tokenid")); @@ -7424,9 +7426,9 @@ UniValue heirfund(const UniValue& params, bool fHelp) } if( tokenid == zeroid ) - result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); + result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, memo); else - result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, tokenid); + result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, memo, tokenid); return result; } From daf34e231501c55ce0b4009c2befd3196b71836b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 27 Jan 2019 17:17:27 +0500 Subject: [PATCH 09/13] corrected rpc param size check --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2adf931bb..e111ad98a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7388,7 +7388,7 @@ UniValue heirfund(const UniValue& params, bool fHelp) return result; } - if(params.size() == 6) // tokens in satoshis: + if(params.size() == 7) // tokens in satoshis: amount = atoll(params[1].get_str().c_str()); else // coins: amount = atof(params[1].get_str().c_str()) * COIN; From 134534b3847fd0a229049b9569f0f9ae920f9f17 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 27 Jan 2019 17:56:08 +0500 Subject: [PATCH 10/13] var naming improved --- src/cc/CCHeir.h | 2 +- src/cc/heir.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index 2943d747c..fa1f72263 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -27,7 +27,7 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, class CoinHelper; class TokenHelper; -UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo); +UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo); UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid); UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount); UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 8e7f3f08b..04866594d 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -696,8 +696,8 @@ template UniValue _HeirFund(int64_t txfee, int64_t amount, std } // if no these callers - it could not link -UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){ - return _HeirFund(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, zeroid); +UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){ + return _HeirFund(txfee, coins, heirName, heirPubkey, inactivityTimeSec, memo, zeroid); } UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) { From 7bd8f456c30bb2bcb500ea77e6687e8ce8deb3fb Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Mon, 28 Jan 2019 00:03:25 +0700 Subject: [PATCH 11/13] tests adjusted for heirCC json enhancement --- qa/rpc-tests/cryptoconditions_heir.py | 54 +++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/qa/rpc-tests/cryptoconditions_heir.py b/qa/rpc-tests/cryptoconditions_heir.py index 3aa4ee69c..b79ae7bba 100755 --- a/qa/rpc-tests/cryptoconditions_heir.py +++ b/qa/rpc-tests/cryptoconditions_heir.py @@ -34,21 +34,18 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): # getting empty heir list result = rpc.heirlist() - assert_equal(len(result), 1) - assert_success(result) + assert_equal(result, []) # valid heirfund case with coins - result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10") + result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO") assert_success(result) - heir_fund_txid = self.send_and_mine(result["hextx"], rpc) + heir_fund_txid = self.send_and_mine(result["hex"], rpc) assert heir_fund_txid, "got heir funding txid" # heir fund txid should be in heirlist now result = rpc.heirlist() - assert_equal(len(result), 2) - assert_success(result) - assert_equal(result["fundingtxid"], heir_fund_txid) + assert_equal(result, [heir_fund_txid]) # checking heirinfo result = rpc.heirinfo(heir_fund_txid) @@ -57,20 +54,20 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): assert_equal(result["name"], "UNITHEIR") assert_equal(result["owner"], self.pubkey) assert_equal(result["heir"], self.pubkey1) - assert_equal(result["funding total in coins"], "1000.00000000") - assert_equal(result["funding available in coins"], "1000.00000000") - assert_equal(result["inactivity time setting, sec"], "10") - assert_equal(result["spending allowed for the heir"], "false") - - # TODO: heirlist keys are duplicating now + assert_equal(result["memo"], "TESTMEMO") + assert_equal(result["lifetime"], "1000.00000000") + assert_equal(result["type"], "coins") + assert_equal(result["InactivityTimeSetting"], "10") + assert_equal(result["InactivityTime"], "0") + assert_equal(result["IsHeirSpendingAllowed"], "false") # waiting for 11 seconds to be sure that needed time passed for heir claiming time.sleep(11) rpc.generate(1) self.sync_all() result = rpc.heirinfo(heir_fund_txid) - assert_equal(result["funding available in coins"], "1000.00000000") - assert_equal(result["spending allowed for the heir"], "true") + assert_equal(result["lifetime"], "1000.00000000") + assert_equal(result["IsHeirSpendingAllowed"], "true") # have to check that second node have coins to cover txfee at least rpc.sendtoaddress(rpc1.getnewaddress(), 1) @@ -84,7 +81,7 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): result = rpc1.heirclaim("0", "1000", heir_fund_txid) assert_success(result) - heir_claim_txid = self.send_and_mine(result["hextx"], rpc1) + heir_claim_txid = self.send_and_mine(result["hex"], rpc1) assert heir_claim_txid, "got claim txid" # balance of second node after heirclaim should increase for 1000 coins - txfees @@ -96,7 +93,8 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): # no more funds should be available for claiming result = rpc.heirinfo(heir_fund_txid) - assert_equal(result["funding available in coins"], "0.00000000") + assert_equal(result["lifetime"], "1000.00000000") + assert_equal(result["available"], "0.00000000") # creating tokens which we put to heir contract token_hex = rpc.tokencreate("TEST", "1", "TESTING") @@ -108,8 +106,8 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): assert_equal(result, 100000000) # valid heir case with tokens - token_heir_hex = rpc.heirfund("0", "100000000", "UNITHEIR", self.pubkey1, "10", token_txid) - token_heir_txid = self.send_and_mine(token_heir_hex["hextx"], rpc) + token_heir_hex = rpc.heirfund("0", "100000000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO", token_txid) + token_heir_txid = self.send_and_mine(token_heir_hex["hex"], rpc) assert token_heir_txid, "got txid of heirfund with tokens" self.sync_all() @@ -121,24 +119,25 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): assert_equal(result["name"], "UNITHEIR") assert_equal(result["owner"], self.pubkey) assert_equal(result["heir"], self.pubkey1) - assert_equal(result["funding total in tokens"], "100000000") - assert_equal(result["funding available in tokens"], "100000000") - assert_equal(result["inactivity time setting, sec"], "10") - assert_equal(result["spending allowed for the heir"], "false") + assert_equal(result["lifetime"], "100000000") + assert_equal(result["type"], "tokens") + assert_equal(result["InactivityTimeSetting"], "10") + assert_equal(result["InactivityTime"], "0") + assert_equal(result["IsHeirSpendingAllowed"], "false") # waiting for 11 seconds to be sure that needed time passed for heir claiming time.sleep(11) rpc.generate(1) self.sync_all() result = rpc.heirinfo(token_heir_txid) - assert_equal(result["funding available in tokens"], "100000000") - assert_equal(result["spending allowed for the heir"], "true") + assert_equal(result["lifetime"], "100000000") + assert_equal(result["IsHeirSpendingAllowed"], "true") # let's claim whole heir sum from second node result = rpc1.heirclaim("0", "100000000", token_heir_txid) assert_success(result) - heir_tokens_claim_txid = self.send_and_mine(result["hextx"], rpc1) + heir_tokens_claim_txid = self.send_and_mine(result["hex"], rpc1) assert heir_tokens_claim_txid, "got claim txid" # claiming node should have correct token balance now @@ -149,7 +148,8 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework): # no more funds should be available for claiming result = rpc.heirinfo(token_heir_txid) - assert_equal(result["funding available in tokens"], "0") + assert_equal(result["lifetime"], "100000000") + assert_equal(result["available"], "0") def run_test(self): print("Mining blocks...") From 59c67afa11e33705eb6aab1d3f75186f5d0aabb2 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 28 Jan 2019 13:22:29 +0100 Subject: [PATCH 12/13] Fixing FinalizeCCTx to return error if not possible to sign vin. --- src/cc/CCtx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index ae7483f4d..630a00d8f 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -242,7 +242,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran if ( flag == 0 ) { fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr); - continue; + return(""); } } uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata); From 463caf96ec1251afdee1939dc5359ba96e3e6bd5 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 28 Jan 2019 13:54:21 +0100 Subject: [PATCH 13/13] Gateways with new TokensCC (#15) - Adapting Gateways to new Tokens - Making withdraws serialized until solution for parallel is made --- src/cc/CCGateways.h | 3 +- src/cc/CCtx.cpp | 10 +- src/cc/dapps/oraclefeed.c | 184 +++----- src/cc/gateways.cpp | 970 ++++++++++++++++++++++++-------------- src/rpc/server.cpp | 4 +- src/rpc/server.h | 4 +- src/wallet/rpcwallet.cpp | 29 +- 7 files changed, 700 insertions(+), 504 deletions(-) diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index b629ade1f..7ecae2228 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -28,10 +28,9 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin); +UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin); UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin); -UniValue GatewaysMultisig(char *txidaddr); - // CCcustom UniValue GatewaysInfo(uint256 bindtxid); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 630a00d8f..a8d832661 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -390,9 +390,9 @@ int64_t CCfullsupply(uint256 tokenid) return(0); } -int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) +int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid) { - int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; + int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock; std::vector vopretExtra; std::vector > unspentOutputs; uint8_t evalCode; @@ -401,11 +401,11 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; - if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 ) { - char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN); + char str[65]; std::vector voutTokenPubkeys; - if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid ) + if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, vopretExtra) != 0 && reftokenid == tokenid)) { sum += it->second.satoshis; } diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index 8a819a147..8f7ccb197 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -475,7 +475,7 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr) { cJSON *retjson; char *retstr; - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspendingwithdraws",bindtxidstr,refcoin,"","")) != 0 ) { //printf("pending.(%s)\n",jprint(retjson,0)); return(retjson); @@ -588,13 +588,12 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int } } -void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr) +void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys) { cJSON *retjson; char *retstr,Mstr[10],tmp[128]; sprintf(Mstr,"%d",M); - sprintf(tmp,"\"%s\"",bindtxidstr); - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,"","")) != 0 ) { fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0)); free(retstr); @@ -644,7 +643,6 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN); return(0); } - satoshis -= txfee; sprintf(array,"\'[\"%s\"]\'",depositaddr); if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 ) { @@ -699,7 +697,7 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx) { if ( is_cJSON_True(jobj(retjson,"complete")) != 0 ) return(retjson); - else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) ) + else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) + 2 ) { jaddnum(retjson,"partialtx",1); return(retjson); @@ -714,32 +712,14 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx) return(0); } -char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K) -{ - char *retstr,*hexstr,*hex=0; cJSON *retjson; - if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 ) - { - if ((hexstr=jstr(retjson,"hex")) != 0 ) - { - if (strlen(hexstr)>0) hex = clonestr(hexstr); - } - *K=jint(retjson,"number_of_signs"); - free_json(retjson); - } - else if ( retstr != 0 ) - { - printf("error parsing gatewaysmultisig.(%s)\n",retstr); - free(retstr); - } - return(hex); -} - -bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) +bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *coin,char *hex) { char str[65],*retstr; cJSON *retjson; - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),coin,hex,"")) != 0 ) { - return(komodobroadcast(refcoin,acname,retjson)); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { @@ -749,36 +729,38 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) return (zeroid); } -void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex) +bits256 gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex) { - char str[65],str2[65],*retstr; cJSON *retjson; - printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 ) { - komodobroadcast(refcoin,acname,retjson); - free_json(retjson); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { printf("error parsing gatewayscompletesigning.(%s)\n",retstr); free(retstr); } + return (zeroid); } -void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin) +bits256 gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin) { - char str[65],str2[65],*retstr; cJSON *retjson; - printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,"","")) != 0 ) { - komodobroadcast(refcoin,acname,retjson); - free_json(retjson); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { printf("error parsing gatewaysmarkdone.(%s)\n",retstr); free(retstr); } + return (zeroid); } int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys) @@ -882,55 +864,9 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr) free_json(array); } } - fprintf(stderr,"Num=%d\n",num); return(num); } -int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr) -{ - cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr; - if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 ) - { - n=cJSON_GetArraySize(array); - for (i=0; i 0 ) - { - num = 1; - break; - } - } - } - free_json(array); - } else return(-1); - } - return(num); -} void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N) { @@ -941,7 +877,9 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t /// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2) /// if not enough sigs, post partially signed to acname with marker2 // monitor marker2, for the partially signed withdraws - cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,origtxid; int64_t satoshis; + cJSON *retjson,*pending,*item,*clijson; char str[65],str1[65],str2[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; + int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis; + memset(&zeroid,0,sizeof(zeroid)); if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 ) { @@ -954,52 +892,55 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t if ( processed != 0 ) // avoid out of utxo conditions break; item = jitem(pending,i); - origtxid = jbits256(item,"txid"); + withdrawtxid = jbits256(item,"withdrawtxid"); //process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"} - if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 ) + if ( (txidaddr=jstr(item,"withdrawtxidaddr"))!= 0 && (withdrawaddr=jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 ) { - if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0) + if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0) { if ( strcmp(depositaddr,signeraddr) == 0 ) { rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); if ( rawtx != 0 ) { - if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) + if ( (clijson=addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) { - gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); - fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr); + txid=gatewayscompletesigning("KMD",acname,withdrawtxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) complete signing tx sent - %s\n",bits256_str(str,withdrawtxid),bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); free_json(clijson); - } - processed++; + processed++; + } free(rawtx); } else fprintf(stderr,"couldnt create rawtx\n"); } else { - if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0) + lasttxid = jbits256(item,"last_txid"); + if ( lasttxid.txid==withdrawtxid.txid) { rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); } - if ( rawtx != 0 ) + else rawtx=jstr(item,"hex"); + K=jint(item,"number_of_signs"); + if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 ) { - if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 ) - { - if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) - { - gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); - fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr); - } - else if ( jint(clijson,"partialtx") != 0 ) - { - txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex")); - fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid)); - } - free_json(clijson); + if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) + { + txid=gatewayscompletesigning("KMD",acname,lasttxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) complete signing tx (%dof%d) sent - %s\n",bits256_str(str,withdrawtxid),M,N,bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); } + else if ( jint(clijson,"partialtx") != 0 ) + { + txid=gatewayspartialsign("KMD",acname,lasttxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) partial tx (%d/%dof%d) sent - %s\n",bits256_str(str,withdrawtxid),K+1,M,N,bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); + } + free_json(clijson); processed++; - free(rawtx); - } else fprintf(stderr,"couldnt create msig rawtx\n"); + } + free(rawtx); } } } @@ -1012,24 +953,27 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t { if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) { - if ( (pending=jarray(&n,retjson,"processed")) != 0 ) + if ((pending=jarray(&n,retjson,"processed")) != 0) { for (i=0; i pubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2) +CScript EncodeGatewaysBindOpRet(uint8_t funcid,uint256 tokenid,std::string coin,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector gatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2) { - CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid); - return(opret); + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; + + cp = CCinit(&C,EVAL_GATEWAYS); + gatewayspk = GetUnspendable(cp,0); + pubkeys.push_back(gatewayspk); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << totalsupply << oracletxid << M << N << gatewaypubkeys << taddr << prefix << prefix2); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) +uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector vOpretExtra; std::vector pubkeys; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); depositaddr[0] = 0; - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> prefix; ss >> prefix2; ss >> taddr; ss >> tokenid; ss >> totalsupply; ss >> M; ss >> N; ss >> pubkeys; ss >> oracletxid) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> totalsupply; ss >> oracletxid; ss >> M; ss >> N; ss >> gatewaypubkeys; ss >> taddr; ss >> prefix; ss >> prefix2;) != 0 ) { if ( prefix == 60 ) { if ( N > 1 ) { - strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,pubkeys))).ToString().c_str()); - //Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys)); - fprintf(stderr,"f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)pubkeys.size(),depositaddr); - } else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG); + strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,gatewaypubkeys))).ToString().c_str()); + //fprintf(stderr,"f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)gatewaypubkeys.size(),depositaddr); + } else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(gatewaypubkeys[0])) << OP_CHECKSIG); } else { @@ -189,118 +190,134 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,st return(0); } -CScript EncodeGatewaysDepositOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) +CScript EncodeGatewaysDepositOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << deposithex << proof << destpub << amount); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << bindtxid << publishers << txids << height << cointxid << claimvout << deposithex << proof << destpub << amount); return(opret); } -uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -// encodes payload for the token opret (needs to be added to the tail of it) -CScript EncodeGatewaysClaimOpRet(uint8_t funcid, std::string refcoin, uint256 bindtxid, uint256 deposittxid, CPubKey destpub, int64_t amount) +CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 tokenid,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount) { - CScript opret; + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; - opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << bindtxid << deposittxid << destpub << amount); - return(opret); + pubkeys.push_back(destpub); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << deposittxid << destpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,uint256 &bindtxid,std::string &refcoin,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bindtxid; ss >> refcoin; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid, std::string refcoin, CPubKey withdrawpub, int64_t amount) +CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 tokenid,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { - CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << withdrawpub << amount); - return(opret); + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; + + cp = CCinit(&C,EVAL_GATEWAYS); + gatewayspk = GetUnspendable(cp,0); + pubkeys.push_back(gatewayspk); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &tokenid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256& tokenid, uint256 &bindtxid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) { - std::vector vopret; uint8_t *script,e,f; + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; - - GetOpReturnData(scriptPubKey, vopret); + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bindtxid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysPartialOpRet(uint8_t funcid,int32_t K, CPubKey signerpk, std::string refcoin,std::string hex) +CScript EncodeGatewaysPartialOpRet(uint8_t funcid, uint256 withdrawtxid,std::string refcoin,int32_t K, CPubKey signerpk,std::string hex) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << K << signerpk << refcoin << hex); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << signerpk << hex); return(opret); } -uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &refcoin,std::string &hex) +uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,int32_t &K, CPubKey &signerpk,std::string &hex) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> K; ss >> signerpk; ss >> refcoin; ss >> hex) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> K; ss >> signerpk; ss >> hex) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysCompleteSigningOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid,std::string hex) +CScript EncodeGatewaysCompleteSigningOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,std::string hex) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid << hex); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << hex); return(opret); } -uint8_t DecodeGatewaysCompleteSigningOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &withdrawtxid,std::string &hex) +uint8_t DecodeGatewaysCompleteSigningOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,std::string &hex) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid; ss >> hex) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> hex) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysMarkDoneOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid) +CScript EncodeGatewaysMarkDoneOpRet(uint8_t funcid,std::string refcoin,uint256 completetxid,uint256 withdrawtxid) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << completetxid < vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid;) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> completetxid; ss >> withdrawtxid;) != 0 ) { return(f); } @@ -309,12 +326,19 @@ uint8_t DecodeGatewaysMarkDoneOpRet(const CScript &scriptPubKey, std::string &re uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_TOKENS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; uint256 tokenid; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { - if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M') + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && script[0] == EVAL_GATEWAYS) + { + f=script[1]; + if (f == 'B' || f == 'D' || f == 'C' || f == 'W' || f == 'P' || f == 'S' || f == 'M') return(f); } return(0); @@ -429,7 +453,7 @@ uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,u return(zeroid); } -int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool! +int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) { char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock; std::vector > addressIndex; @@ -457,7 +481,9 @@ uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::ve int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub) { - std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; + char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid)); @@ -505,7 +531,7 @@ int64_t GatewaysDepositval(CTransaction tx,CPubKey mypk) int32_t numvouts,claimvout,height; int64_t amount; std::string coin,deposithex; std::vector publishers; std::vectortxids; uint256 bindtxid,cointxid; std::vector proof; CPubKey claimpubkey; if ( (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) + if ( DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) { // coin, bindtxid, publishers fprintf(stderr,"need to validate deposittxid more\n"); @@ -574,74 +600,74 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vout.0: CC vout of total tokens from deposit amount to asset eval code //(vout.1): CC vout if there is change of unused tokens back to owner of tokens (deposit amount less than available tokens) //vout.n-1: opreturn - 't' tokenid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) - if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0) - return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); - else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for gatewaysClaim!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysClaim!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for gatewaysClaim!"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.0 is CC for gatewaysClaim!"); - else if ( numvouts > 2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for gatewaysClaim!"); - else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) - return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') - return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different in bind tx"); - else if (tokenidClaim!=tokenidBind) - return eval->Invalid("tokenid does not match tokenid from gatewaysbind"); - else if (komodo_txnotarizedconfirmed(bindtxid) == false) - return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); - else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) - return eval->Invalid("invalid gatewaysdeposittxid!"); - else if ((numvouts=deposittx.vout.size()) > 0 && DecodeGatewaysDepositOpRet(deposittx.vout[numvouts-1].scriptPubKey,tmprefcoin,tmptxid,tmppublishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D') - return eval->Invalid("invalid gatewaysdeposit OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different in deposit tx"); - else if (bindtxid!=tmptxid) - return eval->Invalid("bindtxid does not match to bindtxid from gatewaysdeposit"); - else if (tmpamount>totalsupply) - return eval->Invalid("deposit amount greater then bind total supply"); - else if (komodo_txnotarizedconfirmed(deposittxid) == false) - return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); - else if (amount>tmpamount) - return eval->Invalid("claimed amount greater then deposit amount"); - else if (destpub!=tmpdestpub) - return eval->Invalid("destination pubkey different than in deposit tx"); - else - { - int32_t m; - merkleroot = zeroid; - for (i=m=0; iInvalid(validationError); - } - if ( GatewaysCointxidExists(cp,cointxid) != 0 ) - { - sprintf(validationError,"cointxid.%s already exists\n",uint256_str(str,cointxid)); - return eval->Invalid(validationError); - } - if (GatewaysVerify(depositaddr,oracletxid,claimvout,tmprefcoin,cointxid,deposithex,proof,merkleroot,destpub)!=amount) - return eval->Invalid("deposittxid didnt validate\n"); - } + // if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0) + // return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); + // else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + // return eval->Invalid("vin.0 is normal for gatewaysClaim!"); + // else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + // return eval->Invalid("vin.1 is CC for gatewaysClaim!"); + // else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + // return eval->Invalid("vin.2 is CC for gatewaysClaim!"); + // else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + // return eval->Invalid("vout.0 is CC for gatewaysClaim!"); + // else if ( numvouts > 2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + // return eval->Invalid("vout.1 is CC for gatewaysClaim!"); + // else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) + // return eval->Invalid("invalid gatewaysbind txid!"); + // else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') + // return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + // else if (tmprefcoin!=refcoin) + // return eval->Invalid("refcoin different in bind tx"); + // else if (tokenidClaim!=tokenidBind) + // return eval->Invalid("tokenid does not match tokenid from gatewaysbind"); + // else if (komodo_txnotarizedconfirmed(bindtxid) == false) + // return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + // else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) + // return eval->Invalid("invalid gatewaysdeposittxid!"); + // else if ((numvouts=deposittx.vout.size()) > 0 && DecodeGatewaysDepositOpRet(deposittx.vout[numvouts-1].scriptPubKey,tmprefcoin,tmptxid,tmppublishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D') + // return eval->Invalid("invalid gatewaysdeposit OP_RETURN data!"); + // else if (tmprefcoin!=refcoin) + // return eval->Invalid("refcoin different in deposit tx"); + // else if (bindtxid!=tmptxid) + // return eval->Invalid("bindtxid does not match to bindtxid from gatewaysdeposit"); + // else if (tmpamount>totalsupply) + // return eval->Invalid("deposit amount greater then bind total supply"); + // else if (komodo_txnotarizedconfirmed(deposittxid) == false) + // return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); + // else if (amount>tmpamount) + // return eval->Invalid("claimed amount greater then deposit amount"); + // else if (destpub!=tmpdestpub) + // return eval->Invalid("destination pubkey different than in deposit tx"); + // else + // { + // int32_t m; + // merkleroot = zeroid; + // for (i=m=0; iInvalid(validationError); + // } + // if ( GatewaysCointxidExists(cp,cointxid) != 0 ) + // { + // sprintf(validationError,"cointxid.%s already exists\n",uint256_str(str,cointxid)); + // return eval->Invalid(validationError); + // } + // if (GatewaysVerify(depositaddr,oracletxid,claimvout,tmprefcoin,cointxid,deposithex,proof,merkleroot,destpub)!=amount) + // return eval->Invalid("deposittxid didnt validate\n"); + // } break; case 'W': //vin.0: normal input @@ -669,8 +695,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & break; } } - - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Gatewaysget validated\n"); @@ -683,65 +707,81 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 reftokenid,int64_t total,int32_t maxinputs) +int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 bindtxid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 tokenid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); - //fprintf(stderr,"check %s for gateway inputs\n",coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + char coinaddr[64],depositaddr[64]; int64_t threshold,nValue,price,totalinputs = 0,totalsupply,amount; + CTransaction vintx,bindtx; int32_t vout,numvouts,n = 0; uint8_t M,N,evalcode,funcid,taddr,prefix,prefix2; std::vector pubkeys; + std::vector > unspentOutputs; std::string refcoin,tmprefcoin; CPubKey withdrawpub,destpub; + uint256 tokenid,txid,oracletxid,tmpbindtxid,tmptokenid,deposittxid,hashBlock; + + if ( GetTransaction(bindtxid,bindtx,hashBlock,false) != 0 ) { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - if ( it->second.satoshis < threshold ) - continue; - for (j=0; jsecond.satoshis/COIN); - if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) - continue; - GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret); - if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> tokenid) != 0 ) + GetTokensCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + threshold = total/(maxinputs+1); + fprintf(stderr,"check %s for gateway inputs\n",coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - tokenid = revuint256(tokenid); - char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for reftokenid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,reftokenid),uint256_str(str2,tokenid),(double)vintx.vout[vout].nValue/COIN); - if ( tokenid == reftokenid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if ( it->second.satoshis < threshold ) + continue; + // for (j=0; jsecond.satoshis/COIN); - if ( total != 0 && maxinputs != 0 ) + funcid=DecodeGatewaysOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey); + if (vout==0 && funcid=='B' && bindtxid==txid && total != 0 && maxinputs != 0) + { mtx.vin.push_back(CTxIn(txid,vout,CScript())); - //nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } + else if (vout==1 && funcid=='W' && DecodeGatewaysWithdrawOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,tmptokenid,tmpbindtxid,tmprefcoin,withdrawpub,amount) == 'W' && + tmpbindtxid==bindtxid && tmprefcoin==refcoin && tmptokenid==tokenid && total != 0 && maxinputs != 0) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } + else if (vout==1 && funcid=='C' && DecodeGatewaysClaimOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,tmptokenid,tmpbindtxid,tmprefcoin,deposittxid,destpub,amount) == 'C' && + tmpbindtxid==bindtxid && tmprefcoin==refcoin && tmptokenid==tokenid && total != 0 && maxinputs != 0) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } } } + return(totalinputs); } + else fprintf(stderr,"invalid GatewaysBind\n"); } - return(totalinputs); + else fprintf(stderr,"can't find GatewaysBind txid\n"); + return(0); } -int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool! +int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) { - char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; CTransaction tx; + char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; CTransaction tx; std::vector > addressIndex; + _GetCCaddress(markeraddr,EVAL_GATEWAYS,gatewayspk); - fprintf(stderr,"bind markeraddr.(%s) need to scan mempool also\n",markeraddr); SetCCtxids(addressIndex,markeraddr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) { if ( tokenid == reftokenid ) { @@ -751,15 +791,29 @@ int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 } } } + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = txmempool.GetHash(); + + if ((numvouts=txmempool.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' && + tokenid == reftokenid) + return(1); + } + return(0); } std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr; + CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; + struct CCcontract_info *cp,*cpTokens,C,CTokens; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; + char destaddr[64],coinaddr[64],myTokenCCaddr[64],str[65],*fstr; + cp = CCinit(&C,EVAL_GATEWAYS); - if ( strcmp((char *)"KMD",coin.c_str()) == 0 ) + cpTokens = CCinit(&CTokens,EVAL_TOKENS); + if (coin=="KMD") { taddr = 0; prefix = 60; @@ -794,20 +848,21 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); + _GetCCaddress(myTokenCCaddr,EVAL_TOKENS,mypk); gatewayspk = GetUnspendable(cp,0); if ( _GetCCaddress(destaddr,EVAL_GATEWAYS,gatewayspk) == 0 ) { fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid)); return(""); } - if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply ) + if ( (fullsupply=CCfullsupply(tokenid)) != totalsupply ) { fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s totalsupply %.8f != fullsupply %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN); return(""); } - if ( CCtoken_balance(destaddr,tokenid) != totalsupply ) + if ( CCtoken_balance(myTokenCCaddr,tokenid) != totalsupply ) { - fprintf(stderr,"Gateway bind.%s (%s) destaddr.%s globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),destaddr,cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN); + fprintf(stderr,"token balance on %s %.8f != %.8f\n",myTokenCCaddr,(double)CCtoken_balance(myTokenCCaddr,tokenid)/COIN,(double)totalsupply/COIN); return(""); } if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 ) @@ -820,20 +875,24 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str()); return(""); } - if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 ) + if ( (fstr=(char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 ) { fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh"); return(""); } - if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool! + if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) { fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid)); return(""); } if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2))); + if (AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, totalsupply, 64)>0) + { + mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,totalsupply,gatewayspk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2))); + } } CCerror = strprintf("cant find enough inputs"); fprintf(stderr,"%s\n", CCerror.c_str() ); @@ -843,7 +902,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; + CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector pubkeys,publishers; std::vectortxids; char str[67],depositaddr[64],txidaddr[64]; @@ -851,14 +910,13 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cp,0); //fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size()); if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) { fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) + if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) { fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -901,7 +959,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: { mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,destpub)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',bindtxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); } fprintf(stderr,"cant find enough inputs\n"); return(""); @@ -925,7 +983,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -935,7 +993,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"cant find deposittxid %s\n",uint256_str(str,bindtxid)); return(""); } - if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,tmptxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) + if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmptxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) { fprintf(stderr,"invalid coin - deposittxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -945,32 +1003,20 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"different destination pubkey from desdeposittxid\n"); return(""); } - if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount ) + if ( (depositamount=GatewaysDepositval(tx,mypk)) != amount ) { fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); return(""); } - //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { - ///////// if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,tokenid,amount,60)) > 0 ) - if ((inputs = AddTokenCCInputs(cp, mtx, gatewayspk, tokenid, amount, 60)) > 0) + if ((inputs=AddGatewaysInputs(cp, mtx, gatewayspk, bindtxid, amount, 60)) > 0) { - if ( inputs > amount ) - CCchange = (inputs - amount); - _GetCCaddress(destaddr,EVAL_GATEWAYS,mypk); - //printf("expecting deposittxid/v0 to be to %s\n",destaddr); - mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,mypk)); // transfer back to normal token - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(mypk); // the pubkey where tokens are going (vout[0]) - - return(FinalizeCCTx(0,cp,mtx,mypk,txfee, - EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, - EncodeGatewaysClaimOpRet('t', refcoin, bindtxid, deposittxid, destpub, amount)))); // yes, 't' is passed twice + if ( inputs > amount ) CCchange = (inputs - amount); + mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,destpub)); + if ( CCchange != 0 ) mtx.vout.push_back(MakeTokensCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('C',tokenid,bindtxid,refcoin,deposittxid,destpub,amount))); } } CCerror = strprintf("cant find enough inputs or mismatched total"); @@ -981,159 +1027,377 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction tx; - CPubKey mypk, gatewayspk; - uint256 tokenid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; - std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; - struct CCcontract_info *cpGateways, gatewaysC; - struct CCcontract_info *cpTokens, tokensC; - - cpGateways = CCinit(&gatewaysC, EVAL_GATEWAYS); - cpTokens = CCinit(&tokensC, EVAL_TOKENS); + CTransaction tx; CPubKey mypk,gatewayspk,signerpk; uint256 txid,tokenid,hashBlock,oracletxid,tmptokenid,tmpbindtxid,withdrawtxid; int32_t K,vout,numvouts; + int64_t nValue,totalsupply,inputs,CCchange=0; uint8_t funcid,M,N,taddr,prefix,prefix2; std::string coin,hex; + std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; struct CCcontract_info *cp,C,*cpTokens,CTokens; + std::vector > unspentOutputs; + cp = CCinit(&C,EVAL_GATEWAYS); + cpTokens = CCinit(&CTokens,EVAL_TOKENS); if ( txfee == 0 ) txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cpGateways, 0); + gatewayspk = GetUnspendable(cp, 0); if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } + _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P')) + { + if (funcid=='W' && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)=='W' + && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + + else if (funcid=='P' && DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)=='P' && + GetTransaction(withdrawtxid,tx,hashBlock,false)!=0 && (numvouts=tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)=='W' + && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + } if( AddNormalinputs(mtx, mypk, 3*txfee, 4) > 0 ) { - /////if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,tokenid,amount,60)) > 0 ) if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0) { - if ( inputs > amount ) - CCchange = (inputs - amount); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, gatewayspk)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, txfee, gatewayspk)); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); - - char unspendableGatewaysAddr[64]; - GetCCaddress(cpGateways, unspendableGatewaysAddr, gatewayspk); - - uint8_t unspendableGatewaysPrivkey[32]; - GetUnspendable(cpGateways, unspendableGatewaysPrivkey); - - // add additional unspendable addr from Gateways: - CCaddr2set(cpTokens, EVAL_GATEWAYS, gatewayspk, unspendableGatewaysPrivkey, unspendableGatewaysAddr); - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(gatewayspk); // the pubkey where tokens are going vout[0] (and for checking the 'change' the Tokens contract will find pubkeys itself) - - return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee, - EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, - EncodeGatewaysWithdrawOpRet('W', refcoin, withdrawpub, amount)))); + if ( inputs > amount ) CCchange = (inputs - amount); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + mtx.vout.push_back(MakeTokensCC1vout(EVAL_GATEWAYS,amount,gatewayspk)); + //mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); + if ( CCchange != 0 ) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); + return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee,EncodeGatewaysWithdrawOpRet('W',tokenid,bindtxid,refcoin,withdrawpub,amount))); + } + else + { + CCerror = strprintf("not enough balance of tokens for withdraw"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - CCerror = strprintf("cant find enough token inputs or mismatched total"); - fprintf(stderr, "%s\n", CCerror.c_str()); - return(""); - } - CCerror = strprintf("cant find enough normal inputs or mismatched total"); + CCerror = strprintf("cant find enough normal inputs"); fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } -std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex) +std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx; - std::vector > unspentOutputs; char txidaddr[65]; - int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock; + CPubKey mypk,withdrawpub,signerpk,gatewayspk; struct CCcontract_info *cp,C; CTransaction tx,bindtx; + std::vector > unspentOutputs; char funcid,str[65],depositaddr[64]; + int32_t numvouts,K=0; uint256 withdrawtxid,hashBlock,bindtxid,tokenid,oracletxid,tmptokenid; std::string coin,tmphex; int64_t amount,totalsupply; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; + cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) - txfee = 5000; + txfee = 10000; mypk = pubkey2pk(Mypubkey()); - txidaddrpk=CCtxidaddr(txidaddr,txid); - SetCCunspents(unspentOutputs,txidaddr); - maxK=0; - if (unspentOutputs.size()==0) + gatewayspk = GetUnspendable(cp,0); + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) { - if (AddNormalinputs(mtx,mypk,2*txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + CCerror = strprintf("can't find last tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - else + if (funcid=='W') { - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + withdrawtxid=lasttxid; + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { - tmptxid = it->first.txhash; - if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) - { - maxK=K; - parttxid=tmptxid; - } + CCerror = strprintf("invalid withdraw tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if (maxK>0) + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) { - if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); - mtx.vin.push_back(CTxIn(parttxid,0,CScript())); + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - else fprintf(stderr,"Error finding previous partial tx\n"); } - - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,5000,txidaddrpk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',maxK+1,mypk,refcoin,hex))); + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) + { + CCerror = strprintf("can't find withdraw tx %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin) + { + CCerror = strprintf("invalid withdraw tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',withdrawtxid,refcoin,K+1,mypk,hex))); } -std::string GatewaysCompleteSigning(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,std::string hex) +std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + CPubKey mypk,gatewayspk,signerpk,withdrawpub; struct CCcontract_info *cp,C; char funcid,str[65],depositaddr[64]; int64_t amount,totalsupply; + std::string coin,tmphex; CTransaction tx,bindtx; uint256 withdrawtxid,hashBlock,tokenid,tmptokenid,bindtxid,oracletxid; int32_t K=0,numvouts; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; + cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); gatewayspk = GetUnspendable(cp,0); if ( txfee == 0 ) - txfee = 10000; - - mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); + txfee = 10000; + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) + { + CCerror = strprintf("invalid last txid %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + if (funcid=='W') + { + withdrawtxid=lasttxid; + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=tx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts=tx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + printf("aaaaaaaaaaa\n"); + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for completesigning\n"); + mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('C',refcoin,withdrawtxid,hex))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('S',withdrawtxid,refcoin,hex))); } std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + CPubKey mypk; struct CCcontract_info *cp,C; char str[65],depositaddr[64]; CTransaction tx,bindtx; int32_t numvouts; + uint256 withdrawtxid,bindtxid,oracletxid,tokenid,tmptokenid,hashBlock; std::string coin,hex; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; int64_t amount,totalsupply; CPubKey withdrawpub; + cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); if ( txfee == 0 ) txfee = 10000; + if (GetTransaction(completetxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) + { + CCerror = strprintf("invalid completesigning txid %s\n",uint256_str(str,completetxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,hex)!='S' || refcoin!=coin) + { + CCerror = strprintf("cannot decode completesigning tx opret %s\n",uint256_str(str,completetxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } mtx.vin.push_back(CTxIn(completetxid,0,CScript())); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',refcoin,completetxid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',refcoin,completetxid,withdrawtxid))); +} + +UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex,pub; + CPubKey mypk,gatewayspk,destpub; std::vector pubkeys,publishers; std::vector txids; + uint256 tmpbindtxid,hashBlock,txid,tokenid,oracletxid,cointxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[65],coinaddr[65],str[65],destaddr[65],txidaddr[65]; std::vector proof; + int32_t numvouts,vout,claimvout,height; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin) + { + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size())>0 && + DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,publishers,txids,height,cointxid,claimvout,hex,proof,destpub,amount) == 'D' + && tmpbindtxid==bindtxid && refcoin == coin && myIsutxo_spentinmempool(txid,vout) == 0) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("cointxid",uint256_str(str,cointxid))); + obj.push_back(Pair("deposittxid",uint256_str(str,txid))); + CCtxidaddr(txidaddr,txid); + obj.push_back(Pair("deposittxidaddr",txidaddr)); + _GetCCaddress(destaddr,EVAL_TOKENS,destpub); + obj.push_back(Pair("tokens_destination_address",destaddr)); + pub=HexStr(destpub); + obj.push_back(Pair("claim_pubkey",pub)); + obj.push_back(Pair("amount",(double)amount/COIN)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + pending.push_back(obj); + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("pending",pending)); + return(result); } UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 hashBlock,tokenid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; - char depositaddr[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],cctxidaddr[64],signeraddr[64]; - int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex; CPubKey mypk,gatewayspk,withdrawpub,signerpk; + std::vector msigpubkeys; uint256 hashBlock,tokenid,txid,tmpbindtxid,tmptokenid,oracletxid,withdrawtxid; uint8_t M,N,taddr,prefix,prefix2; + char funcid,depositaddr[65],coinaddr[65],tokensaddr[65],destaddr[65],str[65],withaddr[65],numstr[32],signeraddr[65],txidaddr[65]; + int32_t i,n,numvouts,vout,queueflag,K; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; std::vector > unspentOutputs; cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); gatewayspk = GetUnspendable(cp,0); _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + GetTokensCCaddress(cp,tokensaddr,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { - fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); - return(result); + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); - return(result); + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } n = msigpubkeys.size(); queueflag = 0; @@ -1149,28 +1413,45 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second.satoshis; - fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); - if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && - DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P') && myIsutxo_spentinmempool(txid,vout) == 0) { - Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); - Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); - if ( strcmp(destaddr,coinaddr) == 0 ) + if (funcid=='W') + { + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)==0 || refcoin!=coin || tmptokenid!=tokenid || tmpbindtxid!=bindtxid) continue; + } + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)!='P' || GetTransaction(withdrawtxid,tx,hashBlock,false)==0 + || (numvouts=tx.vout.size())<=0 || DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin || tmptokenid!=tokenid || tmpbindtxid!=bindtxid) + continue; + } + Getscriptaddress(destaddr,tx.vout[1].scriptPubKey); + Getscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG); + if ( strcmp(destaddr,tokensaddr) == 0 ) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("txid",uint256_str(str,txid))); - _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,txid)); - obj.push_back(Pair("txidaddr",cctxidaddr)); + obj.push_back(Pair("withdrawtxid",uint256_str(str,tx.GetHash()))); + CCtxidaddr(txidaddr,tx.GetHash()); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); obj.push_back(Pair("withdrawaddr",withaddr)); - sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN); - obj.push_back(Pair("amount",numstr)); - obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(tx.GetHash()))); if ( queueflag != 0 ) { obj.push_back(Pair("depositaddr",depositaddr)); Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG); obj.push_back(Pair("signeraddr",signeraddr)); } + if (N>1) + { + obj.push_back(Pair("number_of_signs",K)); + obj.push_back(Pair("last_txid",uint256_str(str,txid))); + if (K>0) obj.push_back(Pair("hex",hex)); + } pending.push_back(obj); } } @@ -1183,9 +1464,10 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string tmprefcoin,hex; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 withdrawtxid,hashBlock,txid,tokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; - char depositaddr[64],coinaddr[64],str[65],numstr[32],txidaddr[64],cctxidaddr[64],withaddr[64]; + UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string coin,hex; + CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; + uint256 withdrawtxid,hashBlock,txid,tokenid,tmptokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[65],coinaddr[65],str[65],numstr[32],withaddr[65],txidaddr[65]; int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; std::vector > unspentOutputs; @@ -1194,14 +1476,16 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) gatewayspk = GetUnspendable(cp,0); _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); - return(result); + { + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); - return(result); + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } n = msigpubkeys.size(); queueflag = 0; @@ -1217,20 +1501,21 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second.satoshis; - //fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && - DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,tmprefcoin,withdrawtxid,hex) == 'C' && myIsutxo_spentinmempool(txid,vout) == 0) + DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,hex) == 'S' && refcoin == coin && myIsutxo_spentinmempool(txid,vout) == 0) { - if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W') + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 + && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount) == 'W' || refcoin!=coin || tmptokenid!=tokenid) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("txid",uint256_str(str,txid))); - obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); - _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,withdrawtxid)); - obj.push_back(Pair("withdrawtxidaddr",cctxidaddr)); - Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); + obj.push_back(Pair("completesigningtxid",uint256_str(str,txid))); + obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); + CCtxidaddr(txidaddr,withdrawtxid); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); + Getscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG); obj.push_back(Pair("withdrawaddr",withaddr)); - obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); obj.push_back(Pair("hex",hex)); processed.push_back(obj); } @@ -1242,40 +1527,6 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) return(result); } -UniValue GatewaysMultisig(char *cctxidaddr) -{ - std::string parthex,hex,refcoin; uint256 txid,hashBlock; CTransaction tx; int32_t i,maxK,K,numvouts; CPubKey signerpk; - std::vector > unspentOutputs; UniValue result(UniValue::VOBJ); - - SetCCunspents(unspentOutputs,cctxidaddr); - maxK=0; - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) - { - maxK=K; - parthex=hex; - } - } - - BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) - { - const CTransaction &txmempool = e.GetTx(); - const uint256 &hash = txmempool.GetHash(); - - if ((numvouts=txmempool.vout.size()) > 0 && DecodeGatewaysPartialOpRet(txmempool.vout[numvouts-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK) - { - maxK=K; - parthex=hex; - } - } - - result.push_back(Pair("hex",parthex)); - result.push_back(Pair("number_of_signs",maxK)); - return (result); -} - UniValue GatewaysList() { UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; @@ -1286,7 +1537,7 @@ UniValue GatewaysList() txid = it->first.txhash; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) + if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) { result.push_back(uint256_str(str,txid)); } @@ -1298,16 +1549,19 @@ UniValue GatewaysList() UniValue GatewaysInfo(uint256 bindtxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaystokens[64]; + uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; + CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; + result.push_back(Pair("result","success")); result.push_back(Pair("name","Gateways")); cp = CCinit(&C,EVAL_GATEWAYS); Gatewayspk = GetUnspendable(cp,0); - _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); + GetTokensCCaddress(cp,gatewaystokens,Gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) { depositaddr[0] = 0; - if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 ) + if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 ) { if ( N > 1 ) { @@ -1326,7 +1580,7 @@ UniValue GatewaysInfo(uint256 bindtxid) result.push_back(Pair("tokenid",uint256_str(str,tokenid))); sprintf(numstr,"%.8f",(double)totalsupply/COIN); result.push_back(Pair("totalsupply",numstr)); - remaining = CCtoken_balance(gatewaysassets,tokenid); + remaining = CCtoken_balance(gatewaystokens,tokenid); sprintf(numstr,"%.8f",(double)remaining/COIN); result.push_back(Pair("remaining",numstr)); sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 82a400e71..208b3cf02 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -478,9 +478,9 @@ static const CRPCCommand vRPCCommands[] = { "gateways", "gatewayspartialsign", &gatewayspartialsign, true }, { "gateways", "gatewayscompletesigning", &gatewayscompletesigning, true }, { "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true }, - { "gateways", "gatewayspending", &gatewayspending, true }, + { "gateways", "gatewayspendingdeposits", &gatewayspendingdeposits, true }, + { "gateways", "gatewayspendingwithdraws", &gatewayspendingwithdraws, true }, { "gateways", "gatewaysprocessed", &gatewaysprocessed, true }, - { "gateways", "gatewaysmultisig", &gatewaysmultisig, true }, // dice { "dice", "dicelist", &dicelist, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 3edc85ebf..b812ccc9d 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -300,9 +300,9 @@ extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp); extern UniValue gatewayspartialsign(const UniValue& params, bool fHelp); extern UniValue gatewayscompletesigning(const UniValue& params, bool fHelp); extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp); -extern UniValue gatewayspending(const UniValue& params, bool fHelp); +extern UniValue gatewayspendingdeposits(const UniValue& params, bool fHelp); +extern UniValue gatewayspendingwithdraws(const UniValue& params, bool fHelp); extern UniValue gatewaysprocessed(const UniValue& params, bool fHelp); -extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp); extern UniValue channelslist(const UniValue& params, bool fHelp); extern UniValue channelsinfo(const UniValue& params, bool fHelp); extern UniValue channelsopen(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e111ad98a..0ffc370e2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6263,11 +6263,23 @@ UniValue gatewaysmarkdone(const UniValue& params, bool fHelp) return(result); } -UniValue gatewayspending(const UniValue& params, bool fHelp) +UniValue gatewayspendingdeposits(const UniValue& params, bool fHelp) { uint256 bindtxid; std::string coin; if ( fHelp || params.size() != 2 ) - throw runtime_error("gatewayspending bindtxid coin\n"); + throw runtime_error("gatewayspendingdeposits bindtxid coin\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + return(GatewaysPendingDeposits(bindtxid,coin)); +} + +UniValue gatewayspendingwithdraws(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("gatewayspendingwithdraws bindtxid coin\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); bindtxid = Parseuint256((char *)params[0].get_str().c_str()); @@ -6287,19 +6299,6 @@ UniValue gatewaysprocessed(const UniValue& params, bool fHelp) return(GatewaysProcessedWithdraws(bindtxid,coin)); } -UniValue gatewaysmultisig(const UniValue& params, bool fHelp) -{ - UniValue result(UniValue::VOBJ); std::string hex; char *txidaddr; - if ( fHelp || params.size() != 1 ) - throw runtime_error("gatewaysmultisig txidaddr\n"); - if ( ensure_CCrequirements() < 0 ) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - txidaddr = (char *)params[0].get_str().c_str(); - return(GatewaysMultisig(txidaddr)); -} - UniValue oracleslist(const UniValue& params, bool fHelp) { if ( fHelp || params.size() > 0 )