diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp index 71b67774f4..88b51c9eb4 100644 --- a/src/cpp/ripple/Config.cpp +++ b/src/cpp/ripple/Config.cpp @@ -13,11 +13,11 @@ #define SECTION_ACCOUNT_PROBE_MAX "account_probe_max" #define SECTION_DEBUG_LOGFILE "debug_logfile" -#define SECTION_FEE_ACCOUNT_CREATE "fee_account_create" #define SECTION_FEE_DEFAULT "fee_default" #define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create" #define SECTION_FEE_OFFER "fee_offer" #define SECTION_FEE_OPERATION "fee_operation" +#define SECTION_FEE_RESERVE "fee_reserve" #define SECTION_LEDGER_HISTORY "ledger_history" #define SECTION_IPS "ips" #define SECTION_NETWORK_QUORUM "network_quorum" @@ -48,7 +48,7 @@ // Fees are in XRP. #define DEFAULT_FEE_DEFAULT 10 -#define DEFAULT_FEE_ACCOUNT_CREATE 200*SYSTEM_CURRENCY_PARTS +#define DEFAULT_FEE_RESERVE 200*SYSTEM_CURRENCY_PARTS #define DEFAULT_FEE_NICKNAME_CREATE 1000 #define DEFAULT_FEE_OFFER DEFAULT_FEE_DEFAULT #define DEFAULT_FEE_OPERATION 1 @@ -162,7 +162,7 @@ void Config::setup(const std::string& strConf, bool bQuiet) NETWORK_QUORUM = 0; // Don't need to see other nodes VALIDATION_QUORUM = 1; // Only need one node to vouch - FEE_ACCOUNT_CREATE = DEFAULT_FEE_ACCOUNT_CREATE; + FEE_RESERVE = DEFAULT_FEE_RESERVE; FEE_NICKNAME_CREATE = DEFAULT_FEE_NICKNAME_CREATE; FEE_OFFER = DEFAULT_FEE_OFFER; FEE_DEFAULT = DEFAULT_FEE_DEFAULT; @@ -297,8 +297,8 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp)) VALIDATION_QUORUM = std::max(0, boost::lexical_cast(strTemp)); - if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp)) - FEE_ACCOUNT_CREATE = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_FEE_RESERVE, strTemp)) + FEE_RESERVE = boost::lexical_cast(strTemp); if (sectionSingleB(secConfig, SECTION_FEE_NICKNAME_CREATE, strTemp)) FEE_NICKNAME_CREATE = boost::lexical_cast(strTemp); diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index bd3c9c56e5..881fb572e3 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -106,9 +106,9 @@ public: // Validation RippleAddress VALIDATION_SEED, VALIDATION_PUB, VALIDATION_PRIV; - // Fees + // Fee schedule uint64 FEE_DEFAULT; // Default fee. - uint64 FEE_ACCOUNT_CREATE; // Fee to create an account. + uint64 FEE_RESERVE; // Amount of XRP not allowed to send. uint64 FEE_NICKNAME_CREATE; // Fee to create a nickname. uint64 FEE_OFFER; // Rate per day. int FEE_CONTRACT_OPERATION; // fee for each contract operation diff --git a/src/cpp/ripple/PaymentTransactor.cpp b/src/cpp/ripple/PaymentTransactor.cpp index 2d30ff9628..acd0021e9c 100644 --- a/src/cpp/ripple/PaymentTransactor.cpp +++ b/src/cpp/ripple/PaymentTransactor.cpp @@ -4,23 +4,10 @@ #define RIPPLE_PATHS_MAX 3 -// only have the higher fee if the account doesn't in fact exist -void PaymentTransactor::calculateFee() -{ - if (mTxn.getFlags() & tfCreateAccount) - { - const uint160 uDstAccountID = mTxn.getFieldAccount160(sfDestination); - SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - if(!sleDst) mFeeDue = theConfig.FEE_ACCOUNT_CREATE; - else Transactor::calculateFee(); - }else Transactor::calculateFee(); -} - TER PaymentTransactor::doApply() { // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = mTxn.getFlags(); - const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality); const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); @@ -87,17 +74,20 @@ TER PaymentTransactor::doApply() if (!sleDst) { // Destination account does not exist. - if (bCreate && !saDstAmount.isNative()) + + if (!saDstAmount.isNative()) { // This restriction could be relaxed. Log(lsINFO) << "doPayment: Malformed transaction: Create account may only fund XRP."; return temCREATEXRP; } - else if (!bCreate) + else if (isSetBit(mParams, tapOPEN_LEDGER) // Ledger is not final, we can vote. + && saDstAmount.getNValue() < theConfig.FEE_RESERVE) // Reserve is not scaled by fee. { - Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist."; + Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist insufficent payment to create account."; + // Not a local failure. Another transaction could create account and then this transaction would succeed. return terNO_DST; } @@ -148,7 +138,7 @@ TER PaymentTransactor::doApply() STAmount saSrcXRPBalance = mTxnAccount->getFieldAmount(sfBalance); - if (saSrcXRPBalance < saDstAmount) + if (saSrcXRPBalance < saDstAmount + theConfig.FEE_RESERVE) // Reserve is not scaled by fee. { // Transaction might succeed, if applied in a different order. Log(lsINFO) << "doPayment: Delay transaction: Insufficient funds."; @@ -158,13 +148,18 @@ TER PaymentTransactor::doApply() else { mTxnAccount->setFieldAmount(sfBalance, saSrcXRPBalance - saDstAmount); + // re-arm the password change fee if we can and need to if ( (sleDst->getFlags() & lsfPasswordSpent) && (saDstAmount > theConfig.FEE_DEFAULT) ) { sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount-theConfig.FEE_DEFAULT); sleDst->clearFlag(lsfPasswordSpent); - }else sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount); + } + else + { + sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount); + } terResult = tesSUCCESS; } diff --git a/src/cpp/ripple/PaymentTransactor.h b/src/cpp/ripple/PaymentTransactor.h index 862a3d3fd4..6b7d8a2b91 100644 --- a/src/cpp/ripple/PaymentTransactor.h +++ b/src/cpp/ripple/PaymentTransactor.h @@ -5,7 +5,6 @@ class PaymentTransactor : public Transactor { - void calculateFee(); public: PaymentTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {} diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 33f80df17b..e1dc3c1786 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -912,10 +912,7 @@ Json::Value RPCHandler::doSubmit(Json::Value jvRequest) if (!txJSON.isMember("Fee")) { - if (mNetOps->getAccountState(mNetOps->getCurrentLedger(), dstAccountID)) - txJSON["Fee"] = (int) theConfig.FEE_DEFAULT; - else - txJSON["Fee"] = (int) theConfig.FEE_ACCOUNT_CREATE; + txJSON["Fee"] = (int) theConfig.FEE_DEFAULT; } if (txJSON.isMember("Paths") && jvRequest.isMember("build_path")) diff --git a/src/cpp/ripple/TransactionFormats.h b/src/cpp/ripple/TransactionFormats.h index 6f399c5917..778da0405b 100644 --- a/src/cpp/ripple/TransactionFormats.h +++ b/src/cpp/ripple/TransactionFormats.h @@ -61,12 +61,12 @@ const uint32 tfPassive = 0x00010000; const uint32 tfOfferCreateMask = ~(tfPassive); // Payment flags: -const uint32 tfCreateAccount = 0x00010000; +const uint32 tfPaymentLegacy = 0x00010000; // Left here to avoid ledger change. const uint32 tfPartialPayment = 0x00020000; const uint32 tfLimitQuality = 0x00040000; const uint32 tfNoRippleDirect = 0x00080000; -const uint32 tfPaymentMask = ~(tfCreateAccount|tfPartialPayment|tfLimitQuality|tfNoRippleDirect); +const uint32 tfPaymentMask = ~(tfPartialPayment|tfLimitQuality|tfNoRippleDirect); #endif // vim:ts=4 diff --git a/src/js/remote.js b/src/js/remote.js index 190b6ff137..4a84228da3 100644 --- a/src/js/remote.js +++ b/src/js/remote.js @@ -267,7 +267,7 @@ Remote.flags = { }, 'Payment' : { - 'CreateAccount' : 0x00010000, + 'PaymentLegacy' : 0x00010000, 'PartialPayment' : 0x00020000, 'LimitQuality' : 0x00040000, 'NoRippleDirect' : 0x00080000, @@ -277,7 +277,6 @@ Remote.flags = { // XXX This needs to be determined from the network. Remote.fees = { 'default' : Amount.from_json("10"), - 'account_create' : Amount.from_json("1000000000"), 'nickname_create' : Amount.from_json("1000"), 'offer' : Amount.from_json("10"), }; @@ -1260,14 +1259,7 @@ Transaction.prototype.submit = function (callback) { // YYY Might check paths for invalid accounts. if (this.remote.local_fee && undefined === tx_json.Fee) { - if ('Payment' === tx_json.TransactionType - && tx_json.Flags & Remote.flags.Payment.CreateAccount) { - - tx_json.Fee = Remote.fees.account_create.to_json(); - } - else { - tx_json.Fee = Remote.fees['default'].to_json(); - } + tx_json.Fee = Remote.fees['default'].to_json(); } if (this.callback || this.listeners('final').length || this.listeners('lost').length || this.listeners('pending').length) { @@ -1435,9 +1427,6 @@ Transaction.prototype.set_flags = function (flags) { // XXX Immediately report an error or mark it. } } - - if (this.remote.local_fee && (this.tx_json.Flags & Remote.flags.Payment.CreateAccount)) - this.tx_json.Fee = Remote.fees.account_create.to_json(); } return this; diff --git a/test/offer-test.js b/test/offer-test.js index af7b688535..4b57c27341 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -157,7 +157,7 @@ buster.testCase("Offer tests", { }, - "new user offer_create then ledger_accept then offer_cancel then ledger_accept." : + "//new user offer_create then ledger_accept then offer_cancel then ledger_accept." : function (done) { var self = this; var final_create; @@ -167,7 +167,6 @@ buster.testCase("Offer tests", { function (callback) { self.remote.transaction() .payment('root', 'alice', "1000") - .set_flags('CreateAccount') .on('proposed', function (m) { // console.log("proposed: %s", JSON.stringify(m)); buster.assert.equals(m.result, 'tesSUCCESS'); @@ -260,8 +259,7 @@ buster.testCase("Offer tests", { async.waterfall([ function (callback) { self.remote.transaction() - .payment('root', 'alice', Amount.from_json("10000")) - .set_flags('CreateAccount') + .payment('root', 'alice', Amount.from_json("10000.0")) .on('proposed', function (m) { // console.log("PROPOSED: CreateAccount: %s", JSON.stringify(m)); callback(m.result !== 'tesSUCCESS', m); @@ -345,7 +343,7 @@ buster.testCase("Offer tests", { function (callback) { self.what = "Create accounts."; - testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback); + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "mtgox"], callback); }, function (callback) { self.what = "Set limits."; @@ -402,7 +400,7 @@ buster.testCase("Offer tests", { testutils.verify_balances(self.remote, { - "alice" : [ "0/USD/mtgox", String(10000+500-2*(Remote.fees['default'].to_number())) ], + "alice" : [ "0/USD/mtgox", String(10000000000+500-2*(Remote.fees['default'].to_number())) ], "bob" : "100/USD/mtgox", }, callback); @@ -427,7 +425,7 @@ buster.testCase("Offer tests", { function (callback) { self.what = "Create accounts."; - testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback); + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "mtgox"], callback); }, function (callback) { self.what = "Set limits."; @@ -484,7 +482,7 @@ buster.testCase("Offer tests", { testutils.verify_balances(self.remote, { - "alice" : [ "160/USD/mtgox", String(10000+200-2*(Remote.fees['default'].to_number())) ], + "alice" : [ "160/USD/mtgox", String(10000000000+200-2*(Remote.fees['default'].to_number())) ], "bob" : "40/USD/mtgox", }, callback); @@ -526,7 +524,7 @@ buster.testCase("Offer tests", { testutils.verify_balances(self.remote, { - "alice" : [ "100/USD/mtgox", String(10000+200+300-4*(Remote.fees['default'].to_number())) ], + "alice" : [ "100/USD/mtgox", String(10000000000+200+300-4*(Remote.fees['default'].to_number())) ], "bob" : "100/USD/mtgox", }, callback); @@ -555,7 +553,7 @@ buster.testCase("Offer cross currency", { function (callback) { self.what = "Create accounts."; - testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "mtgox"], callback); + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "carol", "mtgox"], callback); }, function (callback) { self.what = "Set limits."; @@ -637,7 +635,7 @@ buster.testCase("Offer cross currency", { function (callback) { self.what = "Create accounts."; - testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "mtgox"], callback); + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "carol", "mtgox"], callback); }, function (callback) { self.what = "Set limits."; @@ -690,7 +688,7 @@ buster.testCase("Offer cross currency", { testutils.verify_balances(self.remote, { "alice" : "475/USD/mtgox", - "bob" : "10250", + "bob" : "10000000250", "carol" : "25/USD/mtgox", }, callback); @@ -720,7 +718,7 @@ buster.testCase("Offer cross currency", { function (callback) { self.what = "Create accounts."; - testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "dan", "bitstamp", "mtgox"], callback); + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "carol", "dan", "bitstamp", "mtgox"], callback); }, function (callback) { self.what = "Set limits.";