Merge branch 'master' of github.com:jedmccaleb/NewCoin

Conflicts:
	src/Peer.cpp
This commit is contained in:
Arthur Britto
2012-04-24 14:59:12 -07:00
31 changed files with 628 additions and 473 deletions

View File

@@ -1,42 +1,32 @@
#include <boost/lexical_cast.hpp>
#include "AccountState.h"
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include "Ledger.h"
#include "Serializer.h"
AccountState::AccountState(const std::vector<unsigned char>& v)
AccountState::AccountState(const NewcoinAddress& id) : mAccountID(id), mValid(false)
{
Serializer s(v);
mValid=false;
uint160 acct160 = mAccountID.getAccountID();
if(!s.get160(acct160, 0)) { assert(false); return; }
if(!s.get64(mBalance, 20)) { assert(false); return; }
if(!s.get32(mAccountSeq, 28)) { assert(false); return; }
mValid=true;
if (!id.IsValid()) return;
mLedgerEntry = boost::make_shared<SerializedLedgerEntry>(ltACCOUNT_ROOT);
mLedgerEntry->setIndex(Ledger::getAccountRootIndex(id));
mLedgerEntry->setIFieldAccount(sfAccount, id);
mValid = true;
}
AccountState::AccountState(const NewcoinAddress& id) : mAccountID(id), mBalance(0), mAccountSeq(0), mValid(true)
{ ; }
std::vector<unsigned char> AccountState::getRaw() const
{ // 20-byte acct ID, 8-byte balance, 4-byte sequence
Serializer s(32);
s.add160(mAccountID.getAccountID());
s.add64(mBalance);
s.add32(mAccountSeq);
return s.getData();
AccountState::AccountState(SerializedLedgerEntry::pointer ledgerEntry) : mLedgerEntry(ledgerEntry), mValid(false)
{
if (!mLedgerEntry) return;
if (mLedgerEntry->getType()!=ltACCOUNT_ROOT) return;
mAccountID = mLedgerEntry->getValueFieldAccount(sfAccount);
if (mAccountID.IsValid()) mValid = true;
}
void AccountState::addJson(Json::Value& val)
{
Json::Value as(Json::objectValue);
as["AccountID"]=mAccountID.humanAccountID();
as["Balance"]=boost::lexical_cast<std::string>(mBalance);
as["SendSequence"]=mAccountSeq;
if(!mValid) as["Invalid"]=true;
val[mAccountID.humanAccountID()]=as;
val = mLedgerEntry->getJson(0);
if(!mValid) val["Invalid"]=true;
}
// vim:ts=4

View File

@@ -1,7 +1,8 @@
#ifndef __ACCOUNTSTATE__
#define __ACCOUNTSTATE__
// An account's state in one or more accepted ledgers
// An account's state
// Used to track information about a local account
#include <vector>
@@ -10,47 +11,30 @@
#include "../json/value.h"
#include "types.h"
#include "uint256.h"
#include "NewcoinAddress.h"
#include "SerializedLedger.h"
class AccountState
{
public:
typedef boost::shared_ptr<AccountState> pointer;
typedef boost::shared_ptr<AccountState> pointer;
private:
NewcoinAddress mAccountID;
uint64 mBalance;
uint32 mAccountSeq;
bool mValid;
NewcoinAddress mAccountID;
SerializedLedgerEntry::pointer mLedgerEntry;
bool mValid;
public:
AccountState(const NewcoinAddress& mAccountID); // new account
AccountState(const std::vector<unsigned char>&); // raw form
AccountState(const NewcoinAddress& AccountID); // For new accounts
AccountState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
const NewcoinAddress& getAccountID() const { return mAccountID; }
uint64 getBalance() const { return mBalance; }
uint32 getSeq() const { return mAccountSeq; }
uint64 getBalance() const { return mLedgerEntry->getIFieldU64(sfBalance); }
uint32 getSeq() const { return mLedgerEntry->getIFieldU32(sfSequence); }
void credit(const uint64& a)
{
mBalance+=a;
if(!mAccountSeq) mAccountSeq=1; // an account with non-0 balance cannot have 0 sequence
}
void charge(const uint64& a)
{
assert(mBalance>=a);
mBalance-=a;
}
void incSeq()
{
mAccountSeq++;
}
void decSeq()
{
assert(mAccountSeq!=0);
mAccountSeq--;
}
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; }
std::vector<unsigned char> getRaw() const;
void addJson(Json::Value& value);

View File

@@ -117,7 +117,7 @@ void Application::run()
// temporary
mWallet.load();
mWallet.syncToLedger(true, &(*secondLedger));
// mWallet.syncToLedger(true, &(*secondLedger));
// temporary
mIOService.run(); // This blocks
@@ -128,7 +128,7 @@ void Application::run()
Application::~Application()
{
delete mTxnDB;;
delete mTxnDB;
delete mLedgerDB;
delete mWalletDB;
delete mHashNodeDB;

View File

@@ -22,10 +22,11 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) :
mTransactionMap = boost::make_shared<SHAMap>();
mAccountStateMap = boost::make_shared<SHAMap>();
// special case: put coins in root account
AccountState::pointer startAccount = boost::make_shared<AccountState>(masterID);
startAccount->credit(startAmount);
if (!addAccountState(startAccount))
assert(false);
startAccount->peekSLE().setIFieldU64(sfBalance, startAmount);
startAccount->peekSLE().setIFieldU32(sfSequence, 1);
writeBack(lepCREATE, startAccount->getSLE());
}
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
@@ -116,7 +117,7 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
std::cerr << "Ledger:getAccountState(" << accountID.humanAccountID() << ")" << std::endl;
#endif
ScopedLock l(mTransactionMap->Lock());
SHAMapItem::pointer item = mAccountStateMap->peekItem(accountID.getAccountID().to256());
SHAMapItem::pointer item = mAccountStateMap->peekItem(Ledger::getAccountRootIndex(accountID));
if (!item)
{
#ifdef DEBUG
@@ -124,30 +125,10 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
#endif
return AccountState::pointer();
}
return boost::make_shared<AccountState>(item->getData());
}
uint64 Ledger::getBalance(const NewcoinAddress& accountID) const
{
ScopedLock l(mTransactionMap->Lock());
SHAMapItem::pointer item = mAccountStateMap->peekItem(accountID.getAccountID().to256());
if (!item) return 0;
return AccountState(item->getData()).getBalance();
}
bool Ledger::updateAccountState(AccountState::pointer state)
{
assert(!mAccepted);
return mAccountStateMap->updateGiveItem(boost::make_shared<SHAMapItem>(state->getAccountID().getAccountID(),
state->getRaw()), false);
}
bool Ledger::addAccountState(AccountState::pointer state)
{
assert(!mAccepted);
assert( (state->getBalance()==0) || (state->getSeq()>0) );
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(state->getAccountID().getAccountID(), state->getRaw());
return mAccountStateMap->addGiveItem(item, false);
SerializedLedgerEntry::pointer sle =
boost::make_shared<SerializedLedgerEntry>(item->peekSerializer(), item->getTag());
if (sle->getType() != ltACCOUNT_ROOT) return AccountState::pointer();
return boost::make_shared<AccountState>(sle);
}
bool Ledger::addTransaction(Transaction::pointer trans)
@@ -160,6 +141,12 @@ bool Ledger::addTransaction(Transaction::pointer trans)
return mTransactionMap->addGiveItem(item, true);
}
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
{ // low-level - just add to table
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
return mTransactionMap->addGiveItem(item, true);
}
bool Ledger::delTransaction(const uint256& transID)
{
assert(!mAccepted);
@@ -187,145 +174,6 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const
return txn;
}
Ledger::TransResult Ledger::applyTransaction(Transaction::pointer trans)
{
assert(!mAccepted);
boost::recursive_mutex::scoped_lock sl(mLock);
if (trans->getSourceLedger() > mLedgerSeq) return TR_BADLSEQ;
if (trans->getAmount()<trans->getFee())
{
#ifdef DEBUG
std::cerr << "Transaction for " << trans->getAmount() << ", but fee is " <<
trans->getFee() << std::endl;
#endif
return TR_TOOSMALL;
}
if(!mTransactionMap || !mAccountStateMap) return TR_ERROR;
try
{
// already applied?
Transaction::pointer dupTrans=getTransaction(trans->getID());
if(dupTrans) return TR_ALREADY;
// accounts exist?
AccountState::pointer fromAccount=getAccountState(trans->getFromAccount());
AccountState::pointer toAccount=getAccountState(trans->getToAccount());
// temporary code -- if toAccount doesn't exist but fromAccount does, create it
if(!!fromAccount && !toAccount)
{
toAccount=boost::make_shared<AccountState>(trans->getToAccount());
toAccount->incSeq(); // an account in a ledger has a sequence of 1
updateAccountState(toAccount);
}
if(!fromAccount || !toAccount) return TR_BADACCT;
// pass sanity checks?
if(fromAccount->getBalance()<trans->getAmount())
{
#ifdef DEBUG
std::cerr << "Transaction for " << trans->getAmount() << ", but account has " <<
fromAccount->getBalance() << std::endl;
#endif
return TR_INSUFF;
}
#ifdef DEBUG
if(fromAccount->getSeq()!=trans->getFromAccountSeq())
std::cerr << "aSeq=" << fromAccount->getSeq() << ", tSeq=" << trans->getFromAccountSeq() << std::endl;
#endif
if(fromAccount->getSeq()>trans->getFromAccountSeq()) return TR_PASTASEQ;
if(fromAccount->getSeq()<trans->getFromAccountSeq()) return TR_PREASEQ;
// apply
fromAccount->charge(trans->getAmount());
fromAccount->incSeq();
toAccount->credit(trans->getAmount()-trans->getFee());
mFeeHeld+=trans->getFee();
trans->setStatus(INCLUDED, mLedgerSeq);
updateAccountState(fromAccount);
updateAccountState(toAccount);
addTransaction(trans);
return TR_SUCCESS;
}
catch (SHAMapException)
{
return TR_ERROR;
}
}
Ledger::TransResult Ledger::removeTransaction(Transaction::pointer trans)
{ // high-level - reverse application of transaction
assert(!mAccepted);
boost::recursive_mutex::scoped_lock sl(mLock);
if(!mTransactionMap || !mAccountStateMap) return TR_ERROR;
try
{
Transaction::pointer ourTrans=getTransaction(trans->getID());
if(!ourTrans) return TR_NOTFOUND;
// accounts exist
AccountState::pointer fromAccount=getAccountState(trans->getFromAccount());
AccountState::pointer toAccount=getAccountState(trans->getToAccount());
if(!fromAccount || !toAccount) return TR_BADACCT;
// pass sanity checks?
if(toAccount->getBalance()<trans->getAmount()) return TR_INSUFF;
if(fromAccount->getSeq()!=(trans->getFromAccountSeq()+1)) return TR_PASTASEQ;
// reverse
fromAccount->credit(trans->getAmount());
fromAccount->decSeq();
toAccount->charge(trans->getAmount()-trans->getFee());
mFeeHeld-=trans->getFee();
trans->setStatus(REMOVED, mLedgerSeq);
if(!delTransaction(trans->getID()))
{
assert(false);
return TR_ERROR;
}
updateAccountState(fromAccount);
updateAccountState(toAccount);
return TR_SUCCESS;
}
catch (SHAMapException)
{
return TR_ERROR;
}
}
Ledger::TransResult Ledger::hasTransaction(Transaction::pointer trans)
{ // Is this transaction in this ledger? If not, could it go in it?
boost::recursive_mutex::scoped_lock sl(mLock);
if(mTransactionMap==NULL) return TR_ERROR;
try
{
Transaction::pointer t=getTransaction(trans->getID());
if(!!t) return TR_ALREADY;
if(trans->getSourceLedger()>mLedgerSeq) return TR_BADLSEQ;
AccountState::pointer fromAccount=getAccountState(trans->getFromAccount());
if(!fromAccount) return TR_BADACCT; // cannot send from non-existent account
// may be in a previous ledger
if(fromAccount->getSeq()>trans->getFromAccountSeq()) return TR_PASTASEQ;
if(fromAccount->getSeq()<trans->getFromAccountSeq()) return TR_PREASEQ;
if(fromAccount->getBalance()<trans->getAmount()) return TR_INSUFF;
return TR_NOTFOUND;
}
catch (SHAMapException)
{
return TR_ERROR;
}
}
Ledger::pointer Ledger::closeLedger(uint64 timeStamp)
{ // close this ledger, return a pointer to the next ledger
// CAUTION: New ledger needs its SHAMap's connected to storage
@@ -334,18 +182,6 @@ Ledger::pointer Ledger::closeLedger(uint64 timeStamp)
return Ledger::pointer(new Ledger(*this, timeStamp)); // can't use make_shared, constructor is protected
}
void LocalAccount::syncLedger()
{
AccountState::pointer as=theApp->getMasterLedger().getAccountState(getAddress());
if(!as) mLgrBalance=0;
else
{
mLgrBalance=as->getBalance();
if( (mLgrBalance!=0) && (mTxnSeq==0) ) mTxnSeq=1;
if(mTxnSeq<as->getSeq()) mTxnSeq=as->getSeq();
}
}
bool Ledger::unitTest()
{
#if 0

View File

@@ -10,16 +10,16 @@
#include "../json/value.h"
#include "Transaction.h"
#include "AccountState.h"
#include "types.h"
#include "BitcoinUtil.h"
#include "Hanko.h"
#include "AccountState.h"
#include "SHAMap.h"
#include "SerializedLedger.h"
enum LedgerStateParms
{
lepNONE = 0, // no special flags
// input flags
lepCREATE, // Create if not present
@@ -33,6 +33,7 @@ enum LedgerStateParms
class Ledger : public boost::enable_shared_from_this<Ledger>
{ // The basic Ledger structure, can be opened, closed, or synching
friend class TransactionEngine;
public:
typedef boost::shared_ptr<Ledger> pointer;
@@ -70,13 +71,15 @@ protected:
Ledger(Ledger& previous, uint64 timestamp); // ledger after this one
void updateHash();
bool addAccountState(AccountState::pointer);
bool updateAccountState(AccountState::pointer);
bool addTransaction(Transaction::pointer);
bool addTransaction(const uint256& id, const Serializer& txn);
bool delTransaction(const uint256& id);
static Ledger::pointer getSQL(const std::string& sqlStatement);
SerializedLedgerEntry::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
LedgerEntryType let);
public:
Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
@@ -114,15 +117,10 @@ public:
bool hasTransaction(const uint256& TransID) const;
Transaction::pointer getTransaction(const uint256& transID) const;
// OLD high level functions
uint64 getBalance(const NewcoinAddress& acctID) const;
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
TransResult applyTransaction(Transaction::pointer trans);
TransResult removeTransaction(Transaction::pointer trans);
TransResult hasTransaction(Transaction::pointer trans);
Ledger::pointer switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit);
// high-level functions
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
LedgerStateParms writeBack(LedgerStateParms parms, SerializedLedgerEntry::pointer);
SerializedLedgerEntry::pointer getAccountRoot(LedgerStateParms& parms, const uint160& accountID);
SerializedLedgerEntry::pointer getNickname(LedgerStateParms& parms, const std::string& nickname);
@@ -137,7 +135,15 @@ public:
// index calculation functions
static uint256 getAccountRootIndex(const uint160& account);
static uint256 getAccountRootIndex(const NewcoinAddress& account)
{ return getAccountRootIndex(account.getAccountID()); }
static uint256 getRippleIndex(const uint160& account, const uint160& extendTo, const uint160& currency);
static uint256 getRippleIndex(const uint160& account, const uint160& extendTo)
{ return getRippleIndex(account, extendTo, uint160()); }
static uint256 getRippleIndex(const NewcoinAddress& account, const NewcoinAddress& extendTo,
const uint160& currency)
{ return getRippleIndex(account.getAccountID(), extendTo.getAccountID(), currency); }
Ledger::pointer closeLedger(uint64 timestamp);
bool isCompatible(boost::shared_ptr<Ledger> other);

View File

@@ -14,20 +14,6 @@ uint32 LedgerMaster::getCurrentLedgerIndex()
return mCurrentLedger->getLedgerSeq();
}
uint64 LedgerMaster::getBalance(const NewcoinAddress& acctID)
{
return mCurrentLedger->getBalance(acctID);
}
uint64 LedgerMaster::getBalance(std::string& strAcctID)
{
NewcoinAddress acctID;
acctID.setAccountID(strAcctID);
return mCurrentLedger->getBalance(acctID);
}
bool LedgerMaster::addHeldTransaction(Transaction::pointer transaction)
{ // returns true if transaction was added
boost::recursive_mutex::scoped_lock ml(mLock);
@@ -43,8 +29,9 @@ void LedgerMaster::pushLedger(Ledger::pointer newLedger)
mFinalizingLedger->setAccepted();
mLedgerHistory.addAcceptedLedger(mFinalizingLedger);
}
mFinalizingLedger=mCurrentLedger;
mCurrentLedger=newLedger;
mFinalizingLedger = mCurrentLedger;
mCurrentLedger = newLedger;
mEngine.setLedger(newLedger);
}
#if 0

View File

@@ -6,6 +6,7 @@
#include "Peer.h"
#include "types.h"
#include "Transaction.h"
#include "TransactionEngine.h"
// Tracks the current ledger and any ledgers in the process of closing
// Tracks ledger history
@@ -16,6 +17,8 @@ class LedgerMaster
boost::recursive_mutex mLock;
bool mIsSynced;
TransactionEngine mEngine;
Ledger::pointer mCurrentLedger;
Ledger::pointer mFinalizingLedger;
@@ -38,6 +41,9 @@ public:
Ledger::pointer getCurrentLedger() { return mCurrentLedger; }
Ledger::pointer getClosingLedger() { return mFinalizingLedger; }
TransactionEngineResult doTransaction(const SerializedTransaction& txn, TransactionEngineParams params)
{ return mEngine.applyTransaction(txn, params); }
void pushLedger(Ledger::pointer newLedger);
Ledger::pointer getLedgerBySeq(uint32 index)
@@ -54,12 +60,9 @@ public:
return mLedgerHistory.getLedgerByHash(hash);
}
uint64 getBalance(std::string& strAcctID);
uint64 getBalance(const NewcoinAddress& acctID);
AccountState::pointer getAccountState(const NewcoinAddress& addr)
{ return mCurrentLedger->getAccountState(addr); }
bool addHeldTransaction(Transaction::pointer trans);
uint64 getBalance(std::string& strAcctID, const uint160 currency = 0);
uint64 getBalance(const NewcoinAddress& acctID, const uint160 currency = 0);
};
#endif

View File

@@ -3,12 +3,30 @@
#include "boost/make_shared.hpp"
SerializedLedgerEntry::pointer Ledger::getAccountRoot(LedgerStateParms& parms, const uint160& accountID)
LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SerializedLedgerEntry::pointer entry)
{
uint256 nodeID=getAccountRootIndex(accountID);
ScopedLock l(mAccountStateMap->Lock());
bool create = false;
if (!mAccountStateMap->hasItem(entry->getIndex()))
{
if ((parms & lepCREATE) == 0)
return lepMISSING;
create = true;
}
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(entry->getIndex());
entry->add(item->peekSerializer());
if (!mAccountStateMap->updateGiveItem(item, false))
return lepERROR;
return create ? lepCREATED : lepOKAY;
}
SerializedLedgerEntry::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID,
LedgerEntryType let )
{
SHAMapItem::pointer account = mAccountStateMap->peekItem(nodeID);
if (!account)
{
@@ -18,26 +36,57 @@ SerializedLedgerEntry::pointer Ledger::getAccountRoot(LedgerStateParms& parms, c
return SerializedLedgerEntry::pointer();
}
parms = lepCREATED;
SerializedLedgerEntry::pointer sle=boost::make_shared<SerializedLedgerEntry>(ltACCOUNT_ROOT);
parms = parms | lepCREATED | lepOKAY;
SerializedLedgerEntry::pointer sle=boost::make_shared<SerializedLedgerEntry>(let);
sle->setIndex(nodeID);
return sle;
}
SerializedLedgerEntry::pointer sle =
boost::make_shared<SerializedLedgerEntry>(account->peekSerializer(), nodeID);
if(sle->getType() != let)
{ // maybe it's a currency or something
parms = parms | lepWRONGTYPE;
return SerializedLedgerEntry::pointer();
}
parms = parms | lepOKAY;
return sle;
}
SerializedLedgerEntry::pointer Ledger::getAccountRoot(LedgerStateParms& parms, const uint160& accountID)
{
uint256 nodeID=getAccountRootIndex(accountID);
ScopedLock l(mAccountStateMap->Lock());
try
{
SerializedLedgerEntry::pointer sle =
boost::make_shared<SerializedLedgerEntry>(account->peekSerializer(), nodeID);
if(sle->getType() != ltACCOUNT_ROOT)
{ // maybe it's a currency or something
parms = lepWRONGTYPE;
return SerializedLedgerEntry::pointer();
}
parms = lepOKAY;
return sle;
return getASNode(parms, nodeID, ltACCOUNT_ROOT);
}
catch(...)
catch (...)
{
parms = lepERROR;
return SerializedLedgerEntry::pointer();
}
}
SerializedLedgerEntry::pointer Ledger::getNickname(LedgerStateParms& parms, const std::string& nickname)
{
return getNickname(parms, Serializer::getSHA512Half(nickname));
}
SerializedLedgerEntry::pointer Ledger::getNickname(LedgerStateParms& parms, const uint256& nickHash)
{
ScopedLock l(mAccountStateMap->Lock());
try
{
return getASNode(parms, nickHash, ltNICKNAME);
}
catch (...)
{
parms = lepERROR;
return SerializedLedgerEntry::pointer();

View File

@@ -4,6 +4,8 @@
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include "AccountState.h"
class LocalAccountFamily;
class LocalAccount
@@ -21,11 +23,6 @@ protected:
boost::shared_ptr<LocalAccountFamily> mFamily;
int mAccountFSeq;
// local usage tracking
uint64 mLgrBalance; // The balance, from the last ledger
int64 mTxnDelta; // The balance changes from local/pending transactions
uint32 mTxnSeq; // The sequence number of the next transaction
public:
LocalAccount(boost::shared_ptr<LocalAccountFamily> family, int accountSeq);
@@ -48,16 +45,8 @@ public:
CKey::pointer getPrivateKey();
Json::Value getJson() const;
void update(uint64 balance, uint32 seq);
uint32 getTxnSeq() const { return mTxnSeq; }
uint32 incTxnSeq() { return mTxnSeq++; }
int64 getEffectiveBalance() const { return static_cast<int64_t>(mLgrBalance)+mTxnDelta; }
void credit(uint64 amount) { mTxnDelta+=amount; }
void debit(uint64 amount) { mTxnDelta-=amount; }
void setLedgerBalance(uint64_t lb) { mLgrBalance=lb; if(mTxnSeq==0) mTxnSeq=1; }
void syncLedger();
AccountState::pointer getAccountState() const;
uint64 getEffectiveBalance() const;
};
class LocalAccountFamily : public boost::enable_shared_from_this<LocalAccountFamily>

View File

@@ -38,10 +38,10 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans;
}
Ledger::TransResult r=theApp->getMasterLedger().getCurrentLedger()->applyTransaction(trans);
if(r==Ledger::TR_ERROR) throw Fault(IO_ERROR);
TransactionEngineResult r=theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
if(r==terFAILED) throw Fault(IO_ERROR);
if((r==Ledger::TR_PREASEQ) || (r==Ledger::TR_BADLSEQ))
if(r == terPRE_SEQ)
{ // transaction should be held
#ifdef DEBUG
std::cerr << "Transaction should be held" << std::endl;
@@ -51,7 +51,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
theApp->getMasterLedger().addHeldTransaction(trans);
return trans;
}
if( (r==Ledger::TR_PASTASEQ) || (r==Ledger::TR_ALREADY) )
if ( (r==terPAST_SEQ || r==terPAST_LEDGER) )
{ // duplicate or conflict
#ifdef DEBUG
std::cerr << "Transaction is obsolete" << std::endl;
@@ -60,14 +60,18 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans;
}
if(r==Ledger::TR_SUCCESS)
if(r==terSUCCESS)
{
#ifdef DEBUG
std::cerr << "Transaction is now included, synching to wallet" << std::endl;
#endif
trans->setStatus(INCLUDED);
theApp->getMasterTransaction().canonicalize(trans, true);
theApp->getWallet().applyTransaction(trans);
// FIXME: Need code to get all accounts affected by a transaction and re-synch
// any of them that affect local accounts cached in memory. Or, we need to
// no cache the account balance information and always get it from the current ledger
// theApp->getWallet().applyTransaction(trans);
newcoin::TMTransaction *tx=new newcoin::TMTransaction();

View File

@@ -339,14 +339,13 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
Transaction::pointer tx;
try
{
std::string rawTx=packet.rawtransaction();
std::string rawTx = packet.rawtransaction();
Serializer s(std::vector<unsigned char>(rawTx.begin(), rawTx.end()));
SerializerIterator sit(s);
SerializedTransaction::pointer stx=boost::make_shared<SerializedTransaction>(boost::ref(sit), -1);
SerializedTransaction::pointer stx = boost::make_shared<SerializedTransaction>(boost::ref(sit), -1);
if(stx->getTxnType()!=ttMAKE_PAYMENT) throw(0); // FIXME to support other transaction
tx=boost::make_shared<Transaction>(stx, true);
if(tx->getStatus()==INVALID) throw(0);
tx = boost::make_shared<Transaction>(stx, true);
if (tx->getStatus() == INVALID) throw(0);
}
catch (...)
{
@@ -358,7 +357,7 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
return;
}
tx=theApp->getOPs().processTransaction(tx, this);
tx = theApp->getOPs().processTransaction(tx, this);
if(tx->getStatus()!=INCLUDED)
{ // transaction wasn't accepted into ledger

View File

@@ -1,8 +1,13 @@
#include "PeerDoor.h"
#include "Config.h"
#include <iostream>
#include <boost/bind.hpp>
//#include <boost/log/trivial.hpp>
#include <iostream>
#include "Config.h"
using namespace std;
using namespace boost::asio::ip;

View File

@@ -155,10 +155,6 @@ SHAMapItem::SHAMapItem(const uint256& tag, const std::vector<unsigned char>& dat
: mTag(tag), mData(data)
{ ; }
SHAMapItem::SHAMapItem(const uint160& tag, const std::vector<unsigned char>& data)
: mTag(tag.to256()), mData(data)
{ ; }
SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode::pointer node)
{
// Return the first item below this node

View File

@@ -95,13 +95,10 @@ private:
public:
// for transactions
SHAMapItem(const uint256& tag) : mTag(tag) { ; }
SHAMapItem(const uint256& tag, const std::vector<unsigned char>& data);
SHAMapItem(const std::vector<unsigned char>& data); // tag by hash
// for account balances
SHAMapItem(const uint160& tag, const std::vector<unsigned char>& data);
const uint256& getTag() const { return mTag; }
std::vector<unsigned char> getData() const { return mData.getData(); }
const std::vector<unsigned char>& peekData() const { return mData.peekData(); }
@@ -287,9 +284,6 @@ public:
SHAMapItem::pointer peekNextItem(const uint256&);
SHAMapItem::pointer peekPrevItem(const uint256&);
SHAMapItem::pointer peekPrevItem(const uint160& u) { return peekPrevItem(u.to256()); }
SHAMapItem::pointer peekNextItem(const uint160& u) { return peekNextItem(u.to256()); }
// comparison/sync functions
void getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& hashes, int max);
bool getNodeFat(const SHAMapNode& node, std::vector<SHAMapNode>& nodeIDs,

View File

@@ -192,9 +192,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
}
else if(type==1)
{ // account state
uint160 u;
s.get160(u, len-20);
s.chop(20);
uint256 u;
s.get256(u, len-32);
s.chop(256/8);
if(u.isZero()) throw SHAMapException(InvalidNode);
mItem=boost::make_shared<SHAMapItem>(u, s.peekData());
mType=tnACCOUNT_STATE;
@@ -236,7 +236,7 @@ void SHAMapTreeNode::addRaw(Serializer &s)
if(mType==tnACCOUNT_STATE)
{
mItem->addRaw(s);
s.add160(mItem->getTag().to160());
s.add256(mItem->getTag());
s.add8(1);
return;
}

View File

@@ -313,7 +313,7 @@ static SHAMapItem::pointer makeRandomAS()
Serializer s;
for(int d=0; d<3; d++)
s.add32(rand());
return boost::make_shared<SHAMapItem>(s.getRIPEMD160(), s.peekData());
return boost::make_shared<SHAMapItem>(s.getRIPEMD160().to256(), s.peekData());
}
static bool confuseMap(SHAMap &map, int count)

View File

@@ -4,6 +4,11 @@
#include <boost/thread/recursive_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/ref.hpp>
// A lock holder that can be returned and copied by value
// When the last reference goes away, the lock is released
class ScopedLock
{
@@ -11,9 +16,9 @@ protected:
mutable boost::shared_ptr<boost::interprocess::scoped_lock<boost::recursive_mutex> > mHolder;
public:
ScopedLock(boost::recursive_mutex &mutex) :
mHolder(new boost::interprocess::scoped_lock<boost::recursive_mutex>(mutex))
{ ; }
ScopedLock(boost::recursive_mutex& mutex) :
mHolder(boost::make_shared<boost::interprocess::scoped_lock<boost::recursive_mutex> >(boost::ref(mutex)))
{ ; }
void lock() const
{
mHolder->lock();

View File

@@ -3,6 +3,7 @@
#include "SerializedObject.h"
#include "LedgerFormats.h"
#include "NewcoinAddress.h"
class SerializedLedgerEntry : public STObject
{
@@ -50,7 +51,8 @@ public:
uint256 getIFieldH256(SOE_Field field) const { return mObject.getValueFieldH256(field); }
std::vector<unsigned char> getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); }
std::vector<TaggedListItem> getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); }
void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); }
NewcoinAddress getIValueFieldAccount(SOE_Field field) const { return mObject.getValueFieldAccount(field); }
void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); }
void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); }
void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); }
void setIFieldU64(SOE_Field field, uint32 v) { return mObject.setValueFieldU64(field, v); }
@@ -60,12 +62,14 @@ public:
{ return mObject.setValueFieldVL(field, v); }
void setIFieldTL(SOE_Field field, const std::vector<TaggedListItem>& v)
{ return mObject.setValueFieldTL(field, v); }
void setIFieldAccount(SOE_Field field, const uint160& account)
{ return mObject.setValueFieldAccount(field, account); }
void setIFieldAccount(SOE_Field field, const NewcoinAddress& account)
{ return mObject.setValueFieldAccount(field, account); }
bool getIFieldPresent(SOE_Field field) const { return mObject.isFieldPresent(field); }
void makeIFieldPresent(SOE_Field field) { return mObject.makeFieldPresent(field); }
void makeIFieldAbsent(SOE_Field field) { return mObject.makeFieldAbsent(field); }
};
#endif

View File

@@ -350,6 +350,17 @@ uint256 STObject::getValueFieldH256(SOE_Field field) const
return cf->getValue();
}
NewcoinAddress STObject::getValueFieldAccount(SOE_Field field) const
{
const SerializedType* rf = peekAtPField(field);
if (!rf) throw std::runtime_error("Field not found");
SerializedTypeID id = rf->getSType();
if (id == STI_OBJECT) return NewcoinAddress(); // optional field not present
const STAccount* cf = dynamic_cast<const STAccount *>(rf);
if (!cf) throw std::runtime_error("Wrong field type");
return cf->getValueNCA();
}
std::vector<unsigned char> STObject::getValueFieldVL(SOE_Field field) const
{
const SerializedType* rf = peekAtPField(field);
@@ -452,6 +463,22 @@ void STObject::setValueFieldH160(SOE_Field field, const uint160& v)
cf->setValue(v);
}
void STObject::setValueFieldAccount(SOE_Field field, const uint160& v)
{
SerializedType* rf = getPField(field);
if (!rf) throw std::runtime_error("Field not found");
SerializedTypeID id = rf->getSType();
if (id == STI_OBJECT)
{
makeFieldPresent(field);
rf = getPField(field);
id = rf->getSType();
}
STAccount* cf = dynamic_cast<STAccount*>(rf);
if (!cf) throw std::runtime_error("Wrong field type");
cf->setValueH160(v);
}
void STObject::setValueFieldVL(SOE_Field field, const std::vector<unsigned char>& v)
{
SerializedType* rf = getPField(field);

View File

@@ -102,6 +102,7 @@ public:
uint64 getValueFieldU64(SOE_Field field) const;
uint160 getValueFieldH160(SOE_Field field) const;
uint256 getValueFieldH256(SOE_Field field) const;
NewcoinAddress getValueFieldAccount(SOE_Field field) const;
std::vector<unsigned char> getValueFieldVL(SOE_Field field) const;
std::vector<TaggedListItem> getValueFieldTL(SOE_Field field) const;
@@ -113,6 +114,9 @@ public:
void setValueFieldH256(SOE_Field field, const uint256&);
void setValueFieldVL(SOE_Field field, const std::vector<unsigned char>&);
void setValueFieldTL(SOE_Field field, const std::vector<TaggedListItem>&);
void setValueFieldAccount(SOE_Field field, const uint160&);
void setValueFieldAccount(SOE_Field field, const NewcoinAddress& addr)
{ setValueFieldAccount(field, addr.getAccountID()); }
bool isFieldPresent(SOE_Field field) const;
void makeFieldPresent(SOE_Field field);

View File

@@ -1,13 +1,13 @@
#include "SerializedTransaction.h"
SerializedTransaction::SerializedTransaction(TransactionType type)
SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type)
{
mFormat=getTxnFormat(type);
mFormat = getTxnFormat(type);
if (mFormat == NULL) throw std::runtime_error("invalid transaction type");
mMiddleTxn.giveObject(new STUInt32("Magic", TransactionMagic));
mMiddleTxn.giveObject(new STVariableLength("SigningAccount"));
mMiddleTxn.giveObject(new STVariableLength("SigningPubKey"));
mMiddleTxn.giveObject(new STUInt32("Sequence"));
mMiddleTxn.giveObject(new STUInt8("Type", static_cast<unsigned char>(type)));
mMiddleTxn.giveObject(new STUInt64("Fee"));
@@ -28,16 +28,24 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit, int length
throw std::runtime_error("Transaction has invalid magic");
mMiddleTxn.giveObject(new STUInt32("Magic", TransactionMagic));
mMiddleTxn.giveObject(new STVariableLength("SigningAccount", sit.getVL()));
mMiddleTxn.giveObject(new STVariableLength("SigningPubKey", sit.getVL()));
mMiddleTxn.giveObject(new STUInt32("Sequence", sit.get32()));
int type = sit.get32();
mMiddleTxn.giveObject(new STUInt32("Type", type));
mFormat = getTxnFormat(static_cast<TransactionType>(type));
mType = static_cast<TransactionType>(sit.get32());
mMiddleTxn.giveObject(new STUInt32("Type", static_cast<uint32>(mType)));
mFormat = getTxnFormat(mType);
if (!mFormat) throw std::runtime_error("Transaction has invalid type");
mMiddleTxn.giveObject(new STUInt64("Fee", sit.get64()));
mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction");
updateSourceAccount();
}
void SerializedTransaction::updateSourceAccount()
{
NewcoinAddress a;
a.setAccountPublic(peekSigningPubKey());
mSourceAccount.setAccountID(a.getAccountID());
}
int SerializedTransaction::getLength() const
@@ -67,6 +75,21 @@ std::string SerializedTransaction::getText() const
return ret;
}
std::vector<NewcoinAddress> SerializedTransaction::getAffectedAccounts() const
{
std::vector<NewcoinAddress> accounts;
accounts.push_back(mSourceAccount);
for(boost::ptr_vector<SerializedType>::const_iterator it = mInnerTxn.peekData().begin(),
end = mInnerTxn.peekData().end(); it != end ; ++it)
{
const STAccount* sa = dynamic_cast<const STAccount*>(&*it);
if (sa != NULL) // FIXME: Should we check for duplicates?
accounts.push_back(sa->getValueNCA());
}
return accounts;
}
int SerializedTransaction::getTransaction(Serializer& s, bool include_length) const
{
int l = getLength();
@@ -81,7 +104,7 @@ bool SerializedTransaction::isEquivalent(const SerializedType& t) const
{ // Signatures are not compared
const SerializedTransaction* v = dynamic_cast<const SerializedTransaction*>(&t);
if (!v) return false;
if (type != v->type) return false;
if (mType != v->mType) return false;
if (mMiddleTxn != v->mMiddleTxn) return false;
if (mInnerTxn != v->mInnerTxn) return false;
return true;
@@ -171,34 +194,48 @@ void SerializedTransaction::setSequence(uint32 seq)
v->setValue(seq);
}
std::vector<unsigned char> SerializedTransaction::getSigningAccount() const
std::vector<unsigned char> SerializedTransaction::getSigningPubKey() const
{
const STVariableLength* v =
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningAccount));
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->getValue();
}
const std::vector<unsigned char>& SerializedTransaction::peekSigningAccount() const
const std::vector<unsigned char>& SerializedTransaction::peekSigningPubKey() const
{
const STVariableLength* v=
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningAccount));
dynamic_cast<const STVariableLength*>(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->peekValue();
}
std::vector<unsigned char>& SerializedTransaction::peekSigningAccount()
std::vector<unsigned char>& SerializedTransaction::peekSigningPubKey()
{
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningAccount));
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
return v->peekValue();
}
void SerializedTransaction::setSigningAccount(const std::vector<unsigned char>& s)
const NewcoinAddress& SerializedTransaction::setSigningPubKey(const std::vector<unsigned char>& s)
{
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningAccount));
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(s);
updateSourceAccount();
return mSourceAccount;
}
uint160 SerializedTransaction::getITFieldAccount(SOE_Field field) const
{
uint160 r;
const SerializedType* st = mInnerTxn.peekAtPField(field);
if (!st) return r;
const STAccount* ac = dynamic_cast<const STAccount*>(st);
if (!ac) return r;
ac->getValueH160(r);
return r;
}
int SerializedTransaction::getITFieldIndex(SOE_Field field) const

View File

@@ -8,6 +8,7 @@
#include "uint256.h"
#include "SerializedObject.h"
#include "TransactionFormats.h"
#include "NewcoinAddress.h"
class SerializedTransaction : public STObject
{
@@ -15,11 +16,14 @@ public:
typedef boost::shared_ptr<SerializedTransaction> pointer;
protected:
TransactionType type;
NewcoinAddress mSourceAccount;
TransactionType mType;
STVariableLength mSignature;
STObject mMiddleTxn, mInnerTxn;
TransactionFormat* mFormat;
void updateSourceAccount();
public:
SerializedTransaction(SerializerIterator& sit, int length); // -1=all remaining, 0=get from sit
SerializedTransaction(TransactionType type);
@@ -42,13 +46,16 @@ public:
// middle transaction functions
uint32 getVersion() const;
void setVersion(uint32);
TransactionType getTxnType() const { return type; }
TransactionType getTxnType() const { return mType; }
uint64 getTransactionFee() const;
void setTransactionFee(uint64);
std::vector<unsigned char> getSigningAccount() const;
const std::vector<unsigned char>& peekSigningAccount() const;
std::vector<unsigned char>& peekSigningAccount();
void setSigningAccount(const std::vector<unsigned char>& s);
const NewcoinAddress& getSourceAccount() const { return mSourceAccount; }
std::vector<unsigned char> getSigningPubKey() const;
const std::vector<unsigned char>& peekSigningPubKey() const;
std::vector<unsigned char>& peekSigningPubKey();
const NewcoinAddress& setSigningPubKey(const std::vector<unsigned char>& s);
std::string getTransactionType() const { return mFormat->t_name; }
// inner transaction functions
@@ -72,6 +79,7 @@ public:
uint32 getITFieldU32(SOE_Field field) const { return mInnerTxn.getValueFieldU32(field); }
uint64 getITFieldU64(SOE_Field field) const { return mInnerTxn.getValueFieldU64(field); }
uint160 getITFieldH160(SOE_Field field) const { return mInnerTxn.getValueFieldH160(field); }
uint160 getITFieldAccount(SOE_Field field) const;
uint256 getITFieldH256(SOE_Field field) const { return mInnerTxn.getValueFieldH256(field); }
std::vector<unsigned char> getITFieldVL(SOE_Field field) const { return mInnerTxn.getValueFieldVL(field); }
std::vector<TaggedListItem> getITFieldTL(SOE_Field field) const { return mInnerTxn.getValueFieldTL(field); }
@@ -85,12 +93,18 @@ public:
{ return mInnerTxn.setValueFieldVL(field, v); }
void setITFieldTL(SOE_Field field, const std::vector<TaggedListItem>& v)
{ return mInnerTxn.setValueFieldTL(field, v); }
void setITFieldAccount(SOE_Field field, const uint160& v)
{ return mInnerTxn.setValueFieldAccount(field, v); }
void setITFieldAccount(SOE_Field field, const NewcoinAddress& v)
{ return mInnerTxn.setValueFieldAccount(field, v); }
// optional field functions
bool getITFieldPresent(SOE_Field field) const;
void makeITFieldPresent(SOE_Field field);
void makeITFieldAbsent(SOE_Field field);
std::vector<NewcoinAddress> getAffectedAccounts() const;
// whole transaction functions
int getTransaction(Serializer& s, bool include_length) const;
uint256 getTransactionID() const;

View File

@@ -199,10 +199,24 @@ void STAccount::setValueH160(const uint160& v)
bool STAccount::getValueH160(uint160& v) const
{
if (!isValueH160()) return false;
memcpy(v.begin(), &(peekValue().front()), 32);
memcpy(v.begin(), &(peekValue().front()), 20);
return true;
}
NewcoinAddress STAccount::getValueNCA() const
{
NewcoinAddress a;
uint160 v;
if (getValueH160(v))
a.setAccountID(v);
return a;
}
void STAccount::setValueNCA(const NewcoinAddress& nca)
{
setValueH160(nca.getAccountID());
}
std::string STTaggedList::getText() const
{
std::string ret;

View File

@@ -362,6 +362,9 @@ public:
virtual STAccount* duplicate() const { return new STAccount(name, value); }
std::string getText() const;
NewcoinAddress getValueNCA() const;
void setValueNCA(const NewcoinAddress& nca);
void setValueH160(const uint160& v);
bool getValueH160(uint160&) const;
bool isValueH160() const;

View File

@@ -14,69 +14,66 @@
Transaction::Transaction(LocalAccount::pointer fromLocalAccount, const NewcoinAddress& toAccount, uint64 amount,
uint32 ident, uint32 ledger) : mInLedger(0), mStatus(NEW)
{
mAccountFrom=fromLocalAccount->getAddress();
mAccountTo=toAccount;
AccountState::pointer accountState = fromLocalAccount->getAccountState();
if (!accountState) throw std::runtime_error("transaction on non-existent account");
mTransaction=boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mAccountFrom = fromLocalAccount->getAddress();
mFromPubKey=fromLocalAccount->getPublicKey();
mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mFromPubKey = fromLocalAccount->getPublicKey();
assert(mFromPubKey);
mTransaction->setSigningAccount(mFromPubKey->GetPubKey());
mTransaction->setSigningPubKey(mFromPubKey->GetPubKey());
mTransaction->setSequence(accountState->getSeq());
assert(mTransaction->getSequence() != 0);
mTransaction->setSequence(fromLocalAccount->getTxnSeq());
assert(mTransaction->getSequence()!=0);
mTransaction->setTransactionFee(100); // for now
mTransaction->setITFieldVL(sfDestination, toAccount.getAccountPublic());
mTransaction->setITFieldAccount(sfDestination, toAccount);
mTransaction->setITFieldU64(sfAmount, amount);
if(ledger!=0)
if (ledger != 0)
{
mTransaction->makeITFieldPresent(sfTargetLedger);
mTransaction->setITFieldU32(sfTargetLedger, ledger);
}
if(ident!=0)
if (ident != 0)
{
mTransaction->makeITFieldPresent(sfSourceTag);
mTransaction->setITFieldU32(sfSourceTag, ident);
}
assert(mFromPubKey);
if(!sign(fromLocalAccount))
if (!sign(fromLocalAccount))
{
#ifdef DEBUG
std::cerr << "Unable to sign transaction" << std::endl;
#endif
mStatus=INCOMPLETE;
mStatus = INCOMPLETE;
}
}
Transaction::Transaction(SerializedTransaction::pointer sit, bool validate) : mStatus(INVALID), mTransaction(sit)
{
uint160 toAccountID;
uint160 fromAccountID;
std::vector<unsigned char> pubKey;
try
{
toAccountID=mTransaction->getITFieldH160(sfDestination);
pubKey=mTransaction->getSigningAccount();
mTransactionID=mTransaction->getTransactionID();
pubKey = mTransaction->peekSigningPubKey();
mTransactionID = mTransaction->getTransactionID();
mAccountFrom = mTransaction->getSourceAccount();
}
catch(...)
{
return;
}
mAccountTo.setAccountID(toAccountID);
mAccountFrom.setAccountID(fromAccountID);
mFromPubKey = boost::make_shared<CKey>();
if (!mFromPubKey->SetPubKey(pubKey)) return;
mFromPubKey = theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
mFromPubKey=boost::make_shared<CKey>();
if(!mFromPubKey->SetPubKey(pubKey)) return;
mAccountFrom.setAccountPublic(pubKey);
mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
if(!validate || checkSign())
mStatus=NEW;
if (!validate || checkSign())
mStatus = NEW;
}
Transaction::Transaction(const std::vector<unsigned char>& raw, bool validate) : mStatus(INVALID)
@@ -89,51 +86,52 @@ Transaction::Transaction(const std::vector<unsigned char>& raw, bool validate) :
{
Serializer s(raw);
SerializerIterator sit(s);
mTransaction=boost::make_shared<SerializedTransaction>(boost::ref(sit), -1);
mTransaction = boost::make_shared<SerializedTransaction>(boost::ref(sit), -1);
mFromPubKey=boost::make_shared<CKey>();
if(!mFromPubKey->SetPubKey(pubKey)) return;
mFromPubKey = boost::make_shared<CKey>();
if (!mFromPubKey->SetPubKey(pubKey)) return;
mAccountFrom.setAccountPublic(pubKey);
mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
if(!mFromPubKey->SetPubKey(pubKey)) return;
mFromPubKey = theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
if (!mFromPubKey->SetPubKey(pubKey)) return;
mAccountFrom.setAccountPublic(pubKey);
mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
mFromPubKey = theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey);
}
catch(...)
catch (...)
{
return;
}
if(!validate || checkSign())
mStatus=NEW;
if (!validate || checkSign())
mStatus = NEW;
}
Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID,
CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger,
uint32 ident, const std::vector<unsigned char>& signature, uint32 ledgerSeq, TransStatus st) :
mAccountFrom(fromID), mAccountTo(toID), mFromPubKey(pubKey), mInLedger(ledgerSeq), mStatus(st)
mAccountFrom(fromID), mFromPubKey(pubKey), mInLedger(ledgerSeq), mStatus(st)
{
mTransaction=boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mTransaction->setSignature(signature);
mTransaction->setTransactionFee(fee);
mTransaction->setSigningAccount(pubKey->GetPubKey());
mTransaction->setSigningPubKey(pubKey->GetPubKey());
mTransaction->setSequence(fromSeq);
if(fromLedger!=0)
if (fromLedger != 0)
{
mTransaction->makeITFieldPresent(sfTargetLedger);
mTransaction->setITFieldU32(sfTargetLedger, fromLedger);
}
if(ident!=0)
if (ident != 0)
{
mTransaction->makeITFieldPresent(sfSourceTag);
mTransaction->setITFieldU32(sfSourceTag, ident);
}
mTransaction->setValueFieldU64(sfAmount, amount);
mTransaction->setValueFieldAccount(sfDestination, toID.getAccountID());
updateID();
}
bool Transaction::sign(LocalAccount::pointer fromLocalAccount)
{
CKey::pointer privateKey=fromLocalAccount->getPrivateKey();
CKey::pointer privateKey = fromLocalAccount->getPrivateKey();
if(!privateKey)
{
#ifdef DEBUG
@@ -142,7 +140,7 @@ bool Transaction::sign(LocalAccount::pointer fromLocalAccount)
return false;
}
if( (mTransaction->getITFieldU64(sfAmount)==0) || !mAccountTo.IsValid() )
if( (mTransaction->getITFieldU64(sfAmount)==0) )
{
#ifdef DEBUG
std::cerr << "Bad amount or destination" << std::endl;
@@ -355,7 +353,9 @@ bool Transaction::isHexTxID(const std::string& txid)
Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
{
Json::Value ret(mTransaction->getJson(0));
if(mInLedger) ret["InLedger"]=mInLedger;
if(paid) ret["Paid"]=true;
switch(mStatus)
{
@@ -371,12 +371,7 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
default: ret["Status"]="unknown";
}
Json::Value source(Json::objectValue);
source["AccountID"]=mAccountFrom.humanAccountID();
Json::Value destination(Json::objectValue);
destination["AccountID"]=mAccountTo.humanAccountID();
#if 0
if(decorate)
{
LocalAccount::pointer lac=theApp->getWallet().getLocalAccount(mAccountFrom);
@@ -384,9 +379,7 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
lac=theApp->getWallet().getLocalAccount(mAccountTo);
if(!!lac) destination=lac->getJson();
}
if(paid) source["Paid"]=true;
if(credited) destination["Credited"]=true;
ret["Source"]=source;
ret["Destination"]=destination;
#endif
return ret;
}

View File

@@ -39,7 +39,7 @@ public:
private:
uint256 mTransactionID;
NewcoinAddress mAccountFrom, mAccountTo;
NewcoinAddress mAccountFrom;
CKey::pointer mFromPubKey;
uint32 mInLedger;
@@ -66,7 +66,6 @@ public:
const uint256& getID() const { return mTransactionID; }
const NewcoinAddress& getFromAccount() const { return mAccountFrom; }
const NewcoinAddress& getToAccount() const { return mAccountTo; }
uint64 getAmount() const { return mTransaction->getITFieldU64(sfAmount); }
uint64 getFee() const { return mTransaction->getTransactionFee(); }
uint32 getFromAccountSeq() const { return mTransaction->getSequence(); }

189
src/TransactionEngine.cpp Normal file
View File

@@ -0,0 +1,189 @@
#include "TransactionEngine.h"
#include "TransactionFormats.h"
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params)
{
uint256 txID = txn.getTransactionID();
if(!txID) return terINVALID;
// extract signing key
CKey acctKey;
if (!acctKey.SetPubKey(txn.peekSigningPubKey())) return terINVALID;
// check signature
if (!txn.checkSign(acctKey)) return terINVALID;
uint64 txnFee = txn.getTransactionFee();
if ( (params & tepNO_CHECK_FEE) != tepNONE)
{
// WRITEME: Check if fee is adequate
if (txnFee == 0) return terINSUF_FEE_P;
}
// get source account ID
uint160 srcAccount = txn.getSourceAccount().getAccountID();
if (!srcAccount) return terINVALID;
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
// find source account
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount);
if (!src) return terNO_ACCOUNT;
// deduct the fee, so it's not available during the transaction
// we only write the account back if the transaction succeeds
uint64 balance = src->getIFieldU64(sfBalance);
if (balance < txnFee)
return terINSUF_FEE_B;
src->setIFieldU64(sfBalance, balance - txnFee);
// validate sequence
uint32 t_seq = txn.getSequence();
uint32 a_seq = src->getIFieldU32(sfSequence);
if (t_seq != a_seq)
{
// WRITEME: Special case code for changing transaction key
if (a_seq < t_seq) return terPRE_SEQ;
if (mLedger->hasTransaction(txID))
return terALREADY;
return terPAST_SEQ;
}
else src->setIFieldU32(sfSequence, t_seq);
std::vector<AffectedAccount> accounts;
accounts.push_back(std::make_pair(taaMODIFY, src));
TransactionEngineResult result = terUNKNOWN;
switch(txn.getTxnType())
{
case ttINVALID:
result = terINVALID;
break;
case ttMAKE_PAYMENT:
result = doPayment(txn, accounts);
break;
case ttINVOICE:
result = doInvoice(txn, accounts);
break;
case ttEXCHANGE_OFFER:
result = doOffer(txn, accounts);
break;
default:
result = terUNKNOWN;
break;
}
if (result == terSUCCESS)
{ // Write back the account states and add the transaction to the ledger
// WRITEME: Special case code for changing transaction key
for(std::vector<AffectedAccount>::iterator it=accounts.begin(), end=accounts.end();
it != end; ++it)
{
if ( (it->first==taaMODIFY) || (it->first==taaCREATE) )
{
if(mLedger->writeBack(lepNONE, it->second) & lepERROR)
assert(false);
}
else if (it->first == taaDELETE)
{
if(!mLedger->peekAccountStateMap()->delItem(it->second->getIndex()))
assert(false);
}
}
Serializer s;
txn.add(s);
mLedger->addTransaction(txID, s);
}
return result;
}
TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
uint32 txFlags = txn.getFlags();
uint160 destAccount = txn.getITFieldAccount(sfDestination);
// Does the destination account exist?
if (!destAccount) return terINVALID;
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer dest = mLedger->getAccountRoot(qry, destAccount);
if (!dest)
{ // can this transaction create an account
if ((txFlags & 0x00010000) == 0) // no
return terNO_TARGET;
dest = boost::make_shared<SerializedLedgerEntry>(ltACCOUNT_ROOT);
dest->setIndex(Ledger::getAccountRootIndex(destAccount));
dest->setIFieldAccount(sfAccount, destAccount);
dest->setIFieldU32(sfSequence, 1);
accounts.push_back(std::make_pair(taaCREATE, dest));
}
else accounts.push_back(std::make_pair(taaMODIFY, dest));
uint64 amount = txn.getITFieldU64(sfAmount);
uint160 currency;
if(txn.getITFieldPresent(sfCurrency))
currency = txn.getITFieldH160(sfCurrency);
bool native = !!currency;
if (native)
{
uint64 balance = accounts[0].second->getIFieldU64(sfBalance);
if (balance < amount) return terUNFUNDED;
accounts[0].second->setIFieldU64(sfBalance, balance - amount);
accounts[1].second->setIFieldU64(sfBalance, accounts[1].second->getIFieldU64(sfBalance) + amount);
}
else
{
// WRITEME: Handle non-native currencies, paths
return terUNKNOWN;
}
return terSUCCESS;
}
TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doOffer(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doCancel(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}

View File

@@ -12,13 +12,17 @@
enum TransactionEngineResult
{ // <0 = Can never succeed, 0 = success, >0 = failed, but could succeed
terFAILED = -4, // Something broke horribly
terUNKNOWN = -3, // The transactions requires logic not implemented yet
terINSUF_FEE_P = -2, // fee totally insufficient
terINVALID = -1, // The transaction is ill-formed
terSUCCESS = 0, // The transaction was applied
terALREADY, // The transaction was already in the ledger
terNO_ACCOUNT, // The source account does not exist
terNO_TARGET, // The destination does not exist
terINSUF_FEE_T, // fee insufficient now (account doesn't exist, network load)
terUNFUNDED, // Source account had insufficient balance
terINSUF_FEE_B, // Account balance can't pay fee
terUNFUNDED, // Source account had insufficient balance for transactin
terNO_PATH, // No path existed or met transaction/balance requirements
terPAST_SEQ, // This sequence number has already past
terPRE_SEQ, // Missing/inapplicable prior transaction
@@ -27,22 +31,33 @@ enum TransactionEngineResult
enum TransactionEngineParams
{
tepNONE = 0,
tepNO_CHECK_SIGN = 1, // Signature already checked
tepNO_CHECK_FEE = 2, // It was voted into a ledger anyway
};
enum TransactionAccountAction
{
taaACCESS,
taaCREATE,
taaMODIFY,
taaDELETE
};
typedef std::pair<TransactionAccountAction, SerializedLedgerEntry::pointer> AffectedAccount;
class TransactionEngine
{
protected:
Ledger::pointer mLedger;
TransactionEngineResult doPayment(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doInvoice(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doOffer(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doTake(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doCancel(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doStore(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doDelete(const SerializedTransaction&, SerializedLedgerEntry& source);
TransactionEngineResult doPayment(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doInvoice(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doOffer(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doTake(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doCancel(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doStore(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doDelete(const SerializedTransaction&, std::vector<AffectedAccount>&);
public:
TransactionEngine() { ; }
@@ -54,4 +69,14 @@ public:
TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams);
};
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) | static_cast<int>(l2));
}
inline TransactionEngineParams operator&(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) & static_cast<int>(l2));
}
#endif

View File

@@ -20,7 +20,7 @@ struct TransactionFormat
const int32 TransactionMagic=0x54584E00;
const int TransactionIVersion=0, TransactionISigningAccount=1, TransactionISequence=2;
const int TransactionIVersion=0, TransactionISigningPubKey=1, TransactionISequence=2;
const int TransactionIType=3, TransactionIFee=4;
const int TransactionMinLen=32;

View File

@@ -127,7 +127,7 @@ void ValidationCollection::addToGroup(newcoin::Validation& newValid)
// see if this hash is already on the list. If so add it there.
vector< Group >& groups=mIndexGroups[newValid.ledgerindex()];
BOOST_FOREACH(Group& group,groups)
{
{ // FIXME: Cannot modify *at* *all* inside a BOOST_FOREACH
BOOST_FOREACH(newcoin::Validation& valid,group.mValidations)
{
if(valid.hash()==newValid.hash())

View File

@@ -24,12 +24,10 @@
//
LocalAccount::LocalAccount(boost::shared_ptr<LocalAccountFamily> family, int familySeq) :
mPublicKey(family->getPublicKey(familySeq)), mFamily(family), mAccountFSeq(familySeq),
mLgrBalance(0), mTxnDelta(0), mTxnSeq(0)
mPublicKey(family->getPublicKey(familySeq)), mFamily(family), mAccountFSeq(familySeq)
{
mAcctID.setAccountPublic(mPublicKey->GetPubKey());
if(theApp!=NULL) mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey);
if(theApp!=NULL) mPublicKey = theApp->getPubKeyCache().store(mAcctID, mPublicKey);
}
std::string LocalAccount::getFullName() const
@@ -37,7 +35,6 @@ std::string LocalAccount::getFullName() const
std::string ret(mFamily->getFamily().humanFamilyGenerator());
ret.append(":");
ret.append(boost::lexical_cast<std::string>(mAccountFSeq));
return ret;
}
@@ -51,21 +48,36 @@ std::string LocalAccount::getFamilyName() const
return mFamily->getFamily().humanFamilyGenerator();
}
AccountState::pointer LocalAccount::getAccountState() const
{
return theApp->getOPs().getAccountState(mAcctID);
}
uint64 LocalAccount::getEffectiveBalance() const
{
AccountState::pointer as = getAccountState();
if (!as) return 0;
return as->getBalance();
}
Json::Value LocalAccount::getJson() const
{
Json::Value ret(Json::objectValue);
ret["Family"]=getFamilyName();
ret["AccountID"]=getAddress().humanAccountID();
ret["AccountPublic"]=getAddress().humanAccountPublic();
ret["FullName"]=getFullName();
ret["Issued"]=Json::Value(isIssued());
ret["IsLocked"]=mFamily->isLocked();
ret["Family"] = getFamilyName();
ret["AccountID"] = getAddress().humanAccountID();
ret["AccountPublic"] = getAddress().humanAccountPublic();
ret["FullName"] = getFullName();
ret["Issued"] = Json::Value(isIssued());
ret["IsLocked"] = mFamily->isLocked();
uint64 eb=getEffectiveBalance();
if(eb!=0) ret["Balance"]=boost::lexical_cast<std::string>(eb);
uint32 sq=getTxnSeq();
if(sq!=0) ret["TxnSeq"]=boost::lexical_cast<std::string>(sq);
AccountState::pointer as = getAccountState();
if (as) ret["Account"] = "None";
else
{
Json::Value acct(Json::objectValue);
as->addJson(acct);
ret["Account"] = acct;
}
return ret;
}
@@ -475,7 +487,6 @@ LocalAccount::pointer Wallet::getNewLocalAccount(const NewcoinAddress& family)
mAccounts.insert(std::make_pair(acct, lac));
sl.unlock();
lac->syncLedger();
return lac;
}
@@ -495,7 +506,6 @@ LocalAccount::pointer Wallet::getLocalAccount(const NewcoinAddress& family, int
mAccounts.insert(std::make_pair(acct, lac));
sl.unlock();
lac->syncLedger();
return lac;
}
@@ -743,24 +753,11 @@ bool Wallet::unitTest()
return true;
}
void Wallet::syncToLedger(bool force, Ledger* ledger)
{
boost::recursive_mutex::scoped_lock sl(mLock);
if(!force && (mLedger>=ledger->getLedgerSeq())) return;
for(std::map<uint256, LocalTransaction::pointer>::iterator xit=mTransactions.begin();
xit!=mTransactions.end(); ++xit)
{ // check each transaction, see if it's in the ledger or allowed in the ledger
// WRITEME
}
for(std::map<NewcoinAddress, LocalAccount::pointer>::iterator ait=mAccounts.begin(); ait!=mAccounts.end(); ++ait)
{ // check each account, see if our ledger balance matches
LocalAccount::pointer& lac=ait->second;
AccountState::pointer acs=ledger->getAccountState(ait->first);
if(!acs) lac->setLedgerBalance(0);
else lac->setLedgerBalance(acs->getBalance());
}
if(mLedger<ledger->getLedgerSeq()) mLedger=ledger->getLedgerSeq();
}
#if 0
// We can't replicate the transaction logic in the wallet
// The right way is to apply the transactions to the ledger
// And then sync all affected accounts to the ledger
void Wallet::applyTransaction(Transaction::pointer txn)
{
@@ -775,7 +772,7 @@ void Wallet::applyTransaction(Transaction::pointer txn)
if(lti!=mTransactions.end()) ltx=lti->second;
std::map<NewcoinAddress, LocalAccount::pointer>::iterator lac=mAccounts.find(txn->getToAccount());
if(lac!=mAccounts.end())
if(lac != mAccounts.end())
{ // this is to a local account
if(!ltx)
{ // this is to a local account, and we don't have a local transaction for it
@@ -788,8 +785,8 @@ void Wallet::applyTransaction(Transaction::pointer txn)
}
}
lac=mAccounts.find(txn->getFromAccount());
if(lac==mAccounts.end()) return;
lac = mAccounts.find(txn->getFromAccount());
if(lac == mAccounts.end()) return;
if ( (st!=INVALID) && (lac->second->getTxnSeq()==txn->getFromAccountSeq()) )
lac->second->incTxnSeq();
@@ -830,6 +827,8 @@ void Wallet::applyTransaction(Transaction::pointer txn)
}
}
#endif
void Wallet::addLocalTransactions(Json::Value& ret)
{
boost::recursive_mutex::scoped_lock sl(mLock);
@@ -841,9 +840,9 @@ void Wallet::addLocalTransactions(Json::Value& ret)
bool Wallet::getTxJson(const uint256& txn, Json::Value& ret)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::map<uint256, LocalTransaction::pointer>::iterator it=mTransactions.find(txn);
if(it==mTransactions.end()) return false;
ret=it->second->getJson();
std::map<uint256, LocalTransaction::pointer>::iterator it = mTransactions.find(txn);
if (it == mTransactions.end()) return false;
ret = it->second->getJson();
return true;
}
@@ -851,12 +850,12 @@ bool Wallet::getTxJson(const uint256& txn, Json::Value& ret)
bool Wallet::getTxsJson(const NewcoinAddress& account, Json::Value& ret)
{
boost::recursive_mutex::scoped_lock sl(mLock);
for(std::map<uint256, LocalTransaction::pointer>::iterator it=mTransactions.begin();
it!=mTransactions.end(); ++it)
for(std::map<uint256, LocalTransaction::pointer>::iterator it = mTransactions.begin(),
end = mTransactions.end(); it != end; ++it)
{
Transaction::pointer txn=it->second->getTransaction();
if(txn && ((account==txn->getFromAccount())||(account==txn->getToAccount())) )
ret[it->first.GetHex()]=it->second->getJson();
Transaction::pointer txn = it->second->getTransaction();
if(txn && (account == txn->getFromAccount())) // FIXME: Need a way to get all accounts a txn affects
ret[it->first.GetHex()] = it->second->getJson();
}
return true;