diff --git a/src/Application.cpp b/src/Application.cpp index 37ca4f3952..5b27580c97 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -20,7 +20,7 @@ Application* theApp = NULL; DatabaseCon::DatabaseCon(const std::string& name, const char *initStrings[], int initCount) { std::string path=strprintf("%s%s", theConfig.DATA_DIR.c_str(), name.c_str()); - mDatabase=new SqliteDatabase(path.c_str()); + mDatabase = new SqliteDatabase(path.c_str()); mDatabase->connect(); for(int i = 0; i < initCount; ++i) mDatabase->executeSQL(initStrings[i], true); @@ -35,15 +35,16 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mNodeCache(16384, 600), - mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), + mTxnDB(NULL), mAcctTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); } -extern const char *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; -extern int TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount, NetNodeDBCount; +extern const char *AcctTxnDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], + *HashNodeDBInit[], *NetNodeDBInit[]; +extern int TxnDBCount, AcctTxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount, NetNodeDBCount; void Application::stop() { @@ -59,11 +60,12 @@ void Application::run() // // Construct databases. // - mTxnDB=new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount); - mLedgerDB=new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount); - mWalletDB=new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount); - mHashNodeDB=new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount); - mNetNodeDB=new DatabaseCon("netnode.db", NetNodeDBInit, NetNodeDBCount); + mTxnDB = new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount); + mAcctTxnDB = new DatabaseCon("transacct.db", AcctTxnDBInit, AcctTxnDBCount); + mLedgerDB = new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount); + mWalletDB = new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount); + mHashNodeDB = new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount); + mNetNodeDB = new DatabaseCon("netnode.db", NetNodeDBInit, NetNodeDBCount); // // Begin validation and ip maintenance. @@ -76,7 +78,7 @@ void Application::run() // if(!theConfig.PEER_IP.empty() && theConfig.PEER_PORT) { - mPeerDoor=new PeerDoor(mIOService); + mPeerDoor = new PeerDoor(mIOService); } else { @@ -88,7 +90,7 @@ void Application::run() // if(!theConfig.RPC_IP.empty() && theConfig.RPC_PORT) { - mRPCDoor=new RPCDoor(mIOService); + mRPCDoor = new RPCDoor(mIOService); } else { @@ -138,6 +140,7 @@ void Application::run() Application::~Application() { delete mTxnDB; + delete mAcctTxnDB; delete mLedgerDB; delete mWalletDB; delete mHashNodeDB; diff --git a/src/Application.h b/src/Application.h index 2c1fd6c006..546d0aad51 100644 --- a/src/Application.h +++ b/src/Application.h @@ -45,7 +45,7 @@ class Application NetworkOPs mNetOps; NodeCache mNodeCache; - DatabaseCon* mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; + DatabaseCon *mTxnDB, *mAcctTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; ConnectionPool mConnectionPool; PeerDoor* mPeerDoor; @@ -76,6 +76,7 @@ public: NodeCache& getNodeCache() { return mNodeCache; } DatabaseCon* getTxnDB() { return mTxnDB; } + DatabaseCon* getAcctTxnDB() { return mAcctTxnDB; } DatabaseCon* getLedgerDB() { return mLedgerDB; } DatabaseCon* getWalletDB() { return mWalletDB; } DatabaseCon* getHashNodeDB() { return mHashNodeDB; } diff --git a/src/Avalanche.h b/src/Avalanche.h deleted file mode 100644 index 301188edd4..0000000000 --- a/src/Avalanche.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __AVALANCHE__ -#define __AVALANCHE__ - -#include -#include - -#include "Transaction.h" - -class DisputedTransaction -{ -protected: - Transaction::pointer mTransaction; -// std::vector mNodesIncluding; -// std::vector mNodesRejecting; - uint64 mTimeTaken; // when we took our position on this transaction - bool mOurPosition; -}; - -class DTComp -{ -public: - bool operator()(const DisputedTransaction&, const DisputedTransaction&); -}; - -class Avalanche -{ -protected: - SHAMap::pointer mOurLedger; - std::map mTxByID; - std::set mTxInASOrder; - -public: - Avalanche(SHAMap::pointer ourLedger); -}; - -#endif diff --git a/src/CanonicalTXSet.cpp b/src/CanonicalTXSet.cpp new file mode 100644 index 0000000000..93ed79ccd4 --- /dev/null +++ b/src/CanonicalTXSet.cpp @@ -0,0 +1,53 @@ + +#include "CanonicalTXSet.h" + +bool CanonicalTXKey::operator<(const CanonicalTXKey& key) const +{ + if (mAccount < key.mAccount) return true; + if (mAccount > key.mAccount) return false; + if (mSeq < key.mSeq) return true; + if (mSeq > key.mSeq) return false; + return mTXid < key.mTXid; +} + +bool CanonicalTXKey::operator>(const CanonicalTXKey& key) const +{ + if (mAccount > key.mAccount) return true; + if (mAccount < key.mAccount) return false; + if (mSeq > key.mSeq) return true; + if (mSeq < key.mSeq) return false; + return mTXid > key.mTXid; +} + +bool CanonicalTXKey::operator<=(const CanonicalTXKey& key) const +{ + if (mAccount < key.mAccount) return true; + if (mAccount > key.mAccount) return false; + if (mSeq < key.mSeq) return true; + if (mSeq > key.mSeq) return false; + return mTXid <= key.mTXid; +} + +bool CanonicalTXKey::operator>=(const CanonicalTXKey& key)const +{ + if (mAccount > key.mAccount) return true; + if (mAccount < key.mAccount) return false; + if (mSeq > key.mSeq) return true; + if (mSeq < key.mSeq) return false; + return mTXid >= key.mTXid; +} + +void CanonicalTXSet::push_back(SerializedTransaction::pointer txn) +{ + uint256 effectiveAccount = mSetHash; + effectiveAccount ^= txn->getSourceAccount().getAccountID().to256(); + mMap.insert(std::make_pair(CanonicalTXKey(effectiveAccount, txn->getSequence(), txn->getTransactionID()), txn)); +} + +void CanonicalTXSet::eraseInc(iterator& it) +{ + iterator tmp = it++; + mMap.erase(tmp); +} + + diff --git a/src/CanonicalTXSet.h b/src/CanonicalTXSet.h new file mode 100644 index 0000000000..f78c580cd9 --- /dev/null +++ b/src/CanonicalTXSet.h @@ -0,0 +1,53 @@ +#ifndef __CANONICAL_TX_SET_ +#define __CANONICAL_TX_SET_ + +#include + +#include "uint256.h" +#include "SerializedTransaction.h" + +class CanonicalTXKey +{ +protected: + uint256 mAccount, mTXid; + uint32 mSeq; + +public: + CanonicalTXKey(const uint256& account, uint32 seq, const uint256& id) + : mAccount(account), mTXid(id), mSeq(seq) { ; } + + bool operator<(const CanonicalTXKey&) const; + bool operator>(const CanonicalTXKey&) const; + bool operator<=(const CanonicalTXKey&) const; + bool operator>=(const CanonicalTXKey&) const; + + bool operator==(const CanonicalTXKey& k) const { return mTXid == k.mTXid; } + bool operator!=(const CanonicalTXKey& k) const { return mTXid != k.mTXid; } +}; + +class CanonicalTXSet +{ +public: + typedef std::map::iterator iterator; + typedef std::map::const_iterator const_iterator; + +protected: + uint256 mSetHash; + std::map mMap; + +public: + CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; } + + void push_back(SerializedTransaction::pointer txn); + void erase(const iterator& it) { mMap.erase(it); } + void eraseInc(iterator& it); + + iterator begin() { return mMap.begin(); } + iterator end() { return mMap.end(); } + const_iterator begin() const { return mMap.begin(); } + const_iterator end() const { return mMap.end(); } + size_t size() const { return mMap.size(); } + bool empty() const { return mMap.empty(); } +}; + +#endif diff --git a/src/Confirmation.h b/src/Confirmation.h deleted file mode 100644 index a47e3fa1e5..0000000000 --- a/src/Confirmation.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __CONFIRMATION__ -#define __CONFIRMATION__ - -#include "../obj/src/newcoin.pb.h" -#include "uint256.h" -#include - -enum ConfirmationStatus -{ - NEW, // first for this account/seq - CONFLICTED, // rejected as of this time - ACCEPTED, // in active bundle, has confirmations - COMMITTED -}; - - -class Confirmation -{ // used primarily to report conflicted or rejected transactions -public: - typedef boost::shared_ptr pointer; - -private: - uint256 mID; - uint160 mHanko; - uint64 mTimestamp; - ConfirmationStatus mStatus; - bool mConflicts; - std::vector mSignature; - -public: - Confirmation(); - Confirmation(const uint256 &id); - Confirmation(const std::vector rawConfirmation); - - const uint256& GetID() const { return mID; } - const uint160& GetHanko() const { return mHanko; } - uint64 GetTimestamp() const { return mTimestamp; } - ConfirmationStatus() const { return mStatus; } - bool HasConflicts() const { return mConflicts; } - - bool save(); -}; - -#endif diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 9f1f3a92a8..470d28fb31 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -20,7 +20,21 @@ const char *TxnDBInit[] = { );" }; -int TxnDBCount=sizeof(TxnDBInit)/sizeof(const char *); +int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *); + +const char *AcctTxnDBInit[] = { + "CREATE TABLE AccountTransactions ( \ + TransID CHARACTER964) PRIMARY KEY \ + Account CHARACTER(64), \ + LedgerSeq BIGINT UNSIGNED, \ + );", + "CREATE INDEX AcctTxindex ON \ + AccountTransactions(Account), \ + AccountTransactions(LedgerSeq), \ + AccountTransactions(TransID);" +}; + +int AcctTxnDBCount = sizeof(AcctTxnDBInit) / sizeof(const char *); // Ledger database holds ledgers and ledger confirmations const char *LedgerDBInit[] = { @@ -46,7 +60,7 @@ const char *LedgerDBInit[] = { #endif }; -int LedgerDBCount=sizeof(LedgerDBInit)/sizeof(const char *); +int LedgerDBCount = sizeof(LedgerDBInit) / sizeof(const char *); // Wallet database holds local accounts and trusted nodes const char *WalletDBInit[] = { @@ -212,7 +226,7 @@ const char *WalletDBInit[] = { PeerIps(ScanNext);" }; -int WalletDBCount=sizeof(WalletDBInit)/sizeof(const char *); +int WalletDBCount = sizeof(WalletDBInit) / sizeof(const char *); // Hash node database holds nodes indexed by hash const char *HashNodeDBInit[] = { @@ -227,7 +241,7 @@ const char *HashNodeDBInit[] = { CommittedObjects(LedgerIndex, ObjType);" }; -int HashNodeDBCount=sizeof(HashNodeDBInit)/sizeof(const char *); +int HashNodeDBCount = sizeof(HashNodeDBInit) / sizeof(const char *); // Net node database holds nodes seen on the network // XXX Not really used needs replacement. @@ -241,6 +255,6 @@ const char *NetNodeDBInit[] = { }; -int NetNodeDBCount=sizeof(NetNodeDBInit)/sizeof(const char *); +int NetNodeDBCount = sizeof(NetNodeDBInit) / sizeof(const char *); // vim:ts=4 diff --git a/src/DeterministicKeys.cpp b/src/DeterministicKeys.cpp index e6717540bc..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 @@ -78,7 +79,7 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint128& seed) { // set the random point as the private key assert(false); EC_KEY_free(pkey); - BN_free(privKey); + BN_clear_free(privKey); BN_CTX_free(ctx); return NULL; } @@ -87,13 +88,13 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint128& seed) if(!EC_POINT_mul(EC_KEY_get0_group(pkey), pubKey, privKey, NULL, NULL, ctx)) { // compute the corresponding public key point assert(false); - BN_free(privKey); + BN_clear_free(privKey); EC_POINT_free(pubKey); EC_KEY_free(pkey); BN_CTX_free(ctx); return NULL; } - BN_free(privKey); + BN_clear_free(privKey); if(!EC_KEY_set_public_key(pkey, pubKey)) { assert(false); @@ -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; @@ -144,14 +151,14 @@ EC_KEY* CKey::GenerateRootPubKey(BIGNUM* pubGenerator) } // --> public generator -static BIGNUM* makeHash(const NewcoinAddress& generator, int seq, BIGNUM* order) +static BIGNUM* makeHash(const NewcoinAddress& pubGen, int seq, BIGNUM* order) { int subSeq=0; BIGNUM* ret=NULL; do { Serializer s((33*8+32+32)/8); - s.addRaw(generator.getFamilyGenerator()); + s.addRaw(pubGen.getFamilyGenerator()); s.add32(seq); s.add32(subSeq++); uint256 root=s.getSHA512Half(); @@ -164,9 +171,9 @@ static BIGNUM* makeHash(const NewcoinAddress& generator, int seq, BIGNUM* order) } // --> public generator -EC_KEY* CKey::GeneratePublicDeterministicKey(const NewcoinAddress& generator, int seq) +EC_KEY* CKey::GeneratePublicDeterministicKey(const NewcoinAddress& pubGen, int seq) { // publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point - EC_KEY* rootKey = CKey::GenerateRootPubKey(generator.getFamilyGeneratorBN()); + EC_KEY* rootKey = CKey::GenerateRootPubKey(pubGen.getFamilyGeneratorBN()); const EC_POINT* rootPubKey = EC_KEY_get0_public_key(rootKey); BN_CTX* ctx = BN_CTX_new(); EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1); @@ -194,7 +201,7 @@ EC_KEY* CKey::GeneratePublicDeterministicKey(const NewcoinAddress& generator, in // Calculate the private additional key. if (success) { - hash = makeHash(generator, seq, order); + hash = makeHash(pubGen, seq, order); if(!hash) success = false; } @@ -217,8 +224,14 @@ EC_KEY* CKey::GeneratePublicDeterministicKey(const NewcoinAddress& generator, in return success ? pkey : NULL; } +EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& pubGen, const uint256& u, int seq) +{ + CBigNum bn(u); + return GeneratePrivateDeterministicKey(pubGen, static_cast(&bn), seq); +} + // --> root private key -EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& family, const BIGNUM* rootPrivKey, int seq) +EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& pubGen, const BIGNUM* rootPrivKey, int seq) { // privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order BN_CTX* ctx=BN_CTX_new(); if(ctx==NULL) return NULL; @@ -248,7 +261,7 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& family, cons } // calculate the private additional key - BIGNUM* privKey=makeHash(family, seq, order); + BIGNUM* privKey=makeHash(pubGen, seq, order); if(privKey==NULL) { BN_free(order); @@ -266,19 +279,19 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& family, cons EC_POINT* pubKey=EC_POINT_new(EC_KEY_get0_group(pkey)); if(!pubKey) { - BN_free(privKey); + BN_clear_free(privKey); BN_CTX_free(ctx); EC_KEY_free(pkey); return NULL; } if(EC_POINT_mul(EC_KEY_get0_group(pkey), pubKey, privKey, NULL, NULL, ctx)==0) { - BN_free(privKey); + BN_clear_free(privKey); BN_CTX_free(ctx); EC_KEY_free(pkey); return NULL; } - BN_free(privKey); + BN_clear_free(privKey); EC_KEY_set_public_key(pkey, pubKey); EC_POINT_free(pubKey); 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 diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 0da7c29446..fd2aa94ef7 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -36,6 +36,10 @@ CREATE TABLE CommittedObjects ( -- used to synch nodes CREATE INDEX ObjectLocate ON CommittedObjects(LedgerIndex, ObjType); */ +// FIXME: Stores should be added to a queue that's services by an auxilliary thread or from an +// auxilliary thread pool. These should be tied into a cache, since you need one to handle +// an immedate read back (before the write completes) + bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector& data, const uint256& hash) { @@ -44,7 +48,7 @@ bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector< Serializer s(data); assert(hash == s.getSHA512Half()); #endif - std::string sql = "INSERT INTO CommitedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('"; + std::string sql = "INSERT INTO CommittedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('"; sql.append(hash.GetHex()); switch(type) { @@ -78,7 +82,7 @@ bool HashedObject::store() const HashedObject::pointer HashedObject::retrieve(const uint256& hash) { if (!theApp || !theApp->getHashNodeDB()) return HashedObject::pointer(); - std::string sql = "SELECT * from CommitedObjects WHERE Hash='"; + std::string sql = "SELECT * from CommittedObjects WHERE Hash='"; sql.append(hash.GetHex()); sql.append("';"); 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/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/LedgerAcquire.h b/src/LedgerAcquire.h index f06c4dbabf..211567d320 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -60,7 +60,7 @@ typedef std::vector VUC; class THSyncFilter : public SHAMapSyncFilter { protected: - NodeCache* mCache; + NodeCache* mCache; // holds nodes we see during the consensus process public: THSyncFilter(NodeCache* cache) : mCache(cache) { ; } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 4232c57e24..bd15efe5f9 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -577,7 +577,7 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p } void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer ledger, - std::list& failedTransactions) + CanonicalTXSet& failedTransactions) { TransactionEngine engine(ledger); @@ -620,16 +620,17 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led do { successes = 0; - std::list::iterator it = failedTransactions.begin(); + CanonicalTXSet::iterator it = failedTransactions.begin(); while (it != failedTransactions.end()) { try { - TransactionEngineResult result = engine.applyTransaction(**it, tepNO_CHECK_FEE | tepUPDATE_TOTAL, 0); + TransactionEngineResult result = + engine.applyTransaction(*it->second, tepNO_CHECK_FEE | tepUPDATE_TOTAL, 0); if (result <= 0) { if (result == 0) ++successes; - failedTransactions.erase(it++); + failedTransactions.eraseInc(it); } else { @@ -639,7 +640,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led catch (...) { Log(lsWARNING) << " Throws"; - failedTransactions.erase(it++); + failedTransactions.eraseInc(it); } } } while (successes > 0); @@ -653,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; @@ -665,7 +667,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) } #endif - std::list failedTransactions; + CanonicalTXSet failedTransactions(set->getHash()); applyTransactions(set, newLCL, failedTransactions); newLCL->setClosed(); newLCL->setAccepted(); @@ -703,10 +705,10 @@ void LedgerConsensus::accept(SHAMap::pointer set) ScopedLock sl = theApp->getMasterLedger().getLock(); - applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), - newOL, failedTransactions); + 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() diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 820d65a65c..5595435f5a 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -12,6 +12,7 @@ #include "LedgerAcquire.h" #include "LedgerProposal.h" #include "Peer.h" +#include "CanonicalTXSet.h" class TransactionAcquire : public PeerSet, public boost::enable_shared_from_this { // A transaction set we are trying to acquire @@ -113,7 +114,7 @@ protected: void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); void applyTransactions(SHAMap::pointer transactionSet, Ledger::pointer targetLedger, - std::list& failedTransactions); + CanonicalTXSet& failedTransactions); // manipulating our own position void takeInitialPosition(Ledger::pointer initialLedger); diff --git a/src/NewcoinAddress.cpp b/src/NewcoinAddress.cpp index 05179cfd06..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"); @@ -505,12 +505,11 @@ BIGNUM* NewcoinAddress::getFamilyGeneratorBN() const BIGNUM* ret = BN_bin2bn(&vchData[0], vchData.size(), NULL); assert(ret); - 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 daf30cdb9c..3418669152 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -135,7 +135,7 @@ public: // Family Generators // Use to generate a master or regular family. // - BIGNUM* getFamilyGeneratorBN() const; + BIGNUM* getFamilyGeneratorBN() const; // DEPRECATED const std::vector& getFamilyGenerator() const; std::string humanFamilyGenerator() const; diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b5190f665d..912f13d925 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 | [] @@ -2105,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"; } diff --git a/src/RequestParser.h b/src/RequestParser.h index 9e973dd143..f0906daa88 100644 --- a/src/RequestParser.h +++ b/src/RequestParser.h @@ -69,4 +69,4 @@ public: }; -#endif // HTTP_REQUEST_PARSER_HPP \ No newline at end of file +#endif // HTTP_REQUEST_PARSER_HPP 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; 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; } diff --git a/src/TaggedCache.h b/src/TaggedCache.h index 6f79e172c5..a53b7d3dc5 100644 --- a/src/TaggedCache.h +++ b/src/TaggedCache.h @@ -11,6 +11,12 @@ // in the map. The map allows multiple code paths that reference objects // with the same tag to get the same actual object. +// So long as data is in the cache, it will stay in memory. +// If it stays in memory even after it is ejected from the cache, +// the map will track it. + +// CAUTION: Callers must not modify data objects that are stored in the cache! + template class TaggedCache { public: @@ -46,7 +52,9 @@ public: bool touch(const key_type& key); bool del(const key_type& key); bool canonicalize(const key_type& key, boost::shared_ptr& data); + bool store(const key_type& key, const c_Data& data); boost::shared_ptr fetch(const key_type& key); + bool retrieve(const key_type& key, c_Data& data); boost::recursive_mutex& peekMutex() { return mLock; } }; @@ -86,7 +94,10 @@ template void TaggedCache::sweep while (cit != mCache.end()) { if (cit->second->second.first < target) - mCache.erase(cit++); + { + typename boost::unordered_map::iterator tmp = cit++; + mCache.erase(tmp); + } else ++cit; } @@ -95,7 +106,10 @@ template void TaggedCache::sweep while (mit != mMap.end()) { if (mit->second->expired()) - mMap.erase(mit++); + { + typename boost::unordered_map::iterator tmp = mit++; + mMap.erase(mit); + } else ++mit; } } @@ -149,15 +163,16 @@ bool TaggedCache::canonicalize(const key_type& key, boost::shared mMap.insert(std::make_pair(key, data)); return false; } - if (mit->second.expired()) - { // in map, but expired + + boost::shared_ptr cachedData = mit->second.lock(); + if (!cachedData) + { // in map, but expired. Update in map, insert in cache mit->second = data; mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); return false; } - data = mit->second.lock(); - assert(!!data); + data = cachedData; // Valid in map, is it in cache? typename boost::unordered_map::iterator cit = mCache.find(key); @@ -171,28 +186,46 @@ bool TaggedCache::canonicalize(const key_type& key, boost::shared template boost::shared_ptr TaggedCache::fetch(const key_type& key) -{ +{ // fetch us a shared pointer to the stored data object boost::recursive_mutex::scoped_lock sl(mLock); // Is it in the map? typename boost::unordered_map::iterator mit = mMap.find(key); if (mit == mMap.end()) return data_ptr(); // No, we're done - if (mit->second.expired()) - { // in map, but expired - mMap.erase(mit); - return data_ptr(); - } - boost::shared_ptr data = mit->second.lock(); + boost::shared_ptr cachedData = mit->second.lock(); + if (!cachedData) + { // in map, but expired. Sorry, we don't have it + mMap.erase(mit); + return cachedData; + } // Valid in map, is it in the cache? typename boost::unordered_map::iterator cit = mCache.find(key); if (cit != mCache.end()) cit->second.first = time(NULL); // Yes, refresh else // No, add to cache - mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); + mCache.insert(std::make_pair(key, std::make_pair(time(NULL), cachedData))); - return data; + return cachedData; +} + +template +bool TaggedCache::store(const key_type& key, const c_Data& data) +{ + if (!canonicalize(key, boost::shared_ptr(data))) + return false; + return true; +} + +template +bool TaggedCache::retrieve(const key_type& key, c_Data& data) +{ // retrieve the value of the stored data + boost::shared_ptr dataPtr = fetch(key); + if (!dataPtr) + return false; + data = *dataPtr; + return true; } #endif diff --git a/src/TransactionMaster.cpp b/src/TransactionMaster.cpp index 91f0d7d9e9..8cddedf819 100644 --- a/src/TransactionMaster.cpp +++ b/src/TransactionMaster.cpp @@ -20,11 +20,11 @@ TransactionMaster::TransactionMaster() : mCache(CACHED_TRANSACTION_NUM, CACHED_T Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDisk) { - Transaction::pointer txn=mCache.fetch(txnID); - if(!checkDisk || txn) return txn; + Transaction::pointer txn = mCache.fetch(txnID); + if( !checkDisk || txn) return txn; - txn=Transaction::load(txnID); - if(!txn) return txn; + txn = Transaction::load(txnID); + if (!txn) return txn; mCache.canonicalize(txnID, txn); return txn; @@ -32,10 +32,10 @@ Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDi bool TransactionMaster::canonicalize(Transaction::pointer& txn, bool may_be_new) { - uint256 tid=txn->getID(); - if(!tid) return false; - if(mCache.canonicalize(tid, txn)) return true; - if(may_be_new) + uint256 tid = txn->getID(); + if (!tid) return false; + if (mCache.canonicalize(tid, txn)) return true; + if (may_be_new) // FIXME: Don't dispatch to main pool theApp->getIOService().post(boost::bind(&Transaction::saveTransaction, txn)); return false; } diff --git a/src/bignum.h b/src/bignum.h index 01e614a79c..74c87aa73f 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -14,7 +14,7 @@ class bignum_error : public std::runtime_error { public: - explicit bignum_error(const std::string& str) : std::runtime_error(str) {} + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} }; @@ -26,27 +26,27 @@ private: CAutoBN_CTX& operator=(const CAutoBN_CTX&); // no implementation protected: - BN_CTX* pctx; - BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + BN_CTX* pctx; + BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } public: - CAutoBN_CTX() - { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); - } + CAutoBN_CTX() + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } - ~CAutoBN_CTX() - { - if (pctx != NULL) - BN_CTX_free(pctx); - } + ~CAutoBN_CTX() + { + if (pctx != NULL) + BN_CTX_free(pctx); + } - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } - bool operator!() { return (pctx == NULL); } + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } }; @@ -54,482 +54,454 @@ public: class CBigNum : public BIGNUM { public: - CBigNum() - { - BN_init(this); - } + CBigNum() + { + BN_init(this); + } - CBigNum(const CBigNum& b) - { - BN_init(this); - if (!BN_copy(this, &b)) - { - BN_clear_free(this); - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); - } - } + CBigNum(const CBigNum& b) + { + BN_init(this); + if (!BN_copy(this, &b)) + { + BN_clear_free(this); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(this, &b)) - throw bignum_error("CBigNum::operator= : BN_copy failed"); - return (*this); - } + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(this, &b)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } - ~CBigNum() - { - BN_clear_free(this); - } + ~CBigNum() + { + BN_clear_free(this); + } - CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int64 n) { BN_init(this); setint64(n); } - CBigNum(unsigned char n) { BN_init(this); setulong(n); } - CBigNum(unsigned short n) { BN_init(this); setulong(n); } - CBigNum(unsigned int n) { BN_init(this); setulong(n); } - CBigNum(unsigned long n) { BN_init(this); setulong(n); } - CBigNum(uint64 n) { BN_init(this); setuint64(n); } - explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } + CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int64 n) { BN_init(this); setint64(n); } + CBigNum(unsigned char n) { BN_init(this); setulong(n); } + CBigNum(unsigned short n) { BN_init(this); setulong(n); } + CBigNum(unsigned int n) { BN_init(this); setulong(n); } + CBigNum(unsigned long n) { BN_init(this); setulong(n); } + CBigNum(uint64 n) { BN_init(this); setuint64(n); } + explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } - explicit CBigNum(const std::vector& vch) - { - BN_init(this); - setvch(vch); - } + explicit CBigNum(const std::vector& vch) + { + BN_init(this); + setvch(vch); + } - void setulong(unsigned long n) - { - if (!BN_set_word(this, n)) - throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); - } + void setulong(unsigned long n) + { + if (!BN_set_word(this, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); + } - unsigned long getulong() const - { - return BN_get_word(this); - } + unsigned long getulong() const + { + return BN_get_word(this); + } - unsigned int getuint() const - { - return BN_get_word(this); - } + unsigned int getuint() const + { + return BN_get_word(this); + } - int getint() const - { - unsigned long n = BN_get_word(this); - if (!BN_is_negative(this)) - return (n > INT_MAX ? INT_MAX : n); - else - return (n > INT_MAX ? INT_MIN : -(int)n); - } + int getint() const + { + unsigned long n = BN_get_word(this); + if (!BN_is_negative(this)) + return (n > INT_MAX ? INT_MAX : n); + else + return (n > INT_MAX ? INT_MIN : -(int)n); + } - void setint64(int64 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fNegative = false; - if (n < (int64)0) - { - n = -n; - fNegative = true; - } - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } + void setint64(int64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fNegative = false; + if (n < (int64)0) + { + n = -n; + fNegative = true; + } + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } - void setuint64(uint64 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } + void setuint64(uint64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } - void setuint256(uint256 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, this); - } + void setuint256(const uint256& n) + { + BN_bin2bn(n.begin(), n.size(), NULL); + } - uint256 getuint256() - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint256 n = 0; - for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } + uint256 getuint256() + { + uint256 ret; + int size = BN_num_bytes(this); + if (size > ret.size()) + return ret; + BN_bn2bin(this, ret.begin() + (ret.size() - BN_num_bytes(this))); + return ret; + } - void setvch(const std::vector& vch) - { - std::vector vch2(vch.size() + 4); - unsigned int nSize = vch.size(); - // BIGNUM's byte stream format expects 4 bytes of - // big endian size data info at the front - vch2[0] = (nSize >> 24) & 0xff; - vch2[1] = (nSize >> 16) & 0xff; - vch2[2] = (nSize >> 8) & 0xff; - vch2[3] = (nSize >> 0) & 0xff; - // swap data to big endian - std::reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], vch2.size(), this); - } + void setvch(const std::vector& vch) + { + std::vector vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + // BIGNUM's byte stream format expects 4 bytes of + // big endian size data info at the front + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + // swap data to big endian + std::reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), this); + } - std::vector getvch() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - if (nSize < 4) - return std::vector(); - std::vector vch(nSize); - BN_bn2mpi(this, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); - return vch; - } + std::vector getvch() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } - CBigNum& SetCompact(unsigned int nCompact) - { - unsigned int nSize = nCompact >> 24; - std::vector vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], vch.size(), this); - return *this; - } + CBigNum& SetCompact(unsigned int nCompact) + { + unsigned int nSize = nCompact >> 24; + std::vector vch(4 + nSize); + vch[3] = nSize; + if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; + if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; + if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; + BN_mpi2bn(&vch[0], vch.size(), this); + return *this; + } - unsigned int GetCompact() const - { - unsigned int nSize = BN_bn2mpi(this, NULL); - std::vector vch(nSize); - nSize -= 4; - BN_bn2mpi(this, &vch[0]); - unsigned int nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); - return nCompact; - } + unsigned int GetCompact() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + std::vector vch(nSize); + nSize -= 4; + BN_bn2mpi(this, &vch[0]); + unsigned int nCompact = nSize << 24; + if (nSize >= 1) nCompact |= (vch[4] << 16); + if (nSize >= 2) nCompact |= (vch[5] << 8); + if (nSize >= 3) nCompact |= (vch[6] << 0); + return nCompact; + } - void SetHex(const std::string& str) - { - // skip 0x - const char* psz = str.c_str(); - while (isspace(*psz)) - psz++; - bool fNegative = false; - if (*psz == '-') - { - fNegative = true; - psz++; - } - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - while (isspace(*psz)) - psz++; + void SetHex(const std::string& str) + { + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; - // hex string to bignum - static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; - *this = 0; - while (isxdigit(*psz)) - { - *this <<= 4; - int n = phexdigit[(int) *psz++]; - *this += n; - } - if (fNegative) - *this = 0 - *this; - } + // hex string to bignum + static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[(int) *psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + } - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - std::string str; - CBigNum bn = *this; - BN_set_negative(&bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(&bn, &bn0) == 0) - return "0"; - while (BN_cmp(&bn, &bn0) > 0) - { - if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - bn = dv; - unsigned int c = rem.getulong(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(this)) - str += "-"; - reverse(str.begin(), str.end()); - return str; - } + std::string ToString(int nBase=10) const + { + CAutoBN_CTX pctx; + CBigNum bnBase = nBase; + CBigNum bn0 = 0; + std::string str; + CBigNum bn = *this; + BN_set_negative(&bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(&bn, &bn0) == 0) + return "0"; + while (BN_cmp(&bn, &bn0) > 0) + { + if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + bn = dv; + unsigned int c = rem.getulong(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(this)) + str += "-"; + reverse(str.begin(), str.end()); + return str; + } - std::string GetHex() const - { - return ToString(16); - } + std::string GetHex() const + { + return ToString(16); + } /* JED - unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const - { - return ::GetSerializeSize(getvch(), nType, nVersion); - } + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const + { + return ::GetSerializeSize(getvch(), nType, nVersion); + } - template - void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const - { - ::Serialize(s, getvch(), nType, nVersion); - } + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + ::Serialize(s, getvch(), nType, nVersion); + } - template - void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) - { - std::vector vch; - ::Unserialize(s, vch, nType, nVersion); - setvch(vch); - }*/ + template + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) + { + std::vector vch; + ::Unserialize(s, vch, nType, nVersion); + setvch(vch); + }*/ - bool operator!() const - { - return BN_is_zero(this); - } + bool operator!() const + { + return BN_is_zero(this); + } - CBigNum& operator+=(const CBigNum& b) - { - if (!BN_add(this, this, &b)) - throw bignum_error("CBigNum::operator+= : BN_add failed"); - return *this; - } + CBigNum& operator+=(const CBigNum& b) + { + if (!BN_add(this, this, &b)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; + } - CBigNum& operator-=(const CBigNum& b) - { - *this = *this - b; - return *this; - } + CBigNum& operator-=(const CBigNum& b) + { + *this = *this - b; + return *this; + } - CBigNum& operator*=(const CBigNum& b) - { - CAutoBN_CTX pctx; - if (!BN_mul(this, this, &b, pctx)) - throw bignum_error("CBigNum::operator*= : BN_mul failed"); - return *this; - } + CBigNum& operator*=(const CBigNum& b) + { + CAutoBN_CTX pctx; + if (!BN_mul(this, this, &b, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; + } - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } + CBigNum& operator/=(const CBigNum& b) + { + *this = *this / b; + return *this; + } - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } + CBigNum& operator%=(const CBigNum& b) + { + *this = *this % b; + return *this; + } - CBigNum& operator<<=(unsigned int shift) - { - if (!BN_lshift(this, this, shift)) - throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); - return *this; - } + CBigNum& operator<<=(unsigned int shift) + { + if (!BN_lshift(this, this, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; + } - CBigNum& operator>>=(unsigned int shift) - { - // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl - CBigNum a = 1; - a <<= shift; - if (BN_cmp(&a, this) > 0) - { - *this = 0; - return *this; - } + CBigNum& operator>>=(unsigned int shift) + { + // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number + // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl + CBigNum a = 1; + a <<= shift; + if (BN_cmp(&a, this) > 0) + { + *this = 0; + return *this; + } - if (!BN_rshift(this, this, shift)) - throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); - return *this; - } + if (!BN_rshift(this, this, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; + } - CBigNum& operator++() - { - // prefix operator - if (!BN_add(this, this, BN_value_one())) - throw bignum_error("CBigNum::operator++ : BN_add failed"); - return *this; - } + CBigNum& operator++() + { + // prefix operator + if (!BN_add(this, this, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; + } - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } + const CBigNum operator++(int) + { + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; + } - CBigNum& operator--() - { - // prefix operator - CBigNum r; - if (!BN_sub(&r, this, BN_value_one())) - throw bignum_error("CBigNum::operator-- : BN_sub failed"); - *this = r; - return *this; - } + CBigNum& operator--() + { + // prefix operator + CBigNum r; + if (!BN_sub(&r, this, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + return *this; + } - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } + const CBigNum operator--(int) + { + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; + } - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); }; inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) { - CBigNum r; - if (!BN_add(&r, &a, &b)) - throw bignum_error("CBigNum::operator+ : BN_add failed"); - return r; + CBigNum r; + if (!BN_add(&r, &a, &b)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; } inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) { - CBigNum r; - if (!BN_sub(&r, &a, &b)) - throw bignum_error("CBigNum::operator- : BN_sub failed"); - return r; + CBigNum r; + if (!BN_sub(&r, &a, &b)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; } inline const CBigNum operator-(const CBigNum& a) { - CBigNum r(a); - BN_set_negative(&r, !BN_is_negative(&r)); - return r; + CBigNum r(a); + BN_set_negative(&r, !BN_is_negative(&r)); + return r; } inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mul(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator* : BN_mul failed"); - return r; + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mul(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator* : BN_mul failed"); + return r; } inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_div(&r, NULL, &a, &b, pctx)) - throw bignum_error("CBigNum::operator/ : BN_div failed"); - return r; + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_div(&r, NULL, &a, &b, pctx)) + throw bignum_error("CBigNum::operator/ : BN_div failed"); + return r; } inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; - CBigNum r; - if (!BN_mod(&r, &a, &b, pctx)) - throw bignum_error("CBigNum::operator% : BN_div failed"); - return r; + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mod(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator% : BN_div failed"); + return r; } inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) { - CBigNum r; - if (!BN_lshift(&r, &a, shift)) - throw bignum_error("CBigNum:operator<< : BN_lshift failed"); - return r; + CBigNum r; + if (!BN_lshift(&r, &a, shift)) + throw bignum_error("CBigNum:operator<< : BN_lshift failed"); + return r; } inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) { - CBigNum r = a; - r >>= shift; - return r; + CBigNum r = a; + r >>= shift; + return r; } inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } @@ -540,3 +512,5 @@ inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } #endif + +// vim:ts=4 diff --git a/src/key.h b/src/key.h index b9fcd775cb..213bae4ddc 100644 --- a/src/key.h +++ b/src/key.h @@ -128,25 +128,45 @@ public: static EC_KEY* GenerateRootPubKey(BIGNUM* pubGenerator); static EC_KEY* GeneratePublicDeterministicKey(const NewcoinAddress& generator, int n); static EC_KEY* GeneratePrivateDeterministicKey(const NewcoinAddress& family, const BIGNUM* rootPriv, int n); + static EC_KEY* GeneratePrivateDeterministicKey(const NewcoinAddress& family, const uint256& rootPriv, int n); - CKey(const uint128& passPhrase) : fSet(true) + CKey(const uint128& passPhrase) : fSet(false) { pkey = GenerateRootDeterministicKey(passPhrase); + fSet = true; assert(pkey); } - CKey(const NewcoinAddress& generator, int n) : fSet(true) + CKey(const NewcoinAddress& generator, int n) : fSet(false) { // public deterministic key pkey = GeneratePublicDeterministicKey(generator, n); + fSet = true; assert(pkey); } - CKey(const NewcoinAddress& base, const BIGNUM* rootPrivKey, int n) : fSet(true) + CKey(const NewcoinAddress& base, const BIGNUM* rootPrivKey, int n) : fSet(false) { // private deterministic key pkey = GeneratePrivateDeterministicKey(base, rootPrivKey, n); + fSet = true; assert(pkey); } + CKey(const uint256& privateKey) : pkey(NULL), fSet(false) + { + 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); // broken, need seed + fSet = true; + } +#endif + bool IsNull() const { return !fSet; @@ -161,7 +181,7 @@ public: } bool SetPrivKey(const CPrivKey& vchPrivKey) - { + { // DEPRECATED const unsigned char* pbegin = &vchPrivKey[0]; if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) return false; @@ -171,7 +191,7 @@ public: } bool SetSecret(const CSecret& vchSecret) - { + { // DEPRECATED EC_KEY_free(pkey); pkey = EC_KEY_new_by_curve_name(NID_secp256k1); if (pkey == NULL) @@ -189,7 +209,7 @@ public: } CSecret GetSecret() - { + { // DEPRECATED CSecret vchRet; vchRet.resize(32); const BIGNUM *bn = EC_KEY_get0_private_key(pkey); @@ -203,10 +223,55 @@ public: } BIGNUM* GetSecretBN() const - { + { // DEPRECATED return BN_dup(EC_KEY_get0_private_key(pkey)); } + void GetPrivateKeyU(uint256& privKey) + { + const BIGNUM* bn = EC_KEY_get0_private_key(pkey); + if (bn == NULL) + throw key_error("CKey::GetPrivateKeyU: EC_KEY_get0_private_key failed"); + privKey.zero(); + BN_bn2bin(bn, privKey.begin() + (privKey.size() - BN_num_bytes(bn))); + } + + void SetPrivateKeyU(const uint256& key) + { + BIGNUM* bn = BN_bin2bn(key.begin(), key.size(), NULL); + if (!EC_KEY_set_private_key(pkey, bn)) + { + BN_clear_free(bn); + throw key_error("CKey::SetPrivateKeyU: EC_KEY_set_private_key failed"); + } + fSet = true; + BN_clear_free(bn); + } + + void SetPubSeq(const NewcoinAddress& masterKey, int keyNum) + { + EC_KEY* key = GeneratePublicDeterministicKey(masterKey, keyNum); + if (key == NULL) + throw key_error("CKey::SetPubSeq: GenPubDetKey failed"); + if (pkey != NULL) + EC_KEY_free(pkey); + pkey = key; + 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(); + if (pkey != NULL) + EC_KEY_free(pkey); + pkey = key; + fSet = true; + } +#endif + CPrivKey GetPrivKey() { unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);