From 40748df5054e043880952fc29cc9e72f574b72f6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 01:33:13 -0700 Subject: [PATCH 1/8] Store completed transactions in the SQL database, indexed by accounts affected and ledger seq. --- src/LedgerConsensus.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 72190d24a0..bd15efe5f9 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -654,6 +654,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) Log(lsDEBUG) << "Previous LCL " << mPreviousLedger->getHash().GetHex(); Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); + uint32 newLedgerSeq = newLCL->getLedgerSeq(); #ifdef DEBUG Json::StyledStreamWriter ssw; @@ -707,6 +708,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, failedTransactions); theApp->getMasterLedger().pushLedger(newLCL, newOL); mState = lcsACCEPTED; + sl.unlock(); #ifdef DEBUG if (1) @@ -718,8 +720,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) } #endif - sl.unlock(); - SerializedValidation v(newLCLHash, mOurPosition->peekKey(), true); std::vector validation = v.getSigned(); newcoin::TMValidation val; @@ -727,6 +727,34 @@ void LedgerConsensus::accept(SHAMap::pointer set) theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); Log(lsINFO) << "Validation sent " << newLCL->getHash().GetHex(); statusChange(newcoin::neACCEPTED_LEDGER, newOL); + + // Insert the transactions in set into the AcctTxn database + Database *db = theApp->getAcctTxnDB()->getDB(); + ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); + db->executeSQL("BEGIN TRANSACTION"); + for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) + { + SerializerIterator sit(item->peekSerializer()); + SerializedTransaction txn(sit); + std::vector accts = txn.getAffectedAccounts(); + + std::string sql = "INSERT INTO AccountTransactions (TransID,Account,LedgerSeq) VALUES "; + bool first = true; + for (std::vector::iterator it = accts.begin(), end = accts.end(); it != end; ++it) + { + if (!first) sql += ", ("; + else sql += "("; + sql += txn.getTransactionID().GetHex(); + sql += ","; + sql += it->humanAccountID(); + sql += ","; + sql += boost::lexical_cast(newLedgerSeq); + sql += ")"; + } + sql += ";"; + db->executeSQL(sql); + } + db->executeSQL("COMMIT TRANSACTION"); } void LedgerConsensus::endConsensus() From 5dcc7908dd7d759467b23bfd5c2909220e1ee926 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 01:49:18 -0700 Subject: [PATCH 2/8] ledger [id|current|lastclosed] [full] Implementation is not 100% complete yet. --- src/Ledger.h | 1 + src/RPCServer.cpp | 44 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Ledger.h b/src/Ledger.h index 9d82641295..cb9c4cfd15 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -35,6 +35,7 @@ enum LedgerStateParms #define LEDGER_JSON_DUMP_TXNS 0x10000000 #define LEDGER_JSON_DUMP_STATE 0x20000000 +#define LEDGER_JSON_FULL 0x40000000 class Ledger : public boost::enable_shared_from_this { // The basic Ledger structure, can be opened, closed, or synching diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b071c83c82..f325ce6a81 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1410,10 +1410,20 @@ Json::Value RPCServer::doTx(Json::Value& params) return JSONRPCError(501, "not implemented"); } -// ledger +// ledger [id|current|lastclosed] [full] Json::Value RPCServer::doLedger(Json::Value& params) { - if (getParamCount(params)== 0) + + if (params.size() > 2) + { + return "invalid params"; + } + else if (!mNetOps->available()) + { + return JSONRPCError(503, "network not available"); + } + + if (getParamCount(params) == 0) { Json::Value ret(Json::objectValue), current(Json::objectValue), closed(Json::objectValue); theApp->getMasterLedger().getCurrentLedger()->addJson(current, 0); @@ -1423,7 +1433,35 @@ Json::Value RPCServer::doLedger(Json::Value& params) return ret; } - return JSONRPCError(501, "not implemented"); + std::string param; + if (!extractString(param, params, 0)) + { + return "bad params"; + } + + Ledger::pointer ledger; + if (param == "current") + ledger = theApp->getMasterLedger().getCurrentLedger(); + else if (param == "lastclosed") + ledger = theApp->getMasterLedger().getClosedLedger(); + else if (param.size() > 12) + ledger = theApp->getMasterLedger().getLedgerByHash(uint256(param)); + else + ledger = theApp->getMasterLedger().getLedgerBySeq(boost::lexical_cast(param)); + + if (!ledger) + return JSONRPCError(503, "Unable to locate ledger"); + + bool full = false; + if (extractString(param, params, 1)) + { + if (param == "full") + full = true; + } + + Json::Value ret(Json::objectValue); + ledger->addJson(ret, full ? LEDGER_JSON_FULL : 0); + return ret; } // unl_add | [] From 424582a2193c9c9885dae5f0d4402ed61ea48598 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 01:50:52 -0700 Subject: [PATCH 3/8] Dead code. --- src/Hanko.cpp | 12 ---------- src/Hanko.h | 65 --------------------------------------------------- 2 files changed, 77 deletions(-) delete mode 100644 src/Hanko.cpp delete mode 100644 src/Hanko.h diff --git a/src/Hanko.cpp b/src/Hanko.cpp deleted file mode 100644 index 4c2bb25b81..0000000000 --- a/src/Hanko.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "Hanko.h" - -#include - -using namespace boost; -using namespace std; - -Hanko::Hanko() -{ -} - -// vim:ts=4 diff --git a/src/Hanko.h b/src/Hanko.h deleted file mode 100644 index 4a1079a5b8..0000000000 --- a/src/Hanko.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef __HANKO__ -#define __HANKO__ - -// We use SECP256K1 http://www.secg.org/collateral/sec2_final.pdf - -#include "key.h" - -enum HankoFormat -{ - TEXT, // Hanko in text form - RAW, // Hanko in raw binary form - CONTACT, // Hanko contact block -}; - - -class Hanko -{ -public: - static const int smPubKeySize= 65; - static const int smPrivKeySize = 279; - static const int smSigSize = 57; - -private: - std::string mHanko; - std::vector mContactBlock; - CKey mPubKey; - -public: - Hanko(); - Hanko(const std::string& TextHanko); - Hanko(const std::vector& Data, HankoFormat format); - Hanko(const CKey &pubKey); - Hanko(const Hanko &); - - std::string GetHankoString(HankoFormat format) const; - std::vector GetHankoBinary(HankoFormat format) const; - - const std::vector& GetContactBlock() const { return mContactBlock; } - const CKey& GetPublicKey() const { return mPubKey; } - - int UpdateContact(std::vector& Contact); - - bool CheckHashSign(const uint256& hash, const std::vector& Signature); - bool CheckPrefixSign(const std::vector& data, uint64 type, - const std::vector &signature); -}; - - -class LocalHanko : public Hanko -{ -private: - CKey mPrivKey; - -public: - LocalHanko(std::vector &PrivKey); - LocalHanko(const CKey &Privkey); - LocalHanko(const LocalHanko &); - ~LocalHanko(); - - bool HashSign(const uint256& hash, std::vector& Signature); - bool PrefixSign(std::vector data, uint64 type, std::vector &Signature); -}; - -#endif -// vim:ts=4 From dd27ce9324c5fb779703f0085059ecdd4bcbeb48 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 01:59:00 -0700 Subject: [PATCH 4/8] Sorry, I broke this. --- src/NewcoinAddress.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NewcoinAddress.cpp b/src/NewcoinAddress.cpp index 715863c3e7..ccb6e311fb 100644 --- a/src/NewcoinAddress.cpp +++ b/src/NewcoinAddress.cpp @@ -503,8 +503,8 @@ BIGNUM* NewcoinAddress::getFamilyGeneratorBN() const throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion))); } - assert(vchData.size() <= (256 / 8)); - BIGNUM* ret = BN_bin2bn(&vchData[0], vchData.size(), NULL); + assert(vchData.size() <= ((256 + 8) / 8)); + BIGNUM* ret = BN_bin2bn(&vchData[1], vchData.size() - 1, NULL); assert(ret); return ret; @@ -524,9 +524,9 @@ uint256 NewcoinAddress::getFamilyGeneratorU() const throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion))); } - assert(vchData.size() <= (256 / 8)); + assert(vchData.size() <= ((256 + 1) / 8)); uint256 ret; - memcpy(ret.begin() + (ret.size() - vchData.size()), &vchData[0], vchData.size()); + memcpy(ret.begin() + (ret.size() - (vchData.size() - 1)), &vchData[1], vchData.size() - 1); return ret; } From 51ba107e2ca2b510053a5459b318ced946ccf7df Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 02:22:00 -0700 Subject: [PATCH 5/8] Fix breakage. --- src/DeterministicKeys.cpp | 15 +++++++++++---- src/NewcoinAddress.cpp | 28 +++------------------------- src/NewcoinAddress.h | 1 - src/key.h | 8 ++++++-- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/DeterministicKeys.cpp b/src/DeterministicKeys.cpp index 2373fe52c1..e95280c72c 100644 --- a/src/DeterministicKeys.cpp +++ b/src/DeterministicKeys.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // Functions to add CKey support for deterministic EC keys @@ -115,26 +116,32 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint128& seed) // <-- root public generator in EC format EC_KEY* CKey::GenerateRootPubKey(BIGNUM* pubGenerator) { - if(pubGenerator==NULL) return NULL; + if (pubGenerator == NULL) + { + assert(false); + return NULL; + } - EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1); - if(!pkey) + EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!pkey) { BN_free(pubGenerator); return NULL; } EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); - EC_POINT* pubPoint=EC_POINT_bn2point(EC_KEY_get0_group(pkey), pubGenerator, NULL, NULL); + EC_POINT* pubPoint = EC_POINT_bn2point(EC_KEY_get0_group(pkey), pubGenerator, NULL, NULL); BN_free(pubGenerator); if(!pubPoint) { + assert(false); EC_KEY_free(pkey); return NULL; } if(!EC_KEY_set_public_key(pkey, pubPoint)) { + assert(false); EC_POINT_free(pubPoint); EC_KEY_free(pkey); return NULL; diff --git a/src/NewcoinAddress.cpp b/src/NewcoinAddress.cpp index ccb6e311fb..a621b7f75b 100644 --- a/src/NewcoinAddress.cpp +++ b/src/NewcoinAddress.cpp @@ -490,7 +490,7 @@ std::vector NewcoinAddress::accountPrivateDecrypt(const NewcoinAd // BIGNUM* NewcoinAddress::getFamilyGeneratorBN() const -{ +{ // returns the public generator switch (nVersion) { case VER_NONE: throw std::runtime_error("unset source"); @@ -503,35 +503,13 @@ BIGNUM* NewcoinAddress::getFamilyGeneratorBN() const throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion))); } - assert(vchData.size() <= ((256 + 8) / 8)); - BIGNUM* ret = BN_bin2bn(&vchData[1], vchData.size() - 1, NULL); + BIGNUM* ret = BN_bin2bn(&vchData[0], vchData.size(), NULL); assert(ret); - - return ret; -} - -uint256 NewcoinAddress::getFamilyGeneratorU() const -{ - switch (nVersion) { - case VER_NONE: - throw std::runtime_error("unset source"); - - case VER_FAMILY_GENERATOR: - // Do nothing. - break; - - default: - throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion))); - } - - assert(vchData.size() <= ((256 + 1) / 8)); - uint256 ret; - memcpy(ret.begin() + (ret.size() - (vchData.size() - 1)), &vchData[1], vchData.size() - 1); return ret; } const std::vector& NewcoinAddress::getFamilyGenerator() const -{ +{ // returns the public generator switch (nVersion) { case VER_NONE: throw std::runtime_error("unset source"); diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index 8e3069d722..3418669152 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -136,7 +136,6 @@ public: // Use to generate a master or regular family. // BIGNUM* getFamilyGeneratorBN() const; // DEPRECATED - uint256 getFamilyGeneratorU() const; const std::vector& getFamilyGenerator() const; std::string humanFamilyGenerator() const; diff --git a/src/key.h b/src/key.h index 38a47e8c26..213bae4ddc 100644 --- a/src/key.h +++ b/src/key.h @@ -156,14 +156,16 @@ public: SetPrivateKeyU(privateKey); } +#if 0 CKey(const NewcoinAddress& masterKey, int keyNum, bool isPublic) : pkey(NULL), fSet(false) { if (isPublic) SetPubSeq(masterKey, keyNum); else - SetPrivSeq(masterKey, keyNum); + SetPrivSeq(masterKey, keyNum); // broken, need seed fSet = true; } +#endif bool IsNull() const { @@ -257,8 +259,9 @@ public: fSet = true; } +#if 0 void SetPrivSeq(const NewcoinAddress& masterKey, int keyNum) - { + { // broken: Need the seed uint256 privKey; EC_KEY* key = GeneratePrivateDeterministicKey(masterKey, masterKey.getFamilyGeneratorU(), keyNum); privKey.zero(); @@ -267,6 +270,7 @@ public: pkey = key; fSet = true; } +#endif CPrivKey GetPrivKey() { From eaf511ebb605108707f3d1f998832a333685eddd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 02:22:15 -0700 Subject: [PATCH 6/8] New ledger code. --- src/Ledger.cpp | 25 +++++++++++++++++++++---- src/RPCServer.cpp | 3 ++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 440fb393a2..a77b0e649c 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -336,20 +336,37 @@ void Ledger::addJson(Json::Value& ret, int options) else ledger["Closed"] = false; if (mCloseTime != 0) ledger["CloseTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime)); - if ((options & LEDGER_JSON_DUMP_TXNS) != 0) + bool full = (options & LEDGER_JSON_FULL) != 0; + if (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0)) { Json::Value txns(Json::arrayValue); for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(); !!item; item = mTransactionMap->peekNextItem(item->getTag())) - txns.append(item->getTag().GetHex()); + { + if (full) + { + SerializerIterator sit(item->peekSerializer()); + SerializedTransaction txn(sit); + txns.append(txn.getJson(0)); + } + else txns.append(item->getTag().GetHex()); + } ledger["Transactions"] = txns; } - if ((options & LEDGER_JSON_DUMP_STATE) != 0) + if (full || ((options & LEDGER_JSON_DUMP_STATE) != 0)) { Json::Value state(Json::arrayValue); for (SHAMapItem::pointer item = mAccountStateMap->peekFirstItem(); !!item; item = mAccountStateMap->peekNextItem(item->getTag())) - state.append(item->getTag().GetHex()); + { + if (full) + { + SerializerIterator sit(item->peekSerializer()); + SerializedLedgerEntry sle(sit, item->getTag()); + state.append(sle.getJson(0)); + } + else state.append(item->getTag().GetHex()); + } ledger["AccountState"] = state; } ret[boost::lexical_cast(mLedgerSeq)] = ledger; diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index f325ce6a81..6ba9ad38d4 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -2143,12 +2143,13 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params if (command == "wallet_propose") return doWalletPropose(params); if (command == "wallet_seed") return doWalletSeed(params); + if (command=="ledger") return doLedger(params); + // // Obsolete or need rewrite: // if (command=="tx") return doTx(params); - if (command=="ledger") return doLedger(params); return "unknown command"; } From 182d23e22a63fad8ae3e21d1f7e6814b5d55a1df Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 02:27:57 -0700 Subject: [PATCH 7/8] Give account state node types. --- src/SerializedLedger.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index beeb69dee5..726296d189 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -57,6 +57,7 @@ std::string SerializedLedgerEntry::getText() const Json::Value SerializedLedgerEntry::getJson(int options) const { Json::Value ret(mObject.getJson(options)); + ret["Type"] = mFormat->t_name; ret["Index"] = mIndex.GetHex(); ret["Version"] = mVersion.getText(); return ret; From c0fced82c8a9fb4ee7f728c79e3a650c5ec2b119 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 02:31:56 -0700 Subject: [PATCH 8/8] Cleanup. --- src/SerializedTransaction.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index ec94093f0b..daadbd5b39 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -272,11 +272,14 @@ void SerializedTransaction::makeITFieldAbsent(SOE_Field field) Json::Value SerializedTransaction::getJson(int options) const { - Json::Value ret(Json::objectValue); - ret["Type"] = mFormat->t_name; + Json::Value ret = Json::objectValue; ret["ID"] = getTransactionID().GetHex(); ret["Signature"] = mSignature.getText(); - ret["Middle"] = mMiddleTxn.getJson(options); + + Json::Value middle = mMiddleTxn.getJson(options); + middle["Type"] = mFormat->t_name; + ret["Middle"] = middle; + ret["Inner"] = mInnerTxn.getJson(options); return ret; }