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

Conflicts:
	src/main.cpp
This commit is contained in:
jed
2012-05-15 16:19:16 -07:00
24 changed files with 734 additions and 305 deletions

View File

@@ -118,16 +118,7 @@ void Application::run()
std::cerr << "Master seed: " << rootSeedMaster.humanFamilySeed() << std::endl;
std::cerr << "Master generator: " << rootGeneratorMaster.humanFamilyGenerator() << std::endl;
std::cerr << "Root address: " << rootAddress.humanAccountPublic() << std::endl;
// Temporary root account will be ["This is my payphrase."]:0
NewcoinAddress rootFamilySeed; // Hold the 128 password.
NewcoinAddress rootFamilyGenerator; // Hold the generator.
// NewcoinAddress rootAddress;
rootFamilySeed.setFamilySeed(CKey::PassPhraseToKey("This is my payphrase."));
rootFamilyGenerator.setFamilyGenerator(rootFamilySeed);
rootAddress.setAccountPublic(rootFamilyGenerator, 0);
std::cerr << "Root public key: " << rootAddress.humanAccountPublic() << std::endl;
std::cerr << "Root account: " << rootAddress.humanAccountID() << std::endl;
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, 100000000);

View File

@@ -15,9 +15,10 @@
#include "BitcoinUtil.h"
#include "Wallet.h"
#include "BinaryFormats.h"
#include "LedgerTiming.h"
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount),
mCloseTime(0), mLedgerSeq(0), mLedgerInterval(60), mClosed(false), mValidHash(false),
mCloseTime(0), mLedgerSeq(0), mLedgerInterval(LEDGER_INTERVAL), mClosed(false), mValidHash(false),
mAccepted(false), mImmutable(false)
{
mTransactionMap = boost::make_shared<SHAMap>();
@@ -37,7 +38,7 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash),
mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(60),
mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(LEDGER_INTERVAL),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false)
{
updateHash();

View File

@@ -220,7 +220,7 @@ void LedgerAcquire::trigger(Peer::pointer peer)
tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liAS_NODE);
for (std::vector<SHAMapNode>::iterator it =nodeIDs.begin(); it != nodeIDs.end(); ++it)
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids()) = it->getRawString();
if (peer)
{
@@ -325,7 +325,7 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
#endif
if (!mHaveBase) return false;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
std::list<std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
std::list< std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
while (nodeIDit != nodeIDs.end())
{
if (nodeIDit->isRoot())
@@ -411,10 +411,10 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi
std::list<SHAMapNode> nodeIDs;
std::list<std::vector<unsigned char> > nodeData;
if (packet.nodes().size()<=0) return false;
if (packet.nodes().size() <= 0) return false;
for (int i = 0; i<packet.nodes().size(); ++i)
{
const newcoin::TMLedgerNode& node=packet.nodes(i);
const newcoin::TMLedgerNode& node = packet.nodes(i);
if (!node.has_nodeid() || !node.has_nodedata()) return false;
nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size()));

View File

@@ -25,6 +25,7 @@ protected:
std::list< boost::weak_ptr<Peer> > mPeers;
PeerSet(const uint256& hash, int interval);
virtual ~PeerSet() { ; }
public:
const uint256& getHash() const { return mHash; }
@@ -85,6 +86,29 @@ public:
Peer::pointer);
};
class TransactionAcquire : public PeerSet, public boost::enable_shared_from_this<TransactionAcquire>
{ // A transaction set we are trying to acquire
public:
typedef boost::shared_ptr<TransactionAcquire> pointer;
protected:
SHAMap::pointer mMap;
void onTimer() { trigger(Peer::pointer()); }
void newPeer(Peer::pointer peer) { trigger(peer); }
void done();
void trigger(Peer::pointer);
boost::weak_ptr<PeerSet> pmDowncast();
public:
TransactionAcquire(const uint256& hash);
SHAMap::pointer getMap();
bool takeNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data,
Peer::pointer);
};
class LedgerAcquireMaster
{
protected:

100
src/LedgerConsensus.h Normal file
View File

@@ -0,0 +1,100 @@
#ifndef __LEDGER_CONSENSUS__
#define __LEDGER_CONSENSUS__
#include <list>
#include <boost/unordered/unordered_map.hpp>
#include "key.h"
#include "Transaction.h"
#include "LedgerAcquire.h"
class LCPosition
{ // A position taken by one of our trusted peers
protected:
uint256 mPubKeyHash;
CKey::pointer mPubKey;
uint256 mCurrentPosition;
uint32 mSequence;
public:
typedef boost::shared_ptr<LCPosition> pointer;
LCPosition(CKey::pointer pubKey, const uint256& currentPosition, uint32 seq) :
mPubKey(pubKey), mCurrentPosition(currentPosition), mSequence(seq) { ; }
const uint256& getPubKeyHash() const { return mPubKeyHash; }
const uint256& getCurrentPosition() const { return mCurrentPosition; }
uint32 getSeq() const { return mSequence; }
bool verifySignature(const uint256& hash, const std::vector<unsigned char>& signature) const;
void setPosition(const uint256& position, uint32 sequence);
};
class LCTransaction
{ // A transaction that may be disputed
protected:
uint256 mTransactionID;
int mYays, mNays;
bool mOurPosition;
boost::unordered_map<uint256, bool> mVotes;
Transaction::pointer mTransaction;
public:
typedef boost::shared_ptr<LCTransaction> pointer;
LCTransaction(const uint256 &txID, bool ourPosition) : mTransactionID(txID), mYays(0), mNays(0),
mOurPosition(ourPosition) { ; }
const uint256& getTransactionID() const { return mTransactionID; }
bool getOurPosition() const { return mOurPosition; }
bool haveTransaction() const { return !!mTransaction; }
Transaction::pointer getTransaction() { return mTransaction; }
void setVote(const uint256& peer, bool votesYes);
bool updatePosition(int timePassed);
};
class LedgerConsensus
{
protected:
Ledger::pointer mPreviousLedger, mCurrentLedger;
// Convergence tracking, trusted peers indexed by hash of public key
boost::unordered_map<uint256, LCPosition::pointer> mPeerPositions;
// Transaction Sets, indexed by hash of transaction tree
boost::unordered_map<uint256, SHAMap::pointer> mComplete;
boost::unordered_map<uint256, TransactionAcquire::pointer> mAcquiring;
// Peer sets
boost::unordered_map<uint256, std::vector< boost::weak_ptr<Peer> > > mPeerData;
public:
LedgerConsensus(Ledger::pointer previousLedger, Ledger::pointer currentLedger) :
mPreviousLedger(previousLedger), mCurrentLedger(currentLedger) { ; }
Ledger::pointer peekPreviousLedger() { return mPreviousLedger; }
Ledger::pointer peekCurrentLedger() { return mCurrentLedger; }
LCPosition::pointer getCreatePeerPosition(const uint256& pubKeyHash);
SHAMap::pointer getTransactionTree(const uint256& hash);
TransactionAcquire::pointer getAcquiring(const uint256& hash);
void acquireComplete(const uint256& hash);
LCPosition::pointer getPeerPosition(const uint256& peer);
// high-level functions
bool peerPosition(Peer::pointer peer, const Serializer& report);
bool peerHasSet(Peer::pointer peer, const std::vector<uint256>& sets);
bool peerGaveNodes(Peer::pointer peer, const uint256& setHash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
};
#endif

33
src/LedgerTiming.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef __LEDGERTIMING__
#define __LEDGERTIMING__
#define LEDGER_CLOSE_FAST
// #define LEDGER_CLOSE_SLOW
#ifdef LEDGER_CLOSE_FAST
// Time between one ledger close and the next ledger close
# define LEDGER_INTERVAL 60
// Time we expect avalanche to finish
# define LEDGER_CONVERGE 20
// Time we forcibly abort avalanche
# define LEDGER_FORCE_CONVERGE 30
#endif
#ifdef LEDGER_CLOSE_SLOW
# define LEDGER_INTERVAL 1800
# define LEDGER_CONVERGE 180
# define LEDGER_FORCE_CONVERGE 240
// Time a transaction must be unconflicted before we consider it protected
# define LEDGER_PROTECT 90
#endif
#endif

View File

@@ -303,6 +303,25 @@ void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq)
setAccountPublic(pubkey.GetPubKey());
}
bool NewcoinAddress::accountPublicVerify(const uint256& uHash, const std::vector<unsigned char>& vucSig) const
{
CKey ckPublic;
bool bVerified;
if (!ckPublic.SetPubKey(getAccountPublic()))
{
// Bad private key.
std::cerr << "accountPublicVerify: Bad private key." << std::endl;
bVerified = false;
}
else
{
bVerified = ckPublic.Verify(uHash, vucSig);
}
return bVerified;
}
//
// AccountPrivate
//
@@ -631,16 +650,17 @@ void NewcoinAddress::setFamilySeedGeneric(const std::string& strText)
{
if (setFamilySeed(strText))
{
std::cerr << "Recognized seed." << std::endl;
// std::cerr << "Recognized seed." << std::endl;
nothing();
}
else if (1 == setFamilySeed1751(strText))
{
std::cerr << "Recognized 1751 seed." << std::endl;
// std::cerr << "Recognized 1751 seed." << std::endl;
nothing();
}
else
{
std::cerr << "Creating seed from pass phrase." << std::endl;
// std::cerr << "Creating seed from pass phrase." << std::endl;
setFamilySeed(CKey::PassPhraseToKey(strText));
}
}

View File

@@ -76,6 +76,8 @@ public:
void setAccountPublic(const std::vector<unsigned char>& vPublic);
void setAccountPublic(const NewcoinAddress& generator, int seq);
bool accountPublicVerify(const uint256& uHash, const std::vector<unsigned char>& vucSig) const;
//
// Accounts Private
//

View File

@@ -749,12 +749,12 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
{
std::vector<SHAMapNode>::iterator nodeIDIterator;
std::list<std::vector<unsigned char> >::iterator rawNodeIterator;
for(nodeIDIterator=nodeIDs.begin(), rawNodeIterator=rawNodes.begin();
nodeIDIterator!=nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator)
for(nodeIDIterator = nodeIDs.begin(), rawNodeIterator = rawNodes.begin();
nodeIDIterator != nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator)
{
Serializer nID(33);
nodeIDIterator->addIDRaw(nID);
newcoin::TMLedgerNode* node=data->add_nodes();
newcoin::TMLedgerNode* node = data->add_nodes();
node->set_nodeid(nID.getDataPtr(), nID.getLength());
node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size());
}
@@ -766,14 +766,14 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
punishPeer(PP_INVALID_REQUEST);
return;
}
PackedMessage::pointer oPacket=boost::make_shared<PackedMessage>
PackedMessage::pointer oPacket = boost::make_shared<PackedMessage>
(PackedMessage::MessagePointer(data), newcoin::mtLEDGER);
sendPacket(oPacket);
}
void Peer::recvLedger(newcoin::TMLedgerData& packet)
{
if(!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()))
if (!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()))
punishPeer(PP_UNWANTED_DATA);
}

View File

@@ -172,6 +172,7 @@ NewcoinAddress RPCServer::parseFamily(const std::string& fParam)
return family;
}
#if 0
Json::Value RPCServer::doCreateFamily(Json::Value& params)
{
// createfamily FXXXX
@@ -216,37 +217,83 @@ Json::Value RPCServer::doCreateFamily(Json::Value& params)
return ret;
}
#endif
// account_info <account>|<nickname>|<account_public_key>
// account_info <seed>|<pass_phrase>|<key> [<index>]
Json::Value RPCServer::doAccountInfo(Json::Value &params)
{ // accountinfo <family>:<number>
// accountinfo <account>
std::string acct;
if (!extractString(acct, params, 0))
return JSONRPCError(500, "Invalid account identifier");
LocalAccount::pointer account = theApp->getWallet().parseAccount(acct);
if (account) return account->getJson();
NewcoinAddress acctid;
if (!acctid.setAccountID(acct))
return JSONRPCError(500, "Unable to parse account");
LocalAccount::pointer lac(theApp->getWallet().getLocalAccount(acctid));
if (!!lac) return lac->getJson();
AccountState::pointer as=theApp->getMasterLedger().getCurrentLedger()->getAccountState(acctid);
Json::Value ret(Json::objectValue);
if (as)
as->addJson(ret);
{
if (params.size() < 1 || params.size() > 2)
{
return "invalid params";
}
else
{
NewcoinAddress ad;
ad.setAccountID(acct);
ret[ad.humanAccountID()]="NotFound";
std::string strIdent = params[0u].asString();
bool bIndex = 2 == params.size();
int iIndex = bIndex ? boost::lexical_cast<int>(params[1u].asString()) : 0;
NewcoinAddress naAccount;
NewcoinAddress naSeed;
if (!bIndex && (naAccount.setAccountPublic(strIdent) || naAccount.setAccountID(strIdent)))
{
// Got the account.
nothing();
}
else
{
// Must be a seed.
naSeed.setFamilySeedGeneric(strIdent);
NewcoinAddress naGenerator;
NewcoinAddress naRegularReservedPublic;
naGenerator.setFamilyGenerator(naSeed);
naRegularReservedPublic.setAccountPublic(naGenerator, -1);
uint160 uGeneratorID = naRegularReservedPublic.getAccountID();
// if (probe (uGeneratorID))
if (false)
{
// Found master public key.
}
else
{
// Didn't find a generator map, assume it is a master generator.
nothing();
}
bIndex = true;
naAccount.setAccountPublic(naGenerator, iIndex);
}
// Get info on account.
Json::Value ret(Json::objectValue);
AccountState::pointer as=theApp->getMasterLedger().getCurrentLedger()->getAccountState(naAccount);
if (as)
{
as->addJson(ret);
}
else
{
ret["account"] = naAccount.humanAccountID();
ret["status"] = "NotFound";
ret["bIndex"] = bIndex;
if (bIndex)
ret["index"] = iIndex;
}
return ret;
}
return ret;
}
#if 0
Json::Value RPCServer::doNewAccount(Json::Value &params)
{ // newaccount <family> [<name>]
std::string fParam;
@@ -262,6 +309,7 @@ Json::Value RPCServer::doNewAccount(Json::Value &params)
return account->getJson();
}
#endif
Json::Value RPCServer::doLock(Json::Value &params)
{ // lock <family>
@@ -597,10 +645,26 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) {
// To provide an example to client writers, we do everything we expect a client to do here.
Json::Value RPCServer::doWalletClaim(Json::Value& params)
{
NewcoinAddress naTemp;
if (params.size() < 2 || params.size() > 4)
{
return "invalid params";
}
else if (naTemp.setAccountID(params[0u].asString())
|| naTemp.setAccountPublic(params[0u].asString())
|| naTemp.setAccountPrivate(params[0u].asString()))
{
// Should also not allow account id's as seeds.
return "master seed expected";
}
else if (naTemp.setAccountID(params[1u].asString())
|| naTemp.setAccountPublic(params[1u].asString())
|| naTemp.setAccountPrivate(params[1u].asString()))
{
// Should also not allow account id's as seeds.
return "regular seed expected";
}
else
{
// Trying to build:
@@ -608,8 +672,9 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
//
// Which has no confidential information.
// XXX Need better parsing.
uint32 uSourceTag = (params.size() == 2) ? 0 : boost::lexical_cast<uint32>(params[2u].asString());
// XXX Annotation is ignored.
uint32 uSourceTag = (params.size() == 2) ? 0 : params[2u].asUInt();
std::string strAnnotation = (params.size() == 3) ? "" : params[3u].asString();
NewcoinAddress naMasterSeed;
@@ -622,7 +687,6 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
NewcoinAddress naAccountPublic;
NewcoinAddress naAccountPrivate;
NewcoinAddress naUnset;
naMasterSeed.setFamilySeedGeneric(params[0u].asString());
naRegularSeed.setFamilySeedGeneric(params[1u].asString());
@@ -640,14 +704,14 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
uint160 uGeneratorID = naRegularReservedPublic.getAccountID();
std::vector<unsigned char> vucGeneratorCipher = naRegularReservedPrivate.accountPrivateEncrypt(naRegularReservedPublic, naMasterGenerator.getFamilyGenerator());
Transaction::pointer trns = boost::make_shared<Transaction>(
Transaction::pointer trns = Transaction::sharedClaim(
naAccountPublic, naAccountPrivate,
naAccountPublic, naUnset,
0, // Free
0, // Seq
uSourceTag, // Source tag
0); // Ledger not specified.
naAccountPublic,
uSourceTag,
naRegularReservedPublic, // GeneratorID
vucGeneratorCipher);
(void) theApp->getOPs().processTransaction(trns);
Json::Value obj(Json::objectValue);
@@ -662,6 +726,9 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
obj["generator"] = strHex(vucGeneratorCipher);
obj["annotation"] = strAnnotation;
obj["transaction"] = trns->getSTransaction()->getJson(0);
obj["status"] = trns->getStatus();
return obj;
}
}
@@ -809,38 +876,47 @@ Json::Value RPCServer::doUnlScore(Json::Value& params) {
else return "invalid params";
}
Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params)
{
std::cerr << "RPC:" << command << std::endl;
if (command== "stop")
Json::Value RPCServer::doStop(Json::Value& params) {
if (!params.size())
{
theApp->stop();
return SYSTEM_NAME " server stopping";
}
else return "invalid params";
}
if (command=="unl_add") return doUnlAdd(params);
if (command=="unl_default") return doUnlDefault(params);
if (command=="unl_delete") return doUnlDelete(params);
if (command=="unl_list") return doUnlList(params);
if (command=="unl_reset") return doUnlReset(params);
if (command=="unl_score") return doUnlScore(params);
Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params)
{
std::cerr << "RPC:" << command << std::endl;
if (command=="validation_create") return doValidatorCreate(params);
if (command == "account_info") return doAccountInfo(params);
if (command == "connect") return doConnect(params);
if (command == "peers") return doPeers(params);
if (command == "stop") return doStop(params);
if (command=="wallet_claim") return doWalletClaim(params);
if (command=="wallet_propose") return doWalletPropose(params);
if (command == "unl_add") return doUnlAdd(params);
if (command == "unl_default") return doUnlDefault(params);
if (command == "unl_delete") return doUnlDelete(params);
if (command == "unl_list") return doUnlList(params);
if (command == "unl_reset") return doUnlReset(params);
if (command == "unl_score") return doUnlScore(params);
if (command=="createfamily") return doCreateFamily(params);
if (command == "validation_create") return doValidatorCreate(params);
if (command == "wallet_claim") return doWalletClaim(params);
if (command == "wallet_propose") return doWalletPropose(params);
//
// Obsolete or need rewrite:
//
// if (command=="createfamily") return doCreateFamily(params);
if (command=="familyinfo") return doFamilyInfo(params);
if (command=="accountinfo") return doAccountInfo(params);
if (command=="newaccount") return doNewAccount(params);
// if (command=="newaccount") return doNewAccount(params);
if (command=="lock") return doLock(params);
if (command=="unlock") return doUnlock(params);
if (command=="sendto") return doSendTo(params);
if (command=="connect") return doConnect(params);
if (command=="peers") return doPeers(params);
if (command=="tx") return doTx(params);
if (command=="ledger") return doLedger(params);

View File

@@ -45,6 +45,7 @@ class RPCServer : public boost::enable_shared_from_this<RPCServer>
Json::Value doTx(Json::Value& params);
Json::Value doLedger(Json::Value& params);
Json::Value doAccount(Json::Value& params);
Json::Value doStop(Json::Value& params);
Json::Value doUnlAdd(Json::Value& params);
Json::Value doUnlDefault(Json::Value& params);

View File

@@ -38,6 +38,7 @@ public:
SHAMapNode() : mDepth(0) { ; }
SHAMapNode(int depth, const uint256& hash);
virtual ~SHAMapNode() { ; }
int getDepth() const { return mDepth; }
const uint256& getNodeID() const { return mNodeID; }
bool isValid() const { return (mDepth >= 0) && (mDepth < 64); }

View File

@@ -15,9 +15,6 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
if(root->isFullBelow())
{
#ifdef GMN_DEBUG
std::cerr << "getMissingNodes: root is full below" << std::endl;
#endif
clearSynching();
return;
}
@@ -31,34 +28,23 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
std::stack<SHAMapTreeNode::pointer> stack;
stack.push(root);
while ((max > 0) && (!stack.empty()))
while (!stack.empty())
{
SHAMapTreeNode::pointer node = stack.top();
stack.pop();
#ifdef GMN_DEBUG
std::cerr << "gMN: popped " << node->getString() << std::endl;
#endif
for (int i = 0; i < 16; ++i)
if( !node->isEmptyBranch(i))
if (!node->isEmptyBranch(i))
{
#ifdef GMN_DEBUG
std::cerr << "gMN: " << node->getString() << " has non-empty branch " << i << std::endl;
#endif
SHAMapTreeNode::pointer desc = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(desc)
if (!desc)
{
if (desc->isInner() && !desc->isFullBelow())
stack.push(desc);
}
else if (max-- > 0)
{
#ifdef GMN_DEBUG
std::cerr << "gMN: need " << node->getChildNodeID(i).getString() << std::endl;
#endif
nodeIDs.push_back(node->getChildNodeID(i));
if (--max <= 0)
return;
}
else if (desc->isInner() && !desc->isFullBelow())
stack.push(desc);
}
}
}

View File

@@ -17,6 +17,8 @@ protected:
STObject mObject;
LedgerEntryFormat* mFormat;
SerializedLedgerEntry* duplicate() const { return new SerializedLedgerEntry(*this); }
public:
SerializedLedgerEntry(const Serializer& s, const uint256& index);
SerializedLedgerEntry(SerializerIterator& sit, const uint256& index);
@@ -24,7 +26,6 @@ public:
int getLength() const { return mVersion.getLength() + mObject.getLength(); }
SerializedTypeID getSType() const { return STI_LEDGERENTRY; }
SerializedLedgerEntry* duplicate() const { return new SerializedLedgerEntry(*this); }
std::string getFullText() const;
std::string getText() const;
Json::Value getJson(int options) const;

View File

@@ -5,77 +5,88 @@
#include "../json/writer.h"
SerializedType* STObject::makeDefaultObject(SerializedTypeID id, const char *name)
std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, const char *name)
{
switch(id)
{
case STI_NOTPRESENT:
return std::auto_ptr<SerializedType>(new SerializedType(name));
case STI_UINT16:
return new STUInt16(name);
return std::auto_ptr<SerializedType>(new STUInt16(name));
case STI_UINT32:
return new STUInt32(name);
return std::auto_ptr<SerializedType>(new STUInt32(name));
case STI_UINT64:
return new STUInt64(name);
return std::auto_ptr<SerializedType>(new STUInt64(name));
case STI_AMOUNT:
return new STAmount(name);
return std::auto_ptr<SerializedType>(new STAmount(name));
case STI_HASH128:
return std::auto_ptr<SerializedType>(new STHash128(name));
case STI_HASH160:
return new STHash160(name);
return std::auto_ptr<SerializedType>(new STHash160(name));
case STI_HASH256:
return new STHash256(name);
return std::auto_ptr<SerializedType>(new STHash256(name));
case STI_VL:
return new STVariableLength(name);
return std::auto_ptr<SerializedType>(new STVariableLength(name));
case STI_TL:
return new STTaggedList(name);
return std::auto_ptr<SerializedType>(new STTaggedList(name));
case STI_ACCOUNT:
return new STAccount(name);
return std::auto_ptr<SerializedType>(new STAccount(name));
default:
assert(false);
return NULL;
throw std::runtime_error("Unknown object type");
}
}
SerializedType* STObject::makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator& sit)
std::auto_ptr<SerializedType> STObject::makeDeserializedObject(SerializedTypeID id, const char *name,
SerializerIterator& sit)
{
switch(id)
{
case STI_NOTPRESENT:
return SerializedType::deserialize(name);
case STI_UINT16:
return STUInt16::construct(sit, name);
return STUInt16::deserialize(sit, name);
case STI_UINT32:
return STUInt32::construct(sit, name);
return STUInt32::deserialize(sit, name);
case STI_UINT64:
return STUInt64::construct(sit, name);
return STUInt64::deserialize(sit, name);
case STI_AMOUNT:
return STAmount::construct(sit, name);
return STAmount::deserialize(sit, name);
case STI_HASH128:
return STHash128::deserialize(sit, name);
case STI_HASH160:
return STHash160::construct(sit, name);
return STHash160::deserialize(sit, name);
case STI_HASH256:
return STHash256::construct(sit, name);
return STHash256::deserialize(sit, name);
case STI_VL:
return STVariableLength::construct(sit, name);
return STVariableLength::deserialize(sit, name);
case STI_TL:
return STTaggedList::construct(sit, name);
return STTaggedList::deserialize(sit, name);
case STI_ACCOUNT:
return STAccount::construct(sit, name);
return STAccount::deserialize(sit, name);
default:
assert(false);
return NULL;
throw std::runtime_error("Unknown object type");
}
}
@@ -86,13 +97,9 @@ STObject::STObject(SOElement* elem, const char *name) : SerializedType(name), mF
if (elem->e_type == SOE_FLAGS) mFlagIdx = mType.size();
mType.push_back(elem);
if (elem->e_type == SOE_IFFLAG)
giveObject(new SerializedType(elem->e_name));
giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_name));
else
{
SerializedType* t = makeDefaultObject(elem->e_id, elem->e_name);
if (!t) throw std::runtime_error("invalid transaction element");
giveObject(t);
}
giveObject(makeDefaultObject(elem->e_id, elem->e_name));
++elem;
}
}
@@ -107,12 +114,20 @@ STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) :
if (elem->e_type == SOE_IFFLAG)
{
assert(flags >= 0);
if ((flags&elem->e_flags) == 0) done = true;
if ((flags&elem->e_flags) == 0)
{
done = true;
giveObject(makeDefaultObject(elem->e_id, elem->e_name));
}
}
else if (elem->e_type == SOE_IFNFLAG)
{
assert(flags >= 0);
if ((flags&elem->e_flags) != 0) done = true;
if ((flags&elem->e_flags) != 0)
{
done = true;
giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_name));
}
}
else if (elem->e_type == SOE_FLAGS)
{
@@ -122,11 +137,7 @@ STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) :
done = true;
}
if (!done)
{
SerializedType* t = makeDeserializedObject(elem->e_id, elem->e_name, sit);
if (!t) throw std::runtime_error("invalid transaction element");
giveObject(t);
}
giveObject(makeDeserializedObject(elem->e_id, elem->e_name, sit));
elem++;
}
}
@@ -141,12 +152,14 @@ std::string STObject::getFullText() const
ret += " = {";
}
else ret = "{";
for (boost::ptr_vector<SerializedType>::const_iterator it = mData.begin(), end = mData.end(); it != end; ++it)
{
if (!first) ret += ", ";
else first = false;
ret += it->getFullText();
}
ret += "}";
return ret;
}
@@ -269,23 +282,22 @@ uint32 STObject::getFlags(void) const
SerializedType* STObject::makeFieldPresent(SOE_Field field)
{
SerializedType* ret = NULL;
int index = getFieldIndex(field);
if (index == -1) throw std::runtime_error("Field not found");
if ((mType[index]->e_type != SOE_IFFLAG) && (mType[index]->e_type != SOE_IFNFLAG))
throw std::runtime_error("field is not optional");
ret = getPIndex(index);
if (ret->getSType() != STI_NOTPRESENT) return ret;
ret = makeDefaultObject(mType[index]->e_id, mType[index]->e_name);
mData.replace(index, ret);
SerializedType* f = getPIndex(index);
if (f->getSType() != STI_NOTPRESENT) return f;
mData.replace(index, makeDefaultObject(mType[index]->e_id, mType[index]->e_name));
f = getPIndex(index);
if (mType[index]->e_type == SOE_IFFLAG)
setFlag(mType[index]->e_flags);
else if (mType[index]->e_type == SOE_IFNFLAG)
clearFlag(mType[index]->e_flags);
return ret;
return f;
}
void STObject::makeFieldAbsent(SOE_Field field)

View File

@@ -54,8 +54,10 @@ protected:
boost::ptr_vector<SerializedType> mData;
std::vector<SOElement*> mType;
static SerializedType* makeDefaultObject(SerializedTypeID id, const char *name);
static SerializedType* makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator&);
static std::auto_ptr<SerializedType> makeDefaultObject(SerializedTypeID id, const char *name);
static std::auto_ptr<SerializedType> makeDeserializedObject(SerializedTypeID id, const char *name,
SerializerIterator&);
STObject* duplicate() const { return new STObject(*this); }
public:
STObject(const char *n = NULL) : SerializedType(n), mFlagIdx(-1) { ; }
@@ -65,7 +67,6 @@ public:
int getLength() const;
SerializedTypeID getSType() const { return STI_OBJECT; }
STObject* duplicate() const { return new STObject(*this); }
virtual bool isEquivalent(const SerializedType& t) const;
void add(Serializer& s) const;
@@ -74,8 +75,9 @@ public:
std::string getText() const;
virtual Json::Value getJson(int options) const;
int addObject(const SerializedType& t) { mData.push_back(t.duplicate()); return mData.size()-1; }
int giveObject(SerializedType* t) { mData.push_back(t); return mData.size()-1; }
int addObject(const SerializedType& t) { mData.push_back(t.clone()); return mData.size() - 1; }
int giveObject(std::auto_ptr<SerializedType> t) { mData.push_back(t); return mData.size() - 1; }
int giveObject(SerializedType* t) { mData.push_back(t); return mData.size() - 1; }
const boost::ptr_vector<SerializedType>& peekData() const { return mData; }
boost::ptr_vector<SerializedType>& peekData() { return mData; }

View File

@@ -136,9 +136,9 @@ bool SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate)
return naAccountPrivate.accountPrivateSign(getSigningHash(), mSignature.peekValue());
}
bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPrivate) const
bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) const
{
return naAccountPrivate.accountPrivateVerify(getSigningHash(), mSignature.getValue());
return naAccountPublic.accountPublicVerify(getSigningHash(), mSignature.getValue());
}
void SerializedTransaction::setSignature(const std::vector<unsigned char>& sig)

View File

@@ -23,6 +23,8 @@ protected:
STObject mMiddleTxn, mInnerTxn;
TransactionFormat* mFormat;
SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); }
public:
SerializedTransaction(SerializerIterator& sit, int length); // -1=all remaining, 0=get from sit
SerializedTransaction(TransactionType type);
@@ -30,7 +32,6 @@ public:
// STObject functions
int getLength() const;
SerializedTypeID getSType() const { return STI_TRANSACTION; }
SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); }
std::string getFullText() const;
std::string getText() const;
void add(Serializer& s) const { getTransaction(s, true); }
@@ -112,7 +113,7 @@ public:
virtual Json::Value getJson(int options) const;
bool sign(const NewcoinAddress& naAccountPrivate);
bool checkSign(const NewcoinAddress& naAccountPrivate) const;
bool checkSign(const NewcoinAddress& naAccountPublic) const;
};
#endif

View File

@@ -26,6 +26,8 @@ class SerializedType
protected:
const char *name;
virtual SerializedType* duplicate() const { return new SerializedType(name); }
public:
SerializedType() : name(NULL) { ; }
@@ -33,12 +35,15 @@ public:
SerializedType(const SerializedType& n) : name(n.name) { ; }
virtual ~SerializedType() { ; }
static std::auto_ptr<SerializedType> deserialize(const char *name)
{ return std::auto_ptr<SerializedType>(new SerializedType(name)); }
void setName(const char *n) { name=n; }
const char *getName() const { return name; }
virtual int getLength() const { return 0; }
virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; }
virtual SerializedType* duplicate() const { return new SerializedType(name); }
std::auto_ptr<SerializedType> clone() const { return std::auto_ptr<SerializedType>(duplicate()); }
virtual std::string getFullText() const;
virtual std::string getText() const // just the value
@@ -49,12 +54,12 @@ public:
virtual bool isEquivalent(const SerializedType& t) const { return true; }
bool operator==(const SerializedType& t) const
{ return (getSType()==t.getSType()) && isEquivalent(t); }
{ return (getSType() == t.getSType()) && isEquivalent(t); }
bool operator!=(const SerializedType& t) const
{ return (getSType()!=t.getSType()) || !isEquivalent(t); }
{ return (getSType() != t.getSType()) || !isEquivalent(t); }
};
inline SerializedType* new_clone(const SerializedType& s) { return s.duplicate(); }
inline SerializedType* new_clone(const SerializedType& s) { return s.clone().release(); }
inline void delete_clone(const SerializedType* s) { boost::checked_delete(s); }
class STUInt8 : public SerializedType
@@ -62,15 +67,18 @@ class STUInt8 : public SerializedType
protected:
unsigned char value;
STUInt8* duplicate() const { return new STUInt8(name, value); }
static STUInt8* construct(SerializerIterator&, const char *name = NULL);
public:
STUInt8(unsigned char v=0) : value(v) { ; }
STUInt8(const char *n, unsigned char v=0) : SerializedType(n), value(v) { ; }
static STUInt8* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 1; }
SerializedTypeID getSType() const { return STI_UINT8; }
STUInt8* duplicate() const { return new STUInt8(name, value); }
std::string getText() const;
void add(Serializer& s) const { s.add8(value); }
@@ -87,15 +95,18 @@ class STUInt16 : public SerializedType
protected:
uint16 value;
STUInt16* duplicate() const { return new STUInt16(name, value); }
static STUInt16* construct(SerializerIterator&, const char *name = NULL);
public:
STUInt16(uint16 v=0) : value(v) { ; }
STUInt16(const char *n, uint16 v=0) : SerializedType(n), value(v) { ; }
static STUInt16* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 2; }
SerializedTypeID getSType() const { return STI_UINT16; }
STUInt16* duplicate() const { return new STUInt16(name, value); }
std::string getText() const;
void add(Serializer& s) const { s.add16(value); }
@@ -112,15 +123,18 @@ class STUInt32 : public SerializedType
protected:
uint32 value;
STUInt32* duplicate() const { return new STUInt32(name, value); }
static STUInt32* construct(SerializerIterator&, const char *name = NULL);
public:
STUInt32(uint32 v=0) : value(v) { ; }
STUInt32(const char *n, uint32 v=0) : SerializedType(n), value(v) { ; }
static STUInt32* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 4; }
SerializedTypeID getSType() const { return STI_UINT32; }
STUInt32* duplicate() const { return new STUInt32(name, value); }
std::string getText() const;
void add(Serializer& s) const { s.add32(value); }
@@ -137,15 +151,18 @@ class STUInt64 : public SerializedType
protected:
uint64 value;
STUInt64* duplicate() const { return new STUInt64(name, value); }
static STUInt64* construct(SerializerIterator&, const char *name = NULL);
public:
STUInt64(uint64 v=0) : value(v) { ; }
STUInt64(const char *n, uint64 v=0) : SerializedType(n), value(v) { ; }
static STUInt64* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 8; }
SerializedTypeID getSType() const { return STI_UINT64; }
STUInt64* duplicate() const { return new STUInt64(name, value); }
std::string getText() const;
void add(Serializer& s) const { s.add64(value); }
@@ -175,6 +192,8 @@ protected:
uint64 value;
void canonicalize();
STAmount* duplicate() const { return new STAmount(name, offset, value); }
static STAmount* construct(SerializerIterator&, const char *name = NULL);
static const int cMinOffset=-96, cMaxOffset=80;
static const uint64 cMinValue=1000000000000000ull, cMaxValue=9999999999999999ull;
@@ -184,11 +203,11 @@ public:
{ canonicalize(); } // (1,0)=$1 (1,-2)=$.01 (100,0)=(10000,-2)=$.01
STAmount(const char *n, uint64 v = 0, int off = 0) : SerializedType(n), offset(off), value(v)
{ canonicalize(); }
static STAmount* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 8; }
SerializedTypeID getSType() const { return STI_AMOUNT; }
STAmount* duplicate() const { return new STAmount(name, offset, value); }
std::string getText() const;
std::string getRaw() const;
void add(Serializer& s) const;
@@ -245,17 +264,20 @@ class STHash128 : public SerializedType
protected:
uint128 value;
STHash128* duplicate() const { return new STHash128(name, value); }
static STHash128* construct(SerializerIterator&, const char *name = NULL);
public:
STHash128(const uint128& v) : value(v) { ; }
STHash128(const char *n, const uint128& v) : SerializedType(n), value(v) { ; }
STHash128(const char *n) : SerializedType(n) { ; }
STHash128() { ; }
static STHash128* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH128; }
STHash128* duplicate() const { return new STHash128(name, value); }
virtual std::string getText() const;
void add(Serializer& s) const { s.add128(value); }
@@ -272,17 +294,20 @@ class STHash160 : public SerializedType
protected:
uint160 value;
STHash160* duplicate() const { return new STHash160(name, value); }
static STHash160* construct(SerializerIterator&, const char *name = NULL);
public:
STHash160(const uint160& v) : value(v) { ; }
STHash160(const char *n, const uint160& v) : SerializedType(n), value(v) { ; }
STHash160(const char *n) : SerializedType(n) { ; }
STHash160() { ; }
static STHash160* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH160; }
STHash160* duplicate() const { return new STHash160(name, value); }
virtual std::string getText() const;
void add(Serializer& s) const { s.add160(value); }
@@ -299,17 +324,20 @@ class STHash256 : public SerializedType
protected:
uint256 value;
STHash256* duplicate() const { return new STHash256(name, value); }
static STHash256* construct(SerializerIterator&, const char *name = NULL);
public:
STHash256(const uint256& v) : value(v) { ; }
STHash256(const char *n, const uint256& v) : SerializedType(n), value(v) { ; }
STHash256(const char *n) : SerializedType(n) { ; }
STHash256() { ; }
static STHash256* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const { return 32; }
SerializedTypeID getSType() const { return STI_HASH256; }
STHash256* duplicate() const { return new STHash256(name, value); }
std::string getText() const;
void add(Serializer& s) const { s.add256(value); }
@@ -326,6 +354,9 @@ class STVariableLength : public SerializedType
protected:
std::vector<unsigned char> value;
virtual STVariableLength* duplicate() const { return new STVariableLength(name, value); }
static STVariableLength* construct(SerializerIterator&, const char *name = NULL);
public:
STVariableLength(const std::vector<unsigned char>& v) : value(v) { ; }
@@ -333,11 +364,11 @@ public:
STVariableLength(const char *n) : SerializedType(n) { ; }
STVariableLength(SerializerIterator&, const char *name = NULL);
STVariableLength() { ; }
static STVariableLength* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
virtual SerializedTypeID getSType() const { return STI_VL; }
virtual STVariableLength* duplicate() const { return new STVariableLength(name, value); }
virtual std::string getText() const;
void add(Serializer& s) const { s.addVL(value); }
@@ -353,16 +384,20 @@ public:
class STAccount : public STVariableLength
{
protected:
virtual STAccount* duplicate() const { return new STAccount(name, value); }
static STAccount* construct(SerializerIterator&, const char *name = NULL);
public:
STAccount(const std::vector<unsigned char>& v) : STVariableLength(v) { ; }
STAccount(const char *n, const std::vector<unsigned char>& v) : STVariableLength(n, v) { ; }
STAccount(const char *n) : STVariableLength(n) { ; }
STAccount() { ; }
static STAccount* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
SerializedTypeID getSType() const { return STI_ACCOUNT; }
virtual STAccount* duplicate() const { return new STAccount(name, value); }
std::string getText() const;
NewcoinAddress getValueNCA() const;
@@ -378,17 +413,20 @@ class STTaggedList : public SerializedType
protected:
std::vector<TaggedListItem> value;
STTaggedList* duplicate() const { return new STTaggedList(name, value); }
static STTaggedList* construct(SerializerIterator&, const char *name = NULL);
public:
STTaggedList() { ; }
STTaggedList(const char *n) : SerializedType(n) { ; }
STTaggedList(const std::vector<TaggedListItem>& v) : value(v) { ; }
STTaggedList(const char *n, const std::vector<TaggedListItem>& v) : SerializedType(n), value(v) { ; }
static STTaggedList* construct(SerializerIterator&, const char *name = NULL);
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char *name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
int getLength() const;
SerializedTypeID getSType() const { return STI_TL; }
STTaggedList* duplicate() const { return new STTaggedList(name, value); }
std::string getText() const;
void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); }

View File

@@ -1,5 +1,6 @@
#include <cassert>
#include <boost/format.hpp>
#include "boost/lexical_cast.hpp"
#include "boost/make_shared.hpp"
#include "boost/ref.hpp"
@@ -11,47 +12,6 @@
#include "Serializer.h"
#include "SerializedTransaction.h"
Transaction::Transaction(const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naFromAccount, const NewcoinAddress& toAccount,
uint64 amount,
uint32 iSeq, uint32 ident, uint32 ledger) : mInLedger(0), mStatus(NEW)
{
mAccountFrom = naFromAccount;
mFromPubKey = naPublicKey;
assert(mFromPubKey.isValid());
mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mTransaction->setSigningPubKey(mFromPubKey);
mTransaction->setSourceAccount(mAccountFrom);
mTransaction->setSequence(iSeq);
mTransaction->setTransactionFee(100); // for now
mTransaction->setITFieldAccount(sfDestination, toAccount);
mTransaction->setITFieldU64(sfAmount, amount);
if (ledger != 0)
{
mTransaction->makeITFieldPresent(sfTargetLedger);
mTransaction->setITFieldU32(sfTargetLedger, ledger);
}
if (ident != 0)
{
mTransaction->makeITFieldPresent(sfSourceTag);
mTransaction->setITFieldU32(sfSourceTag, ident);
}
if (!sign(naPrivateKey))
{
#ifdef DEBUG
std::cerr << "Unable to sign transaction" << std::endl;
#endif
mStatus = INCOMPLETE;
}
}
Transaction::Transaction(const SerializedTransaction::pointer sit, bool bValidate)
: mInLedger(0), mStatus(INVALID), mTransaction(sit)
{
@@ -87,69 +47,146 @@ Transaction::pointer Transaction::sharedTransaction(const std::vector<unsigned c
}
}
#if 0
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), mFromPubKey(pubKey), mInLedger(ledgerSeq), mStatus(st)
//
// Generic transaction construction
//
Transaction::Transaction(
TransactionType ttKind,
const NewcoinAddress& naPublicKey,
const NewcoinAddress& naSourceAccount,
uint32 uSeq,
uint64 uFee,
uint32 uSourceTag) :
mInLedger(0), mStatus(NEW)
{
mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mTransaction->setSignature(signature);
mTransaction->setTransactionFee(fee);
mTransaction->setSigningPubKey(pubKey); // BROKEN
mTransaction->setSourceAccount(mAccountFrom); // BROKEN
mTransaction->setSequence(fromSeq);
if (fromLedger != 0)
{
mTransaction->makeITFieldPresent(sfTargetLedger);
mTransaction->setITFieldU32(sfTargetLedger, fromLedger);
}
if (ident != 0)
mAccountFrom = naSourceAccount;
mFromPubKey = naPublicKey;
assert(mFromPubKey.isValid());
mTransaction = boost::make_shared<SerializedTransaction>(ttKind);
std::cerr << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID()) << std::endl;
std::cerr << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID()) << std::endl;
mTransaction->setSigningPubKey(mFromPubKey);
mTransaction->setSourceAccount(mAccountFrom);
mTransaction->setSequence(uSeq);
mTransaction->setTransactionFee(uFee);
if (uSourceTag)
{
mTransaction->makeITFieldPresent(sfSourceTag);
mTransaction->setITFieldU32(sfSourceTag, ident);
mTransaction->setITFieldU32(sfSourceTag, uSourceTag);
}
mTransaction->setITFieldU64(sfAmount, amount);
mTransaction->setITFieldAccount(sfDestination, toID.getAccountID());
updateID();
}
#endif
bool Transaction::sign(const NewcoinAddress& naAccountPrivate)
{
if(!naAccountPrivate.isValid())
bool bResult = true;
if (!naAccountPrivate.isValid())
{
#ifdef DEBUG
std::cerr << "No private key for signing" << std::endl;
#endif
return false;
bResult = false;
}
#if 0
if( (mTransaction->getITFieldU64(sfAmount)==0) )
{
#ifdef DEBUG
std::cerr << "Bad amount or destination" << std::endl;
#endif
assert(false);
return false;
}
#endif
if(!getSTransaction()->sign(naAccountPrivate))
else if (!getSTransaction()->sign(naAccountPrivate))
{
#ifdef DEBUG
std::cerr << "Failed to make signature" << std::endl;
#endif
assert(false);
return false;
bResult = false;
}
updateID();
if (bResult)
{
updateID();
}
else
{
mStatus = INCOMPLETE;
}
return true;
return bResult;
}
//
// Claim
//
Transaction::pointer Transaction::setClaim(
const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naGeneratorID,
const std::vector<unsigned char>& vucGenerator)
{
sign(naPrivateKey);
return shared_from_this();
}
Transaction::pointer Transaction::sharedClaim(
const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naSourceAccount,
uint32 uSourceTag,
const NewcoinAddress& naGeneratorID,
const std::vector<unsigned char>& vucGenerator)
{
pointer tResult = boost::make_shared<Transaction>(ttCLAIM,
naPublicKey, naSourceAccount,
0, // Sequence of 0.
0, // Free.
uSourceTag);
return tResult->setClaim(naPrivateKey, naGeneratorID, vucGenerator);
}
//
// Payment
//
Transaction::pointer Transaction::setPayment(
const NewcoinAddress& naPrivateKey,
const NewcoinAddress& toAccount,
uint64 uAmount,
uint32 ledger)
{
mTransaction->setITFieldAccount(sfDestination, toAccount);
mTransaction->setITFieldU64(sfAmount, uAmount);
if (ledger != 0)
{
mTransaction->makeITFieldPresent(sfTargetLedger);
mTransaction->setITFieldU32(sfTargetLedger, ledger);
}
sign(naPrivateKey);
return shared_from_this();
}
Transaction::pointer Transaction::sharedPayment(
const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naSourceAccount,
uint32 uSeq,
uint64 uFee,
uint32 uSourceTag,
const NewcoinAddress& toAccount,
uint64 uAmount,
uint32 ledger)
{
pointer tResult = boost::make_shared<Transaction>(ttMAKE_PAYMENT,
naPublicKey, naSourceAccount,
uSeq, uFee, uSourceTag);
return tResult->setPayment(naPrivateKey, toAccount, uAmount, ledger);
}
//
// Misc.
//
bool Transaction::checkSign() const
{
assert(mFromPubKey.isValid());
@@ -158,8 +195,8 @@ bool Transaction::checkSign() const
void Transaction::setStatus(TransStatus ts, uint32 lseq)
{
mStatus = ts;
mInLedger = lseq;
mStatus = ts;
mInLedger = lseq;
}
void Transaction::saveTransaction(Transaction::pointer txn)
@@ -247,7 +284,6 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
tr->setStatus(st);
return tr;
}
Transaction::pointer Transaction::load(const uint256& id)
@@ -311,22 +347,6 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg
return true;
}
static bool isHex(char j)
{
if ((j >= '0') && (j <= '9')) return true;
if ((j >= 'A') && (j <= 'F')) return true;
if ((j >= 'a') && (j <= 'f')) return true;
return false;
}
bool Transaction::isHexTxID(const std::string& txid)
{
if (txid.size() != 64) return false;
for (int i = 0; i < 64; ++i)
if (!isHex(txid[i])) return false;
return true;
}
Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
{
Json::Value ret(mTransaction->getJson(0));
@@ -360,4 +380,25 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
return ret;
}
//
// Obsolete
//
static bool isHex(char j)
{
if ((j >= '0') && (j <= '9')) return true;
if ((j >= 'A') && (j <= 'F')) return true;
if ((j >= 'a') && (j <= 'f')) return true;
return false;
}
bool Transaction::isHexTxID(const std::string& txid)
{
if (txid.size() != 64) return false;
for (int i = 0; i < 64; ++i)
if (!isHex(txid[i])) return false;
return true;
}
// vim:ts=4

View File

@@ -30,35 +30,66 @@ enum TransStatus
INCOMPLETE = 8 // needs more signatures
};
// This class is for constructing and examining transactions. Transactions are static so manipulation functions are unnecessary.
class Transaction : public boost::enable_shared_from_this<Transaction>
{
public:
typedef boost::shared_ptr<Transaction> pointer;
private:
uint256 mTransactionID;
NewcoinAddress mAccountFrom;
NewcoinAddress mFromPubKey;
NewcoinAddress mFromPubKey; // Sign transaction with this. mSignPubKey
NewcoinAddress mSourcePrivate; // Sign transaction with this.
uint32 mInLedger;
TransStatus mStatus;
uint32 mInLedger;
TransStatus mStatus;
SerializedTransaction::pointer mTransaction;
Transaction::pointer setPayment(
const NewcoinAddress& naPrivateKey,
const NewcoinAddress& toAccount,
uint64 uAmount,
uint32 ledger);
Transaction::pointer setClaim(
const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naGeneratorID,
const std::vector<unsigned char>& vucGenerator);
public:
Transaction(const SerializedTransaction::pointer st, bool bValidate);
static Transaction::pointer sharedTransaction(const std::vector<unsigned char>&vucTransaction, bool bValidate);
Transaction(const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naFromAccount, const NewcoinAddress& toAccount,
uint64 amount,
uint32 iSeq, uint32 ident, uint32 ledger);
Transaction(
TransactionType ttKind,
const NewcoinAddress& naPublicKey,
const NewcoinAddress& naSourceAccount,
uint32 uSeq,
uint64 uFee,
uint32 uSourceTag);
static Transaction::pointer sharedPayment(
const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naSourceAccount,
uint32 uSeq,
uint64 uFee,
uint32 uSourceTag,
const NewcoinAddress& toAccount,
uint64 uAmount,
uint32 ledger);
static Transaction::pointer sharedClaim(
const NewcoinAddress& naPublicKey, const NewcoinAddress& naPrivateKey,
const NewcoinAddress& naSourceAccount,
uint32 uSourceTag,
const NewcoinAddress& naGeneratorID,
const std::vector<unsigned char>& vucGenerator);
#if 0
Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID,
CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger,
CKey::pointer pubKey, uint64 uAmount, uint64 fee, uint32 fromSeq, uint32 fromLedger,
uint32 ident, const std::vector<unsigned char>& signature, uint32 ledgerSeq, TransStatus st);
#endif
@@ -106,9 +137,11 @@ public:
protected:
static Transaction::pointer transactionFromSQL(const std::string& statement);
#if 0
Transaction(const uint256& transactionID, const NewcoinAddress& accountFrom, const NewcoinAddress& accountTo,
CKey::pointer key, uint64 amount, uint64 fee, uint32 fromAccountSeq, uint32 sourceLedger,
CKey::pointer key, uint64 uAmount, uint64 fee, uint32 fromAccountSeq, uint32 sourceLedger,
uint32 ident, const std::vector<unsigned char>& signature, uint32 inLedger, TransStatus status);
#endif
};
#endif

View File

@@ -1,15 +1,21 @@
#include "TransactionEngine.h"
#include "TransactionFormats.h"
#include <boost/format.hpp>
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params)
{
std::cerr << "applyTransaction>" << std::endl;
TransactionEngineResult result = terSUCCESS;
uint256 txID = txn.getTransactionID();
if(!txID) return tenINVALID;
if (!txID)
{
std::cerr << "applyTransaction: invalid transaction id" << std::endl;
return tenINVALID;
}
// Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
@@ -22,7 +28,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
// check signature
if (!txn.checkSign(naPubKey))
{
std::cerr << "applyTransaction: invalid signature" << std::endl;
return tenINVALID;
}
bool bPrepaid = false;
@@ -40,10 +49,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
break;
case ttINVALID:
std::cerr << "applyTransaction: ttINVALID transaction type" << std::endl;
result = tenINVALID;
break;
default:
std::cerr << "applyTransaction: unknown transaction type" << std::endl;
result = tenUNKNOWN;
break;
}
@@ -57,20 +68,30 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
if (bPrepaid)
{
if (txnFee)
{
// Transaction is malformed.
std::cerr << "applyTransaction: fee not allowed" << std::endl;
return tenINSUF_FEE_P;
}
}
else
{
// WRITEME: Check if fee is adequate
if (txnFee == 0)
{
std::cerr << "applyTransaction: insufficient fee" << std::endl;
return tenINSUF_FEE_P;
}
}
}
// get source account ID
uint160 srcAccount = txn.getSourceAccount().getAccountID();
if (!srcAccount) return tenINVALID;
if (!srcAccount)
{
std::cerr << "applyTransaction: bad source id" << std::endl;
return tenINVALID;
}
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
@@ -78,7 +99,11 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
// If we are only verifying some transactions, this would be probablistic.
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount);
if (!src) return terNO_ACCOUNT;
if (!src)
{
std::cerr << str(boost::format("applyTransaction: no such account: %s") % txn.getSourceAccount().humanAccountID()) << std::endl;
return terNO_ACCOUNT;
}
// deduct the fee, so it's not available during the transaction
// we only write the account back if the transaction succeeds
@@ -87,7 +112,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
uint64 balance = src->getIFieldU64(sfBalance);
if (balance < txnFee)
{
std::cerr << "applyTransaction: insufficent balance" << std::endl;
return terINSUF_FEE_B;
}
src->setIFieldU64(sfBalance, balance - txnFee);
}
@@ -98,7 +126,10 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
if (bPrepaid)
{
if (t_seq)
{
std::cerr << "applyTransaction: bad sequence for pre-paid transaction" << std::endl;
return terPAST_SEQ;
}
}
else
{
@@ -107,9 +138,18 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
if (t_seq != a_seq)
{
// WRITEME: Special case code for changing transaction key
if (a_seq < t_seq) return terPRE_SEQ;
if (a_seq < t_seq)
{
std::cerr << "applyTransaction: future sequence number" << std::endl;
return terPRE_SEQ;
}
if (mLedger->hasTransaction(txID))
{
std::cerr << "applyTransaction: duplicate sequence number" << std::endl;
return terALREADY;
}
std::cerr << "applyTransaction: past sequence number" << std::endl;
return terPAST_SEQ;
}
else src->setIFieldU32(sfSequence, t_seq);
@@ -121,6 +161,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
switch(txn.getTxnType())
{
case ttINVALID:
std::cerr << "applyTransaction: invalid type" << std::endl;
result = tenINVALID;
break;
@@ -178,6 +219,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
std::cerr << "doClaim>" << std::endl;
NewcoinAddress naSigningPubKey;
naSigningPubKey.setAccountPublic(txn.peekSigningPubKey());
@@ -185,15 +227,24 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction&
uint160 sourceAccountID = naSigningPubKey.getAccountID();
if (sourceAccountID != txn.getSourceAccount().getAccountID())
{
// Signing Pub Key must be for Source Account ID.
std::cerr << "sourceAccountID: " << naSigningPubKey.humanAccountID() << std::endl;
std::cerr << "txn accountID: " << txn.getSourceAccount().humanAccountID() << std::endl;
return tenINVALID;
}
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer dest = mLedger->getAccountRoot(qry, sourceAccountID);
if (!dest)
{
// Source account does not exist. Could succeed if it was created first.
std::cerr << str(boost::format("doClaim: no such account: %s") % txn.getSourceAccount().humanAccountID()) << std::endl;
return terNO_ACCOUNT;
}
std::cerr << str(boost::format("doClaim: %s") % dest->getFullText()) << std::endl;
if (dest->getIFieldPresent(sfAuthorizedKey))
// Source account already claimed.
@@ -225,6 +276,7 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction&
accounts.push_back(std::make_pair(taaCREATE, gen));
std::cerr << "doClaim<" << std::endl;
return terSUCCESS;
}

View File

@@ -36,13 +36,12 @@ void printHelp(const po::options_description& desc)
cout << desc << endl;
cout << "Commands: " << endl;
cout << " accountinfo <family>:<key>" << endl;
cout << " account_info <account>|<nickname>" << endl;
cout << " account_info <seed>|<pass_phrase>|<key> [<index>]" << endl;
cout << " connect <ip> [<port>]" << endl;
cout << " createfamily [<key>]" << endl;
cout << " familyinfo" << endl;
cout << " ledger" << endl;
cout << " lock <family>" << endl;
cout << " newaccount <family> [<name>]" << endl;
cout << " peers" << endl;
cout << " sendto <destination> <amount> [<tag>]" << endl;
cout << " stop" << endl;
@@ -115,14 +114,14 @@ int main(int argc, char* argv[])
if (iCmd)
vCmd = vm["parameters"].as<std::vector<std::string> >();
/*
char* pvCmd[iCmd];
std::vector<char*> pvCmd;
pvCmd.resize(iCmd);
for (int i=0; i != iCmd; ++i)
pvCmd[i] = (char*) (vCmd[0].c_str());
iResult = unit_test_main(init_unit_test, iCmd, pvCmd);
*/
iResult = unit_test_main(init_unit_test, iCmd, &pvCmd.front());
}
else if (!vm.count("parameters"))
{

View File

@@ -22,6 +22,7 @@ enum MessageType {
mtPROPOSE_LEDGER= 33;
mtCLOSE_LEDGER= 35;
mtSTATUS_CHANGE= 36;
mtPEER_POSITION= 37;
// data replication and synchronization
mtGET_VALIDATIONS= 40;
@@ -98,10 +99,21 @@ message TMStatusChange {
}
message TMPeerPosition {
required uint32 ledgerSequence = 1;
required bytes pubKey = 2;
required uint32 sequence = 3;
required bytes transactionHash = 4;
required bytes signature = 5;
}
message TMHaveTransactionSet {
repeated bytes hashes = 1;
}
message TMProposeLedger {
required uint32 closingSeq = 1;
required uint32 secondsSinceClose = 2;
required uint32 proposeSeq = 2;
required bytes previousLedgerHash = 3; // 0 if first proposal, hash we no longer propose
required bytes currentLedgerHash = 4; // the hash of the ledger we are proposing
required bytes hanko = 5;
@@ -110,6 +122,8 @@ message TMProposeLedger {
required bytes signature = 8;
}
// Used to propose/validate during ledger close
message TMValidation {
required uint32 ledgerIndex = 1;
@@ -205,14 +219,15 @@ message TMObjectByHash
}
message TMLedgerNode {
optional bytes nodeid = 1;
required bytes nodeid = 1;
required bytes nodedata = 2;
}
enum TMLedgerInfoType {
liBASE = 0; // basic ledger info
liTX_NODE = 1; // transaction node
liAS_NODE = 2; // account state node
liBASE = 0; // basic ledger info
liTX_NODE = 1; // transaction node
liAS_NODE = 2; // account state node
liTS_CANDIDATE = 3; // candidate transaction set
}
enum TMLedgerType {