Merge branch 'pay'

This commit is contained in:
Arthur Britto
2012-05-19 18:20:14 -07:00
11 changed files with 314 additions and 127 deletions

View File

@@ -1,11 +1,156 @@
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/test/unit_test.hpp>
#include "Config.h"
#include "SerializedTypes.h"
#include "utils.h"
bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency)
{
bool bSuccess = true;
if (sCurrency.empty() || !sCurrency.compare(SYSTEM_CURRENCY_CODE))
{
uDstCurrency = 0;
}
else if (3 == sCurrency.size())
{
std::vector<unsigned char> vucIso(3);
std::transform(sCurrency.begin(), sCurrency.end(), vucIso.begin(), ::toupper);
// std::string sIso;
// sIso.assign(vucIso.begin(), vucIso.end());
// std::cerr << "currency: " << sIso << std::endl;
Serializer s;
s.addZeros(98/8);
s.addRaw(vucIso);
s.addZeros(16/8);
s.addZeros(25/8);
SerializerIterator sit(s);
uDstCurrency = sit.get160();
}
else
{
bSuccess = false;
}
return bSuccess;
}
std::string STAmount::getCurrencyHuman()
{
std::string sCurrency;
if (mIsNative)
{
return SYSTEM_CURRENCY_CODE;
}
else
{
uint160 uReserved = mCurrency;
Serializer s(160/20);
s.add160(mCurrency);
SerializerIterator sit(s);
std::vector<unsigned char> vucZeros = sit.getRaw(96/8);
std::vector<unsigned char> vucIso = sit.getRaw(24/8);
std::vector<unsigned char> vucVersion = sit.getRaw(16/8);
std::vector<unsigned char> vucReserved = sit.getRaw(24/8);
if (!::isZero(vucZeros.begin(), vucZeros.size()))
{
throw std::runtime_error("bad currency: zeros");
}
else if (!::isZero(vucVersion.begin(), vucVersion.size()))
{
throw std::runtime_error("bad currency: version");
}
else if (!::isZero(vucReserved.begin(), vucReserved.size()))
{
throw std::runtime_error("bad currency: reserved");
}
else
{
sCurrency.assign(vucIso.begin(), vucIso.end());
}
}
return sCurrency;
}
// Not meant to be the ultimate parser. For use by RPC which is supposed to be sane and trusted.
bool STAmount::setValue(const std::string& sAmount, const std::string& sCurrency)
{
if (!currencyFromString(mCurrency, sCurrency))
return false;
uint64 uValue;
int iOffset;
size_t uDecimal = sAmount.find_first_of(".,");
bool bInteger = uDecimal == std::string::npos;
if (bInteger)
{
uValue = sAmount.empty() ? 0 : boost::lexical_cast<uint>(sAmount);
iOffset = 0;
}
else
{
// Example size decimal size-decimal offset
// .1 2 0 2 -1
// 123. 4 3 1 0
// 1.23 4 1 3 -2
iOffset = -(sAmount.size()-uDecimal-1);
uint64 uInteger = uDecimal ? boost::lexical_cast<uint64>(sAmount.substr(0, uDecimal)) : 0;
uint64 uFraction = iOffset ? boost::lexical_cast<uint64>(sAmount.substr(uDecimal+1)) : 0;
uValue = uInteger;
for (int i=-iOffset; i--;)
uValue *= 10;
uValue += uFraction;
}
mIsNative = !mCurrency;
if (mIsNative)
{
if (bInteger)
iOffset = -SYSTEM_CURRENCY_PRECISION;
while (iOffset > -SYSTEM_CURRENCY_PRECISION) {
uValue *= 10;
--iOffset;
}
while (iOffset < -SYSTEM_CURRENCY_PRECISION) {
uValue /= 10;
++iOffset;
}
mValue = uValue;
}
else
{
mValue = uValue;
mOffset = iOffset;
canonicalize();
}
return true;
}
// amount = value * [10 ^ offset]
// representation range is 10^80 - 10^(-80)

View File

@@ -15,17 +15,6 @@
Application* theApp=NULL;
/*
What needs to happen:
Listen for connections
Try to maintain the right number of connections
Process messages from peers
Process messages from RPC
Periodically publish a new ledger
Save the various pieces of data
*/
DatabaseCon::DatabaseCon(const std::string& name, const char *initStrings[], int initCount)
{
std::string path=strprintf("%s%s", theConfig.DATA_DIR.c_str(), name.c_str());
@@ -117,9 +106,8 @@ void Application::run()
rootAddress.setAccountPublic(rootGeneratorMaster, 0);
std::cerr << "Master seed: " << rootSeedMaster.humanFamilySeed() << std::endl;
std::cerr << "Master generator: " << rootGeneratorMaster.humanFamilyGenerator() << std::endl;
std::cerr << "Root public key: " << rootAddress.humanAccountPublic() << std::endl;
// Print enough information to be able to claim root account.
std::cerr << "Root master seed: " << rootSeedMaster.humanFamilySeed() << std::endl;
std::cerr << "Root account: " << rootAddress.humanAccountID() << std::endl;
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, 100000000);

View File

@@ -7,6 +7,7 @@
#include <fstream>
#include <boost/lexical_cast.hpp>
// Fees are in XNS raw.
#define DEFAULT_FEE_CREATE 1000
#define DEFAULT_FEE_DEFAULT 100
@@ -121,15 +122,6 @@ void Config::load()
FEE_DEFAULT = boost::lexical_cast<int>(strTemp);
}
}
/*
node=root.child("DB_TYPE");
if(!node.empty())
{
if( stricmp(node.child_value(),"mysql")==0 ) theApp->setDB(Database::newMysqlDatabase("host","user","pass"));
else theApp->setSerializer(new DiskSerializer());
}else */
}
// vim:ts=4

View File

@@ -2,11 +2,14 @@
#define __CONFIG__
#include "types.h"
#include "SerializedTypes.h"
#include <string>
#define SYSTEM_NAME "newcoin"
#define VALIDATORS_SITE "redstem.com"
#define SYSTEM_NAME "newcoin"
#define VALIDATORS_SITE "redstem.com"
#define SYSTEM_CURRENCY_CODE "XNS"
#define SYSTEM_CURRENCY_PRECISION 6
#define VALIDATORS_FILE_NAME "validators.txt"
const int SYSTEM_PEER_PORT = 6561;
@@ -26,47 +29,49 @@ const int SYSTEM_PEER_PORT = 6561;
class Config
{
public:
// core software parameters
int VERSION;
// Core software parameters
int VERSION;
std::string VERSION_STR;
// network parameters
int NETWORK_START_TIME; // The Unix time we start ledger 0
int TRANSACTION_FEE_BASE;
int LEDGER_SECONDS;
int LEDGER_PROPOSAL_DELAY_SECONDS;
int LEDGER_AVALANCHE_SECONDS;
// Network parameters
int NETWORK_START_TIME; // The Unix time we start ledger 0
int TRANSACTION_FEE_BASE;
int LEDGER_SECONDS;
int LEDGER_PROPOSAL_DELAY_SECONDS;
int LEDGER_AVALANCHE_SECONDS;
// Note: The following parameters do not relate to the UNL or trust at all
int NETWORK_QUORUM; // Minimum number of nodes to consider the network present
int VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
int NETWORK_QUORUM; // Minimum number of nodes to consider the network present
int VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
// node networking parameters
// Peer networking parameters
std::string PEER_IP;
int PEER_PORT;
int NUMBER_CONNECTIONS;
// bool NODE_INBOUND; // we accept inbound connections
// bool NODE_DATABASE; // we offer historical data services
// bool NODE_PUBLIC; // we do not attempt to hide our identity
// bool NODE_DUMB; // we are a 'dumb' client
// bool NODE_SMART; // we offer services to 'dumb' clients
// RPC parameters
std::string RPC_IP;
int RPC_PORT;
std::string RPC_USER;
std::string RPC_PASSWORD;
std::string VALIDATION_PASSWORD;
std::string VALIDATION_KEY;
int PEER_PORT;
int NUMBER_CONNECTIONS;
std::string PEER_SSL_CIPHER_LIST;
int PEER_SCAN_INTERVAL_MIN;
int PEER_START_MAX;
int PEER_CONNECT_LOW_WATER;
uint64 FEE_CREATE; // Fee to create an account
uint64 FEE_DEFAULT; // Default fee.
// bool NODE_INBOUND; // We accept inbound connections
// bool NODE_DATABASE; // We offer historical data services
// bool NODE_PUBLIC; // We do not attempt to hide our identity
// bool NODE_DUMB; // We are a 'dumb' client
// bool NODE_SMART; // We offer services to 'dumb' clients
// RPC parameters
std::string RPC_IP;
int RPC_PORT;
std::string RPC_USER;
std::string RPC_PASSWORD;
// Validation
std::string VALIDATION_PASSWORD;
std::string VALIDATION_KEY;
// Fees
STAmount FEE_CREATE; // Fee to create an account
STAmount FEE_DEFAULT; // Default fee.
// configuration parameters
std::string DATA_DIR;

View File

@@ -29,7 +29,7 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
startAccount->peekSLE().setIFieldAmount(sfBalance, startAmount);
startAccount->peekSLE().setIFieldU32(sfSequence, 1);
writeBack(lepCREATE, startAccount->getSLE());
#ifdef DEBUG
#if 0
std::cerr << "Root account:";
startAccount->dump();
#endif

View File

@@ -353,63 +353,63 @@ Json::Value RPCServer::doPeers(Json::Value& params)
return theApp->getConnectionPool().getPeersJson();
}
Json::Value RPCServer::doSendTo(Json::Value& params)
{ // Implement simple sending without gathering
// sendto <destination> <amount>
// sendto <destination> <amount> <tag>
if (!params.isArray() || (params.size()<2))
// send regular_seed paying_account account_id amount [currency] [send_max] [send_currency]
Json::Value RPCServer::doSend(Json::Value& params)
{
NewcoinAddress naSeed;
NewcoinAddress naSrcAccountID;
NewcoinAddress naDstAccountID;
STAmount saSrcAmount;
STAmount saDstAmount;
std::string sSrcCurrency;
std::string sDstCurrency;
if (params.size() >= 5)
sDstCurrency = params[4u].asString();
if (params.size() >= 7)
sSrcCurrency = params[6u].asString();
if (!params.isArray() || params.size() < 3 || params.size() > 7)
{
return JSONRPCError(500, "Invalid parameters");
int paramCount=getParamCount(params);
if ((paramCount<2)||(paramCount>3))
return JSONRPCError(500, "Invalid parameters");
std::string sDest, sAmount;
if (!extractString(sDest, params, 0) || !extractString(sAmount, params, 1))
return JSONRPCError(500, "Invalid parameters");
NewcoinAddress destAccount;
destAccount.setAccountID(sDest) || destAccount.setAccountPublic(sDest);
if (!destAccount.isValid())
return JSONRPCError(500, "Unable to parse destination account");
uint64 iAmount;
try
{
iAmount=boost::lexical_cast<uint64>(sAmount);
if (iAmount<=0) return JSONRPCError(500, "Invalid amount");
}
catch (...)
else if (!naSeed.setFamilySeedGeneric(params[0u].asString()))
{
return JSONRPCError(500, "Invalid amount");
return JSONRPCError(500, "disallowed seed");
}
uint32 iTag(0);
try
else if (!naSrcAccountID.setAccountID(params[1u].asString()))
{
if (paramCount>2)
{
std::string sTag;
extractString(sTag, params, 2);
iTag=boost::lexical_cast<uint32>(sTag);
}
return JSONRPCError(500, "source account id needed");
}
catch (...)
else if (!naDstAccountID.setAccountID(params[2u].asString()))
{
return JSONRPCError(500, "Invalid tag");
return JSONRPCError(500, "create account id needed");
}
else if (!saDstAmount.setValue(params[3u].asString(), sDstCurrency))
{
return JSONRPCError(500, "bad dst amount/currency");
}
else if (!saSrcAmount.setValue(params[5u].asString(), sSrcCurrency))
{
return JSONRPCError(500, "bad src amount/currency");
}
else
{
Json::Value obj(Json::objectValue);
#ifdef DEBUG
std::cerr << "SendTo(" << destAccount.humanAccountID() << ") amount=" << iAmount <<
", tag=" << iTag << std::endl;
#endif
// obj["transaction"] = trans->getSTransaction()->getJson(0);
obj["seed"] = naSeed.humanFamilySeed();
obj["srcAccountID"] = naSrcAccountID.humanAccountID();
obj["dstAccountID"] = naDstAccountID.humanAccountID();
obj["srcAmount"] = saSrcAmount.getText();
obj["srcISO"] = saSrcAmount.getCurrencyHuman();
obj["dstAmount"] = saDstAmount.getText();
obj["dstISO"] = saDstAmount.getCurrencyHuman();
LocalTransaction::pointer lt(new LocalTransaction(destAccount, iAmount, iTag));
if (!lt->makeTransaction())
return JSONRPCError(500, "Insufficient funds in unlocked accounts");
lt->performTransaction();
return lt->getTransaction()->getJson(true);
return obj;
}
}
Json::Value RPCServer::doTx(Json::Value& params)
@@ -549,6 +549,16 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) {
return obj;
}
Json::Value RPCServer::doWalletAccounts(Json::Value& params)
{
return "not implemented";
}
Json::Value RPCServer::doWalletAdd(Json::Value& params)
{
return "not implemented";
}
// wallet_claim <master_seed> <regular_seed> [<source_tag>] [<account_annotation>]
//
// To provide an example to client writers, we do everything we expect a client to do here.
@@ -573,7 +583,7 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
}
else
{
// Trying to build:
// Building:
// peer_wallet_claim <account_id> <authorized_key> <encrypted_master_public_generator> <generator_pubkey> <generator_signature>
// <source_tag> [<annotation>]
//
@@ -646,31 +656,31 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params)
// YYY Need annotation and source tag
Json::Value RPCServer::doWalletCreate(Json::Value& params)
{
NewcoinAddress naSourceID;
NewcoinAddress naCreateID;
NewcoinAddress naSrcAccountID;
NewcoinAddress naDstAccountID;
NewcoinAddress naRegularSeed;
if (params.size() < 3 || params.size() > 4)
{
return "invalid params";
}
else if (!naSourceID.setAccountID(params[1u].asString()))
{
return "source account id needed";
}
else if (!naCreateID.setAccountID(params[2u].asString()))
{
return "create account id needed";
}
else if (!naRegularSeed.setFamilySeedGeneric(params[0u].asString()))
{
return "disallowed seed";
}
else if (!naSrcAccountID.setAccountID(params[1u].asString()))
{
return "source account id needed";
}
else if (!naDstAccountID.setAccountID(params[2u].asString()))
{
return "create account id needed";
}
else if (!theApp->getOPs().available()) {
// We require access to the paying account's sequence number and key information.
return "network not available";
}
else if (theApp->getMasterLedger().getCurrentLedger()->getAccountState(naCreateID))
else if (theApp->getMasterLedger().getCurrentLedger()->getAccountState(naDstAccountID))
{
return "account already exists";
}
@@ -684,7 +694,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger();
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer sleSrc = ledger->getAccountRoot(qry, naSourceID);
SerializedLedgerEntry::pointer sleSrc = ledger->getAccountRoot(qry, naSrcAccountID);
if (!sleSrc)
{
@@ -694,7 +704,6 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance);
STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast<uint64>(params[3u].asString());
#if 0
if (saSrcBalance < theConfig.FEE_CREATE + saInitialFunds)
{
return "insufficent funds";
@@ -703,7 +712,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
{
return "source account has not been claimed";
}
#endif
NewcoinAddress naRegularGenerator;
NewcoinAddress naRegular0Public;
NewcoinAddress naRegular0Private;
@@ -742,7 +751,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
do {
++iIndex;
naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
} while (naSourceID.getAccountID() != naMasterAccountPublic.getAccountID());
} while (naSrcAccountID.getAccountID() != naMasterAccountPublic.getAccountID());
NewcoinAddress naRegularAccountPublic;
NewcoinAddress naRegularAccountPrivate;
@@ -761,11 +770,11 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
Transaction::pointer trans = Transaction::sharedCreate(
naRegularAccountPublic, naRegularAccountPrivate,
naSourceID,
naSrcAccountID,
sleSrc->getIFieldU32(sfSequence),
theConfig.FEE_CREATE,
0, // YYY No source tag
naCreateID,
naDstAccountID,
saInitialFunds); // Initial funds in XNC.
(void) theApp->getOPs().processTransaction(trans);
@@ -841,6 +850,11 @@ Json::Value RPCServer::doWalletSeed(Json::Value& params)
}
}
Json::Value RPCServer::doWalletVerify(Json::Value& params)
{
return "not implemented";
}
void RPCServer::validatorsResponse(const boost::system::error_code& err, std::string strResponse)
{
std::cerr << "Fetch '" VALIDATORS_FILE_NAME "' complete." << std::endl;
@@ -974,6 +988,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
if (command == "account_info") return doAccountInfo(params);
if (command == "connect") return doConnect(params);
if (command == "peers") return doPeers(params);
if (command == "send") return doSend(params);
if (command == "stop") return doStop(params);
if (command == "unl_add") return doUnlAdd(params);
@@ -985,16 +1001,18 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
if (command == "validation_create") return doValidatorCreate(params);
if (command == "wallet_accounts") return doWalletAccounts(params);
if (command == "wallet_add") return doWalletAdd(params);
if (command == "wallet_claim") return doWalletClaim(params);
if (command == "wallet_create") return doWalletCreate(params);
if (command == "wallet_propose") return doWalletPropose(params);
if (command == "wallet_seed") return doWalletSeed(params);
if (command == "wallet_verify") return doWalletVerify(params);
//
// Obsolete or need rewrite:
//
if (command=="sendto") return doSendTo(params);
if (command=="tx") return doTx(params);
if (command=="ledger") return doLedger(params);

View File

@@ -35,7 +35,7 @@ class RPCServer : public boost::enable_shared_from_this<RPCServer>
Json::Value doConnect(Json::Value& params);
Json::Value doLedger(Json::Value& params);
Json::Value doPeers(Json::Value& params);
Json::Value doSendTo(Json::Value& params);
Json::Value doSend(Json::Value& params);
Json::Value doSessionClose(Json::Value& params);
Json::Value doSessionOpen(Json::Value& params);
Json::Value doStop(Json::Value& params);
@@ -52,12 +52,14 @@ class RPCServer : public boost::enable_shared_from_this<RPCServer>
Json::Value doValidatorCreate(Json::Value& params);
Json::Value doWalletAccounts(Json::Value& params);
Json::Value doWalletAdd(Json::Value& params);
Json::Value doWalletClaim(Json::Value& params);
Json::Value doWalletCreate(Json::Value& params);
Json::Value doWalletLock(Json::Value& params);
Json::Value doWalletPropose(Json::Value& params);
Json::Value doWalletSeed(Json::Value& params);
Json::Value doWalletUnlock(Json::Value& params);
Json::Value doWalletVerify(Json::Value& params);
void validatorsResponse(const boost::system::error_code& err, std::string strResponse);

View File

@@ -232,10 +232,12 @@ public:
int getOffset() const { return mOffset; }
uint64 getValue() const { return mValue; }
void setValue(const STAmount& v) { mValue=v; }
std::string getCurrencyHuman();
bool isNative() const { return mIsNative; }
const uint160& getCurrency() const { return mCurrency; }
void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; }
bool isZero() const { return mValue == 0; }
bool setValue(const std::string& sAmount, const std::string& sCurrency);
virtual bool isEquivalent(const SerializedType& t) const;
@@ -279,6 +281,7 @@ public:
const char* name = NULL);
static STAmount deSerialize(SerializerIterator&);
static bool currencyFromString(uint160& uDstCurrency, const std::string& sCurrency);
};
class STHash128 : public SerializedType

View File

@@ -4,6 +4,16 @@
#include <openssl/ripemd.h>
#include <openssl/sha.h>
int Serializer::addZeros(size_t uBytes)
{
int ret = mData.size();
while (uBytes--)
mData.push_back(0);
return ret;
}
int Serializer::add16(uint16 i)
{
int ret = mData.size();
@@ -574,4 +584,13 @@ std::vector<TaggedListItem> SerializerIterator::getTaggedList()
mPos += length;
return tl;
}
std::vector<unsigned char> SerializerIterator::getRaw(int iLength)
{
int iPos = mPos;
mPos += iLength;
return mSerializer.getRaw(iPos, iLength);
}
// vim:ts=4

View File

@@ -36,6 +36,7 @@ class Serializer
int addRaw(const std::vector<unsigned char> &vector);
int addRaw(const void *ptr, int len);
int addRaw(const Serializer& s);
int addZeros(size_t uBytes);
int addVL(const std::vector<unsigned char> &vector);
int addVL(const void *ptr, int len);
@@ -136,6 +137,8 @@ public:
uint160 get160();
uint256 get256();
std::vector<unsigned char> getRaw(int iLength);
std::vector<unsigned char> getVL();
std::vector<TaggedListItem> getTaggedList();
};

View File

@@ -54,18 +54,30 @@ std::string strHex(Iterator first, int iSize)
return strDst;
}
inline const std::string strHex(const std::string& strSrc) {
inline const std::string strHex(const std::string& strSrc)
{
return strHex(strSrc.begin(), strSrc.size());
}
inline std::string strHex(const std::vector<unsigned char> vchData) {
return strHex(vchData.begin(), vchData.size());
inline std::string strHex(const std::vector<unsigned char> vucData)
{
return strHex(vucData.begin(), vucData.size());
}
inline const std::string strHex(const uint160& ui) {
inline const std::string strHex(const uint160& ui)
{
return strHex(ui.begin(), ui.size());
}
template<class Iterator>
bool isZero(Iterator first, int iSize)
{
while (iSize && !*first++)
--iSize;
return !iSize;
}
int charUnHex(char cDigit);
void strUnHex(std::string& strDst, const std::string& strSrc);