diff --git a/BitcoinUnlimited-bucash1.3.0.1/src/consensus/tx_verify.cpp b/BitcoinUnlimited-bucash1.3.0.1/src/consensus/tx_verify.cpp index 08d522d..35ce575 100644 --- a/BitcoinUnlimited-bucash1.3.0.1/src/consensus/tx_verify.cpp +++ b/BitcoinUnlimited-bucash1.3.0.1/src/consensus/tx_verify.cpp @@ -219,7 +219,8 @@ bool Consensus::CheckTxInputs(const CTransaction &tx, CValidationState &state, c std::map mVinToken; std::map mVoutToken; - std::vector vTxid; + // verify token issue txid + std::vector vTxid; std::vector vTokenid; for (unsigned int i = 0; i < tx.vin.size(); i++) @@ -246,42 +247,26 @@ bool Consensus::CheckTxInputs(const CTransaction &tx, CValidationState &state, c // Token // verify token CScript prevPubkey = coin.out.scriptPubKey; - if (prevPubkey.IsPayToScriptHash()) - { - std::vector vec(prevPubkey.begin() + 2, prevPubkey.begin() + 22); - CScriptID hash = CScriptID(uint160(vec)); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - { - if (!redeemScript.IsPayToToken()) - continue; - - int namesize = redeemScript[1]; - int amountsize = redeemScript[2 + namesize]; - std::vector vecName(redeemScript.begin() + 2, redeemScript.begin() + 2 + namesize); - std::vector vecAmount(redeemScript.begin() + 3 + namesize, redeemScript.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - if (tokenAmount > MAX_TOKEN_SUPPLY) - return state.DoS(100, false, REJECT_INVALID, "token amount out of range"); - - CAmount temp = mVinToken[tokenName]; - temp += tokenAmount; - if (temp > MAX_TOKEN_SUPPLY) - return state.DoS(100, false, REJECT_INVALID, "vin amount out of range"); - mVinToken[tokenName] = temp; - } - } - else if (prevPubkey.IsPayToToken()) + if (prevPubkey.IsPayToToken()) { int namesize = prevPubkey[1]; int amountsize = prevPubkey[2 + namesize]; std::vector vecName(prevPubkey.begin() + 2, prevPubkey.begin() + 2 + namesize); - std::vector vecAmount(prevPubkey.begin() + 3 + namesize, prevPubkey.begin() + 3 + namesize + amountsize); std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - mVinToken[tokenName] = tokenAmount; - + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(prevPubkey.begin() + 2 + namesize, prevPubkey.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(prevPubkey.begin() + 3 + namesize, prevPubkey.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + if (tokenAmount > MAX_TOKEN_SUPPLY) return state.DoS(100, false, REJECT_INVALID, "token amount out of range"); @@ -306,9 +291,20 @@ bool Consensus::CheckTxInputs(const CTransaction &tx, CValidationState &state, c std::vector vecName(outScript.begin() + 2, outScript.begin() + 2 + namesize); std::string name(vecName.begin(), vecName.end()); - - std::vector vec(outScript.begin() + 3 + namesize, outScript.begin() + 3 + namesize + amountsize); - CAmount amount = CScriptNum(vec, true).getint64(); + + // check opcode or scriptnum + CAmount amount = 0; + std::vector opcode(outScript.begin() + 2 + namesize, outScript.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + amount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(outScript.begin() + 3 + namesize, outScript.begin() + 3 + namesize + amountsize); + amount = CScriptNum(vec, true).getint64(); + } + if (amount > MAX_TOKEN_SUPPLY) return state.DoS(100, false, REJECT_INVALID, "token amount out of range"); @@ -345,7 +341,6 @@ bool Consensus::CheckTxInputs(const CTransaction &tx, CValidationState &state, c // if (!issue) // return state.DoS(100, false, REJECT_INVALID, "tokenid must be one of the issuer's UTXO txid"); // } - // verify token end if (nValueIn < tx.GetValueOut()) return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, diff --git a/BitcoinUnlimited-bucash1.3.0.1/src/rpc/rawtransaction.cpp b/BitcoinUnlimited-bucash1.3.0.1/src/rpc/rawtransaction.cpp index 0ff4c29..b62333b 100644 --- a/BitcoinUnlimited-bucash1.3.0.1/src/rpc/rawtransaction.cpp +++ b/BitcoinUnlimited-bucash1.3.0.1/src/rpc/rawtransaction.cpp @@ -1073,10 +1073,21 @@ UniValue GetAccountInfo(const std::string &account) int namesize = pk[1]; int amountsize = pk[2 + namesize]; std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + entry.push_back(Pair("token", tokenName)); entry.push_back(Pair("tokenAmount", tokenAmount)); unspentToken.push_back(entry); @@ -1142,7 +1153,7 @@ UniValue getaccountinfo(const UniValue ¶ms, bool fHelp) return GetAccountInfo(account); } -bool SignTokenTx(CMutableTransaction &rawTx) +bool SignTokenTx(CMutableTransaction &rawTx, UniValue &vErrors) { // Fetch previous transactions (inputs): CCoinsView viewDummy; @@ -1187,9 +1198,6 @@ bool SignTokenTx(CMutableTransaction &rawTx) bool fHashSingle = ((nHashType & ~(SIGHASH_ANYONECANPAY | SIGHASH_FORKID)) == SIGHASH_SINGLE); - // Script verification errors - UniValue vErrors(UniValue::VARR); - // Use CTransaction for the constant parts of the // transaction to avoid rehashing. const CTransaction txConst(rawTx); @@ -1238,9 +1246,7 @@ bool SignTokenTx(CMutableTransaction &rawTx) } } - if (!vErrors.empty()) - return false; - return true; + return vErrors.empty(); } void SendTokenTx(const CMutableTransaction &rawTx) @@ -1281,6 +1287,65 @@ void SendTokenTx(const CMutableTransaction &rawTx) RelayTransaction(rawTx); } +opcodetype GetOpcode(const CAmount n) +{ + opcodetype ret = OP_1; + switch (n) + { + case 1: + ret = OP_1; + break; + case 2: + ret = OP_2; + break; + case 3: + ret = OP_3; + break; + case 4: + ret = OP_4; + break; + case 5: + ret = OP_5; + break; + case 6: + ret = OP_6; + break; + case 7: + ret = OP_7; + break; + case 8: + ret = OP_8; + break; + case 9: + ret = OP_9; + break; + case 10: + ret = OP_10; + break; + case 11: + ret = OP_11; + break; + case 12: + ret = OP_12; + break; + case 13: + ret = OP_13; + break; + case 14: + ret = OP_14; + break; + case 15: + ret = OP_15; + break; + case 16: + ret = OP_16; + break; + default: + break; + } + return ret; +} + UniValue tokenmint(const UniValue ¶ms, bool fHelp) { if (fHelp || params.size() != 3) @@ -1367,7 +1432,13 @@ UniValue tokenmint(const UniValue ¶ms, bool fHelp) // build token script CTxDestination destination = DecodeDestination(addresses[0].get_str()); CScript scriptPubKey = GetScriptForDestination(destination); - CScript script = CScript() << OP_TOKEN << ToByteVector(tokenname) << CScriptNum(nSupply); + + CScript script; + if (nSupply < 17) + script = CScript() << OP_TOKEN << ToByteVector(tokenname) << GetOpcode(nSupply); + else + script = CScript() << OP_TOKEN << ToByteVector(tokenname) << CScriptNum(nSupply); + script << OP_DROP << OP_DROP; script += scriptPubKey; @@ -1393,10 +1464,11 @@ UniValue tokenmint(const UniValue ¶ms, bool fHelp) rawTx.vout.push_back(chargeOut); } + UniValue vErrors(UniValue::VARR); // sign tx - if (!SignTokenTx(rawTx)) + if (!SignTokenTx(rawTx, vErrors)) { - result.push_back(Pair("error", 4)); + result.push_back(Pair("error", vErrors)); return result; } @@ -1409,11 +1481,12 @@ UniValue tokenmint(const UniValue ¶ms, bool fHelp) return result; } + UniValue tokentransfer(const UniValue ¶ms, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( - "tokentransfer \"token\" \"account\" [{\"address\":\"xxxx\", \"amount\":n},...] \n" + "tokentransfer \"token\" \"account\" [{\"address\":\"xxxx\", \"amount\":\"1111\"},...] \n" "\nCreate a transaction to transfer token.\n" "Returns hex-encoded raw transaction.\n" @@ -1478,6 +1551,12 @@ UniValue tokentransfer(const UniValue ¶ms, bool fHelp) return result; } CAmount n = atoll(obj["amount"].get_str().c_str()); + if (n < 1) + { + // amount < 1, return error + result.push_back(Pair("error", 3)); + return result; + } nVoutToken += n; } @@ -1490,11 +1569,13 @@ UniValue tokentransfer(const UniValue ¶ms, bool fHelp) for (size_t i = 0; i < utxoToken.size(); ++i) { UniValue u = utxoToken[i]; + if (u["token"].get_str() != token) + continue; + uint256 txid; txid.SetHex(u["txid"].get_str()); CTxIn in(COutPoint(txid, u["vout"].get_int()), CScript(), nSequence); rawTx.vin.push_back(in); - nVinToken += u["tokenAmount"].get_int64(); if (nVinToken >= nVoutToken) break; @@ -1542,7 +1623,14 @@ UniValue tokentransfer(const UniValue ¶ms, bool fHelp) std::string address = output["address"].get_str(); CAmount n = atoll(output["amount"].get_str().c_str()); CTxDestination destination = DecodeDestination(address); - CScript scriptPubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(n) << OP_DROP << OP_DROP; + + CScript scriptPubKey; + if (n < 17) + scriptPubKey = CScript() << OP_TOKEN << ToByteVector(token) << GetOpcode(n) << OP_DROP << OP_DROP; + else + scriptPubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(n) << OP_DROP << OP_DROP; + + // CScript scriptPubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(n) << OP_DROP << OP_DROP; scriptPubKey += GetScriptForDestination(destination); CTxOut out(defaultTransferFee, scriptPubKey); rawTx.vout.push_back(out); @@ -1553,7 +1641,14 @@ UniValue tokentransfer(const UniValue ¶ms, bool fHelp) // token charge if (nVinToken > nVoutToken) { - CScript chargePubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(nVinToken - nVoutToken) << OP_DROP << OP_DROP; + CAmount n = nVinToken - nVoutToken; + CScript chargePubKey; + if (n < 17) + chargePubKey = CScript() << OP_TOKEN << ToByteVector(token) << GetOpcode(n) << OP_DROP << OP_DROP; + else + chargePubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(n) << OP_DROP << OP_DROP; + + // CScript chargePubKey = CScript() << OP_TOKEN << ToByteVector(token) << CScriptNum(nVinToken - nVoutToken) << OP_DROP << OP_DROP; chargePubKey += GetScriptForDestination(chargeDest); CTxOut out(defaultTransferFee, chargePubKey); rawTx.vout.push_back(out); @@ -1567,10 +1662,12 @@ UniValue tokentransfer(const UniValue ¶ms, bool fHelp) rawTx.vout.push_back(out); } + UniValue vErrors(UniValue::VARR); // sign tx - if (!SignTokenTx(rawTx)) + if (!SignTokenTx(rawTx, vErrors)) { - result.push_back(Pair("error", 4)); + result.push_back(Pair("error", vErrors)); + result.push_back(Pair("hex", EncodeHexTx(rawTx))); return result; } @@ -1593,45 +1690,67 @@ UniValue tokenlist(const UniValue ¶ms, bool fHelp) UniValue result(UniValue::VARR); std::set sToken; + int height = chainActive.Height(); + CBlockIndex *pblockindex = NULL; - for (auto it: pwalletMain->mapWallet) + for (int i = 100; i <= height; ++i) { - const CWalletTx &wtx = it.second; - if (wtx.IsCoinBase()) - continue; - - for (const auto &out: wtx.vout) - { - const CScript &pk = out.scriptPubKey; - if (pk.IsPayToToken()) - { - int namesize = pk[1]; - int amountsize = pk[2 + namesize]; - std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); + pblockindex = chainActive[i]; + CBlock block; + if (ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + { + for (const auto &tx: block.vtx) + { + if (tx->IsCoinBase()) + continue; - if (sToken.count(tokenName)) - continue; - else - sToken.insert(tokenName); - - UniValue entry(UniValue::VOBJ); - // entry.push_back(Pair("txid", it.first.ToString())); - CTxDestination address; - if (ExtractDestination(pk, address)) - { - // entry.push_back(Pair("address", EncodeDestination(address))); - if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); - } - entry.push_back(Pair("token", tokenName)); - entry.push_back(Pair("supply", tokenAmount)); - result.push_back(entry); - } - } + for (const auto &out: tx->vout) + { + const CScript &pk = out.scriptPubKey; + if (pk.IsPayToToken()) + { + int namesize = pk[1]; + int amountsize = pk[2 + namesize]; + std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); + std::string tokenName(vecName.begin(), vecName.end()); + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + + if (sToken.count(tokenName)) + continue; + else + sToken.insert(tokenName); + + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", tx->GetHash().GetHex())); + CTxDestination address; + if (ExtractDestination(pk, address)) + { + entry.push_back(Pair("address", EncodeDestination(address))); + if (pwalletMain->mapAddressBook.count(address)) + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + } + entry.push_back(Pair("token", tokenName)); + entry.push_back(Pair("supply", tokenAmount)); + result.push_back(entry); + } + } + + } + } } + return result; } @@ -1665,9 +1784,20 @@ UniValue tokensearch(const UniValue ¶ms, bool fHelp) int namesize = pk[1]; int amountsize = pk[2 + namesize]; std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } CTxDestination address; std::string issuer = ""; @@ -1708,7 +1838,7 @@ UniValue tokensearch(const UniValue ¶ms, bool fHelp) return result; } -UniValue GetAccountTokenAddress(const std::string &account) +UniValue GetTokenAddress(const std::string &account, const std::string &token) { LOCK2(cs_main, pwalletMain->cs_wallet); assert(pwalletMain != NULL); @@ -1733,19 +1863,33 @@ UniValue GetAccountTokenAddress(const std::string &account) const CScript &pk = out.tx->vout[out.i].scriptPubKey; if (pk.IsPayToToken()) { + int namesize = pk[1]; + int amountsize = pk[2 + namesize]; + std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); + std::string tokenName(vecName.begin(), vecName.end()); + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + + if (tokenName != token) + continue; + UniValue entry(UniValue::VOBJ); CTxDestination address; if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { entry.push_back(Pair("address", EncodeDestination(address))); - } - int namesize = pk[1]; - int amountsize = pk[2 + namesize]; - std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - + } entry.push_back(Pair("token", tokenName)); entry.push_back(Pair("amount", tokenAmount)); result.push_back(entry); @@ -1756,18 +1900,19 @@ UniValue GetAccountTokenAddress(const std::string &account) UniValue tokenaddress(const UniValue ¶ms, bool fHelp) { - if (fHelp || params.size() != 1) + if (fHelp || params.size() != 2) throw runtime_error( - "tokenaddress \"account\" \n" + "tokenaddress \"account\" \"token\"\n" "\nList the addresses that contains token.\n" "Returns address list.\n"); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR), true); - if (params[0].isNull()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, argument must be non-null"); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR), true); + if (params[0].isNull() || params[1].isNull()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameters, arguments must be non-null"); std::string account = params[0].get_str(); - return GetAccountTokenAddress(account); + std::string token = params[1].get_str(); + return GetTokenAddress(account, token); } void ListTokenTransactions(const CWalletTx &wtx, @@ -1873,9 +2018,20 @@ UniValue tokenhistory(const UniValue ¶ms, bool fHelp) int namesize = pk[1]; int amountsize = pk[2 + namesize]; std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); std::string tokenName(vecName.begin(), vecName.end()); - CAmount amount = CScriptNum(vecAmount, true).getint64(); + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } if (tokenName != token) continue; @@ -1894,7 +2050,7 @@ UniValue tokenhistory(const UniValue ¶ms, bool fHelp) UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", it.first.ToString())); entry.push_back(Pair("address", EncodeDestination(address))); - entry.push_back(Pair("amount", amount)); + entry.push_back(Pair("amount", tokenAmount)); entry.push_back(Pair("category", "receive")); entry.push_back(Pair("timestamp", wtx.GetTxTime())); result.push_back(entry); @@ -1918,9 +2074,20 @@ UniValue tokenhistory(const UniValue ¶ms, bool fHelp) int namesize = pk[1]; int amountsize = pk[2 + namesize]; std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); std::string tokenName(vecName.begin(), vecName.end()); - CAmount amount = CScriptNum(vecAmount, true).getint64(); + + // check opcode or scriptnum + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } if (tokenName != token) continue; @@ -1939,7 +2106,7 @@ UniValue tokenhistory(const UniValue ¶ms, bool fHelp) UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", it.first.ToString())); entry.push_back(Pair("address", EncodeDestination(address))); - entry.push_back(Pair("amount", amount)); + entry.push_back(Pair("amount", tokenAmount)); entry.push_back(Pair("category", "send")); entry.push_back(Pair("timestamp", wtx.GetTxTime())); result.push_back(entry); @@ -2007,10 +2174,21 @@ UniValue tokendetail(const UniValue ¶ms, bool fHelp) int namesize = pk[1]; int amountsize = pk[2 + namesize]; std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); std::string name(vecName.begin(), vecName.end()); - CAmount amount = CScriptNum(vecAmount, true).getint64(); + // check opcode or scriptnum + CAmount amount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + amount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + amount = CScriptNum(vec, true).getint64(); + } + UniValue entry(UniValue::VOBJ); CTxDestination address; if (ExtractDestination(pk, address)) @@ -2038,8 +2216,19 @@ UniValue tokendetail(const UniValue ¶ms, bool fHelp) { int namesize = pk[1]; int amountsize = pk[2 + namesize]; - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); - CAmount amount = CScriptNum(vecAmount, true).getint64(); + + // check opcode or scriptnum + CAmount amount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + amount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + amount = CScriptNum(vec, true).getint64(); + } UniValue entry(UniValue::VOBJ); CTxDestination address; diff --git a/BitcoinUnlimited-bucash1.3.0.1/src/script/standard.cpp b/BitcoinUnlimited-bucash1.3.0.1/src/script/standard.cpp index d7e8b1e..86db4b0 100644 --- a/BitcoinUnlimited-bucash1.3.0.1/src/script/standard.cpp +++ b/BitcoinUnlimited-bucash1.3.0.1/src/script/standard.cpp @@ -96,7 +96,7 @@ bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, vector hashBytes(scriptPubKey.end() - 22, scriptPubKey.end() - 2); + vector hashBytes(scriptPubKey.end() - 22, scriptPubKey.end() - 2); vSolutionsRet.push_back(hashBytes); return true; } diff --git a/BitcoinUnlimited-bucash1.3.0.1/src/wallet/rpcwallet.cpp b/BitcoinUnlimited-bucash1.3.0.1/src/wallet/rpcwallet.cpp index 1aaf075..e6ded2f 100644 --- a/BitcoinUnlimited-bucash1.3.0.1/src/wallet/rpcwallet.cpp +++ b/BitcoinUnlimited-bucash1.3.0.1/src/wallet/rpcwallet.cpp @@ -693,7 +693,6 @@ CAmount GetAccountBalance(CWalletDB &walletdb, const string &strAccount, int nMi if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) nBalance += nReceived; nBalance -= nSent + nFee; - std::cout << "balance: " << nBalance << std::endl; } // Tally internal accounting entries @@ -768,7 +767,7 @@ UniValue getbalance(const UniValue ¶ms, bool fHelp) list listReceived; list listSent; wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); - if (wtx.GetDepthInMainChain() >= nMinDepth) + if (wtx.GetDepthInMainChain() >= nMinDepth) { BOOST_FOREACH (const COutputEntry &r, listReceived) nBalance += r.amount; @@ -2807,70 +2806,41 @@ UniValue listtokenunspent(const UniValue ¶ms, bool fHelp) CAmount nValue = out.tx->vout[out.i].nValue; const CScript &pk = out.tx->vout[out.i].scriptPubKey; - if (pk.IsPayToScriptHash()) - { - CTxDestination address; - if (ExtractDestination(pk, address)) - { - const CScriptID &hash = boost::get(address); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - { - if (!redeemScript.IsPayToToken()) - continue; - - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); - CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - entry.push_back(Pair("address", EncodeDestination(address))); - - entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); - entry.push_back(Pair("satoshi", UniValue(nValue))); - entry.push_back(Pair("amount", ValueFromAmount(nValue))); - entry.push_back(Pair("confirmations", out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - - int namesize = redeemScript[1]; - int amountsize = redeemScript[2 + namesize]; - std::vector vecName(redeemScript.begin() + 2, redeemScript.begin() + 2 + namesize); - std::vector vecAmount(redeemScript.begin() + 3 + namesize, redeemScript.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - - entry.push_back(Pair("token", tokenName)); - entry.push_back(Pair("tokenAmount", tokenAmount)); - results.push_back(entry); - } - } - } - else if (pk.IsPayToToken()) - { - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); - CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - entry.push_back(Pair("address", EncodeDestination(address))); - entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); - entry.push_back(Pair("satoshi", UniValue(nValue))); - entry.push_back(Pair("amount", ValueFromAmount(nValue))); - entry.push_back(Pair("confirmations", out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - - int namesize = pk[1]; - int amountsize = pk[2 + namesize]; - std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); - std::vector vecAmount(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - - entry.push_back(Pair("token", tokenName)); - entry.push_back(Pair("tokenAmount", tokenAmount)); - results.push_back(entry); - } + if (pk.IsPayToToken()) + { + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); + entry.push_back(Pair("vout", out.i)); + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + entry.push_back(Pair("address", EncodeDestination(address))); + entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + entry.push_back(Pair("satoshi", UniValue(nValue))); + entry.push_back(Pair("amount", ValueFromAmount(nValue))); + entry.push_back(Pair("confirmations", out.nDepth)); + entry.push_back(Pair("spendable", out.fSpendable)); + + int namesize = pk[1]; + int amountsize = pk[2 + namesize]; + std::vector vecName(pk.begin() + 2, pk.begin() + 2 + namesize); + std::string tokenName(vecName.begin(), vecName.end()); + + CAmount tokenAmount = 0; + std::vector opcode(pk.begin() + 2 + namesize, pk.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(pk.begin() + 3 + namesize, pk.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + + entry.push_back(Pair("token", tokenName)); + entry.push_back(Pair("tokenAmount", tokenAmount)); + results.push_back(entry); + } } return results; } diff --git a/BitcoinUnlimited-bucash1.3.0.1/src/wallet/wallet.cpp b/BitcoinUnlimited-bucash1.3.0.1/src/wallet/wallet.cpp index d98736d..2f2ce68 100644 --- a/BitcoinUnlimited-bucash1.3.0.1/src/wallet/wallet.cpp +++ b/BitcoinUnlimited-bucash1.3.0.1/src/wallet/wallet.cpp @@ -1495,6 +1495,11 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const if (!pwallet->IsSpent(hashTx, i)) { const CTxOut &txout = vout[i]; + + // Token + if (txout.scriptPubKey.IsPayToToken()) + continue; + nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAvailableCredit(false) : value out of range"); @@ -1530,41 +1535,32 @@ std::map CWalletTx::GetTokenAvailableCredit() const if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetTokenAvailableCredit() : value out of range"); - if (nCredit == tmpCredit) + if (nCredit == tmpCredit) continue; - tmpCredit = nCredit; - if (txout.scriptPubKey.IsPayToScriptHash()) - { - CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address)) - { - const CScriptID &hash = boost::get(address); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - { - if (!redeemScript.IsPayToToken()) - continue; - int namesize = redeemScript[1]; - int amountsize = redeemScript[2 + namesize]; - std::vector vecName(redeemScript.begin() + 2, redeemScript.begin() + 2 + namesize); - std::vector vecAmount(redeemScript.begin() + 3 + namesize, redeemScript.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - mCredit[tokenName] = tokenAmount; - } - } - } - else if (txout.scriptPubKey.IsPayToToken()) + tmpCredit = nCredit; + if (txout.scriptPubKey.IsPayToToken()) { - int namesize = txout.scriptPubKey[1]; - int amountsize = txout.scriptPubKey[2 + namesize]; - std::vector vecName(txout.scriptPubKey.begin() + 2, txout.scriptPubKey.begin() + 2 + namesize); - std::vector vecAmount(txout.scriptPubKey.begin() + 3 + namesize, txout.scriptPubKey.begin() + 3 + namesize + amountsize); - std::string tokenName(vecName.begin(), vecName.end()); - CAmount tokenAmount = CScriptNum(vecAmount, true).getint64(); - mCredit[tokenName] = tokenAmount; - } + int namesize = txout.scriptPubKey[1]; + int amountsize = txout.scriptPubKey[2 + namesize]; + std::vector vecName(txout.scriptPubKey.begin() + 2, txout.scriptPubKey.begin() + 2 + namesize); + std::vector vecAmount(txout.scriptPubKey.begin() + 3 + namesize, txout.scriptPubKey.begin() + 3 + namesize + amountsize); + std::string tokenName(vecName.begin(), vecName.end()); + + CAmount tokenAmount = 0; + std::vector opcode(txout.scriptPubKey.begin() + 2 + namesize, txout.scriptPubKey.begin() + 3 + namesize); + if (0x50 < opcode.at(0) && opcode.at(0) < 0x61) + { + tokenAmount = opcode.at(0) - 0x50; + } + else + { + std::vector vec(txout.scriptPubKey.begin() + 3 + namesize, txout.scriptPubKey.begin() + 3 + namesize + amountsize); + tokenAmount = CScriptNum(vec, true).getint64(); + } + + mCredit[tokenName] = tokenAmount; + } } } @@ -2078,6 +2074,19 @@ bool CWallet::SelectCoins(const CAmount &nTargetValue, vector vCoins; AvailableCoins(vCoins, true, coinControl); + // Token + std::vector tmp; + for (const COutput &output: vCoins) + { + if (output.tx->vout[output.i].scriptPubKey.IsPayToToken()) + { + continue; + } + tmp.push_back(output); + } + vCoins.clear(); + vCoins.assign(tmp.begin(), tmp.end()); + // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) { @@ -2321,6 +2330,7 @@ bool CWallet::CreateTransaction(const vector &vecSend, strFailReason = _("Insufficient funds"); return false; } + BOOST_FOREACH (PAIRTYPE(const CWalletTx *, unsigned int) pcoin, setCoins) { CAmount nCredit = pcoin.first->vout[pcoin.second].nValue; diff --git a/Token_Wallet_API.pdf b/Token_Wallet_API.pdf index 34442c7..d01169c 100644 Binary files a/Token_Wallet_API.pdf and b/Token_Wallet_API.pdf differ