mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'pay'
Conflicts: src/NetworkOPs.cpp
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
#ifndef __ACCOUNTSTATE__
|
||||
#define __ACCOUNTSTATE__
|
||||
|
||||
// An account's state
|
||||
//
|
||||
// Provide abstract access to an account's state, such that access to the serialized format is hidden.
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -29,6 +31,16 @@ public:
|
||||
AccountState(const NewcoinAddress& AccountID); // For new accounts
|
||||
AccountState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
|
||||
|
||||
bool bHaveAuthorizedKey()
|
||||
{
|
||||
return mLedgerEntry->getIFieldPresent(sfAuthorizedKey);
|
||||
}
|
||||
|
||||
uint160 getAuthorizedKey()
|
||||
{
|
||||
return mLedgerEntry->getIFieldH160(sfAuthorizedKey);
|
||||
}
|
||||
|
||||
const NewcoinAddress& getAccountID() const { return mAccountID; }
|
||||
STAmount getBalance() const { return mLedgerEntry->getIValueFieldAmount(sfBalance); }
|
||||
uint32 getSeq() const { return mLedgerEntry->getIFieldU32(sfSequence); }
|
||||
|
||||
@@ -30,7 +30,9 @@ DatabaseCon::~DatabaseCon()
|
||||
delete mDatabase;
|
||||
}
|
||||
|
||||
Application::Application() : mNetOps(mIOService), mUNL(mIOService),
|
||||
Application::Application() :
|
||||
mUNL(mIOService),
|
||||
mNetOps(mIOService, &mMasterLedger),
|
||||
mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef __APPLICATION__
|
||||
#define __APPLICATION__
|
||||
|
||||
#include "LedgerMaster.h"
|
||||
#include "UniqueNodeList.h"
|
||||
#include "ConnectionPool.h"
|
||||
#include "ScopedLock.h"
|
||||
#include "LedgerMaster.h"
|
||||
#include "LedgerAcquire.h"
|
||||
#include "TransactionMaster.h"
|
||||
#include "Wallet.h"
|
||||
@@ -34,12 +34,12 @@ class Application
|
||||
{
|
||||
boost::asio::io_service mIOService;
|
||||
|
||||
NetworkOPs mNetOps;
|
||||
Wallet mWallet;
|
||||
UniqueNodeList mUNL;
|
||||
LedgerMaster mMasterLedger;
|
||||
LedgerAcquireMaster mMasterLedgerAcquire;
|
||||
TransactionMaster mMasterTransaction;
|
||||
NetworkOPs mNetOps;
|
||||
|
||||
DatabaseCon* mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB;
|
||||
|
||||
|
||||
@@ -142,6 +142,21 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
|
||||
return boost::make_shared<AccountState>(sle);
|
||||
}
|
||||
|
||||
RippleState::pointer Ledger::getRippleState(const uint256& uNode)
|
||||
{
|
||||
ScopedLock l(mAccountStateMap->Lock());
|
||||
SHAMapItem::pointer item = mAccountStateMap->peekItem(uNode);
|
||||
if (!item)
|
||||
{
|
||||
return RippleState::pointer();
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::pointer sle =
|
||||
boost::make_shared<SerializedLedgerEntry>(item->peekSerializer(), item->getTag());
|
||||
if (sle->getType() != ltRIPPLE_STATE) return RippleState::pointer();
|
||||
return boost::make_shared<RippleState>(sle);
|
||||
}
|
||||
|
||||
bool Ledger::addTransaction(Transaction::pointer trans)
|
||||
{ // low-level - just add to table, debit fee
|
||||
assert(!mAccepted);
|
||||
|
||||
38
src/Ledger.h
38
src/Ledger.h
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "Transaction.h"
|
||||
#include "AccountState.h"
|
||||
#include "RippleState.h"
|
||||
#include "types.h"
|
||||
#include "BitcoinUtil.h"
|
||||
#include "SHAMap.h"
|
||||
@@ -75,7 +76,7 @@ protected:
|
||||
|
||||
static Ledger::pointer getSQL(const std::string& sqlStatement);
|
||||
|
||||
SerializedLedgerEntry::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
|
||||
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
|
||||
LedgerEntryType let);
|
||||
|
||||
public:
|
||||
@@ -131,11 +132,11 @@ public:
|
||||
|
||||
// high-level functions
|
||||
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
|
||||
LedgerStateParms writeBack(LedgerStateParms parms, SerializedLedgerEntry::pointer);
|
||||
SerializedLedgerEntry::pointer getAccountRoot(LedgerStateParms& parms, const uint160& accountID);
|
||||
SerializedLedgerEntry::pointer getAccountRoot(LedgerStateParms& parms, const NewcoinAddress& naAccountID);
|
||||
SerializedLedgerEntry::pointer getNickname(LedgerStateParms& parms, const std::string& nickname);
|
||||
SerializedLedgerEntry::pointer getNickname(LedgerStateParms& parms, const uint256& nickHash);
|
||||
LedgerStateParms writeBack(LedgerStateParms parms, SLE::pointer);
|
||||
SLE::pointer getAccountRoot(LedgerStateParms& parms, const uint160& accountID);
|
||||
SLE::pointer getAccountRoot(LedgerStateParms& parms, const NewcoinAddress& naAccountID);
|
||||
SLE::pointer getNickname(LedgerStateParms& parms, const std::string& nickname);
|
||||
SLE::pointer getNickname(LedgerStateParms& parms, const uint256& nickHash);
|
||||
|
||||
// database functions
|
||||
static void saveAcceptedLedger(Ledger::pointer);
|
||||
@@ -153,7 +154,7 @@ public:
|
||||
// Generator Map functions
|
||||
//
|
||||
|
||||
SerializedLedgerEntry::pointer getGenerator(LedgerStateParms& parms, const uint160& uGeneratorID);
|
||||
SLE::pointer getGenerator(LedgerStateParms& parms, const uint160& uGeneratorID);
|
||||
|
||||
static uint256 getGeneratorIndex(const uint160& uGeneratorID)
|
||||
{ return uint160extend256(uGeneratorID, lnsGenerator); } // Index is the generator ID extended to 256 bits in namespace 1
|
||||
@@ -169,31 +170,34 @@ public:
|
||||
static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB)
|
||||
{ return getRippleStateIndex(naA, naB, uint160()); }
|
||||
|
||||
static uint160 getOfferBase(const uint160& currencyIn, const uint160& accountIn,
|
||||
const uint160& currencyOut, const uint160& accountOut);
|
||||
RippleState::pointer getRippleState(const uint256& uNode);
|
||||
SLE::pointer getRippleState(LedgerStateParms& parms, const uint256& uNode);
|
||||
|
||||
SLE::pointer getRippleState(LedgerStateParms& parms, const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency)
|
||||
{ return getRippleState(parms, getRippleStateIndex(naA, naB, uCurrency)); }
|
||||
|
||||
SLE::pointer getRippleState(LedgerStateParms& parms, const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
|
||||
{ return getRippleState(parms, getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency)); }
|
||||
|
||||
//
|
||||
// Offer functions
|
||||
//
|
||||
|
||||
static uint160 getOfferBase(const uint160& currencyIn, const uint160& accountIn,
|
||||
const uint160& currencyOut, const uint160& accountOut);
|
||||
|
||||
static uint256 getOfferIndex(const uint160& offerBase, uint64 rate, int skip = 0);
|
||||
|
||||
static int getOfferSkip(const uint256& offerId);
|
||||
|
||||
SerializedLedgerEntry::pointer getRippleState(LedgerStateParms& parms, const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency);
|
||||
SerializedLedgerEntry::pointer getRippleState(LedgerStateParms& parms, const uint160& uiA, const uint160& uiB, const uint160& uCurrency)
|
||||
{
|
||||
return getRippleState(parms, NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency);
|
||||
}
|
||||
|
||||
//
|
||||
// Directory functions
|
||||
//
|
||||
|
||||
static uint256 getDirIndex(const uint256& uBase, const LedgerEntryType letKind, const uint64 uNodeDir=0);
|
||||
|
||||
SerializedLedgerEntry::pointer getDirRoot(LedgerStateParms& parms, const uint256& uRootIndex);
|
||||
SerializedLedgerEntry::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex);
|
||||
SLE::pointer getDirRoot(LedgerStateParms& parms, const uint256& uRootIndex);
|
||||
SLE::pointer getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex);
|
||||
|
||||
//
|
||||
// Misc
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
{
|
||||
if (mCurrentLedger && (mCurrentLedger->getLedgerSeq()==index)) return mCurrentLedger;
|
||||
if (mFinalizedLedger && (mFinalizedLedger->getLedgerSeq()==index)) return mFinalizedLedger;
|
||||
return mLedgerHistory.getLedgerBySeq(index);
|
||||
return mLedgerHistory.getLedgerBySeq(index);
|
||||
}
|
||||
|
||||
Ledger::pointer getLedgerByHash(const uint256& hash)
|
||||
|
||||
@@ -141,15 +141,13 @@ SerializedLedgerEntry::pointer Ledger::getGenerator(LedgerStateParms& parms, con
|
||||
// Ripple State
|
||||
//
|
||||
|
||||
SerializedLedgerEntry::pointer Ledger::getRippleState(LedgerStateParms& parms, const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency)
|
||||
SerializedLedgerEntry::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNode)
|
||||
{
|
||||
uint256 nodeID=getRippleStateIndex(naA, naB, uCurrency);
|
||||
|
||||
ScopedLock l(mAccountStateMap->Lock());
|
||||
|
||||
try
|
||||
{
|
||||
return getASNode(parms, nodeID, ltRIPPLE_STATE);
|
||||
return getASNode(parms, uNode, ltRIPPLE_STATE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
// code assumes this node is synched (and will continue to do so until
|
||||
// there's a functional network.
|
||||
|
||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service) : mMode(omDISCONNECTED), mNetTimer(io_service)
|
||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
||||
mMode(omDISCONNECTED),
|
||||
mNetTimer(io_service),
|
||||
mLedgerMaster(pLedgerMaster)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,7 +40,7 @@ uint64 NetworkOPs::getNetworkTimeNC()
|
||||
|
||||
uint32 NetworkOPs::getCurrentLedgerID()
|
||||
{
|
||||
return theApp->getMasterLedger().getCurrentLedger()->getLedgerSeq();
|
||||
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();
|
||||
}
|
||||
|
||||
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
|
||||
@@ -54,7 +57,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
return trans;
|
||||
}
|
||||
|
||||
TransactionEngineResult r = theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
|
||||
TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tepNONE);
|
||||
if (r == tenFAILED) throw Fault(IO_ERROR);
|
||||
|
||||
if (r == terPRE_SEQ)
|
||||
@@ -64,7 +67,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
#endif
|
||||
trans->setStatus(HELD);
|
||||
theApp->getMasterTransaction().canonicalize(trans, true);
|
||||
theApp->getMasterLedger().addHeldTransaction(trans);
|
||||
mLedgerMaster->addHeldTransaction(trans);
|
||||
return trans;
|
||||
}
|
||||
if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
|
||||
@@ -116,10 +119,10 @@ Transaction::pointer NetworkOPs::findTransactionByID(const uint256& transactionI
|
||||
return Transaction::load(transactionID);
|
||||
}
|
||||
|
||||
int NetworkOPs::findTransactionsBySource(std::list<Transaction::pointer>& txns,
|
||||
int NetworkOPs::findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>& txns,
|
||||
const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
|
||||
{
|
||||
AccountState::pointer state = getAccountState(sourceAccount);
|
||||
AccountState::pointer state = getAccountState(uLedger, sourceAccount);
|
||||
if (!state) return 0;
|
||||
if (minSeq > state->getSeq()) return 0;
|
||||
if (maxSeq > state->getSeq()) maxSeq = state->getSeq();
|
||||
@@ -145,14 +148,76 @@ int NetworkOPs::findTransactionsByDestination(std::list<Transaction::pointer>& t
|
||||
return 0;
|
||||
}
|
||||
|
||||
AccountState::pointer NetworkOPs::getAccountState(const NewcoinAddress& accountID)
|
||||
//
|
||||
// Account functions
|
||||
//
|
||||
|
||||
AccountState::pointer NetworkOPs::getAccountState(const uint256& uLedger, const NewcoinAddress& accountID)
|
||||
{
|
||||
return theApp->getMasterLedger().getCurrentLedger()->getAccountState(accountID);
|
||||
return mLedgerMaster->getLedgerByHash(uLedger)->getAccountState(accountID);
|
||||
}
|
||||
|
||||
SLE::pointer NetworkOPs::getGenerator(const uint256& uLedger, const uint160& uGeneratorID)
|
||||
{
|
||||
LedgerStateParms qry = lepNONE;
|
||||
|
||||
return mLedgerMaster->getLedgerByHash(uLedger)->getGenerator(qry, uGeneratorID);
|
||||
}
|
||||
|
||||
//
|
||||
// Directory functions
|
||||
//
|
||||
|
||||
// <-- false : no entrieS
|
||||
bool NetworkOPs::getDirInfo(
|
||||
const uint256& uLedger,
|
||||
const uint256& uBase,
|
||||
const LedgerEntryType letKind,
|
||||
uint256& uDirLineNodeFirst,
|
||||
uint256& uDirLineNodeLast)
|
||||
{
|
||||
uint256 uRootIndex = Ledger::getDirIndex(uBase, letKind);
|
||||
LedgerStateParms lspRoot = lepNONE;
|
||||
SLE::pointer sleRoot = mLedgerMaster->getLedgerByHash(uLedger)->getDirRoot(lspRoot, uRootIndex);
|
||||
|
||||
if (sleRoot)
|
||||
{
|
||||
uDirLineNodeFirst = uRootIndex | sleRoot->getIFieldU64(sfFirstNode);
|
||||
uDirLineNodeLast = uRootIndex | sleRoot->getIFieldU64(sfLastNode);
|
||||
}
|
||||
|
||||
return !!sleRoot;
|
||||
}
|
||||
|
||||
STVector256 NetworkOPs::getDirNode(const uint256& uLedger, const uint256& uDirLineNode)
|
||||
{
|
||||
STVector256 svIndexes;
|
||||
|
||||
LedgerStateParms lspNode = lepNONE;
|
||||
SLE::pointer sleNode = mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uDirLineNode);
|
||||
|
||||
if (sleNode)
|
||||
svIndexes = sleNode->getIFieldV256(sfIndexes);
|
||||
|
||||
return svIndexes;
|
||||
}
|
||||
|
||||
//
|
||||
// Ripple functions
|
||||
//
|
||||
|
||||
RippleState::pointer NetworkOPs::getRippleState(const uint256& uLedger, const uint256& uIndex)
|
||||
{
|
||||
return mLedgerMaster->getLedgerByHash(uLedger)->getRippleState(uIndex);
|
||||
}
|
||||
|
||||
//
|
||||
// Other
|
||||
//
|
||||
|
||||
void NetworkOPs::setStateTimer(int sec)
|
||||
{ // set timer early if ledger is closing
|
||||
uint64 consensusTime = theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
|
||||
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
|
||||
uint64 now = getNetworkTimeNC();
|
||||
|
||||
if ((mMode == omFULL) && !mConsensus)
|
||||
@@ -235,7 +300,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
}
|
||||
}
|
||||
|
||||
Ledger::pointer currentClosed = theApp->getMasterLedger().getClosedLedger();
|
||||
Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger();
|
||||
uint256 closedLedger = currentClosed->getHash();
|
||||
ValidationCount& vc = ledgers[closedLedger];
|
||||
if ((vc.nodesUsing == 0) || (theApp->getWallet().getNodePublic() > vc.highNode))
|
||||
@@ -264,7 +329,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
std::cerr << "Net LCL " << closedLedger.GetHex() << std::endl;
|
||||
#endif
|
||||
if ((mMode == omTRACKING) || (mMode == omFULL)) mMode = omTRACKING;
|
||||
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(closedLedger);
|
||||
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
|
||||
if (!consensus)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -334,7 +399,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
|
||||
newLedger->setClosed();
|
||||
Ledger::pointer openLedger = boost::make_shared<Ledger>(newLedger);
|
||||
theApp->getMasterLedger().switchLedgers(newLedger, openLedger);
|
||||
mLedgerMaster->switchLedgers(newLedger, openLedger);
|
||||
|
||||
if (getNetworkTimeNC() > openLedger->getCloseTimeNC())
|
||||
{ // this ledger has already closed
|
||||
@@ -348,7 +413,7 @@ int NetworkOPs::beginConsensus(Ledger::pointer closingLedger)
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Ledger close time for ledger " << closingLedger->getLedgerSeq() << std::endl;
|
||||
#endif
|
||||
Ledger::pointer prevLedger = theApp->getMasterLedger().getLedgerByHash(closingLedger->getParentHash());
|
||||
Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash());
|
||||
if (!prevLedger)
|
||||
{ // this shouldn't happen if we jump ledgers
|
||||
mMode = omTRACKING;
|
||||
@@ -384,6 +449,7 @@ bool NetworkOPs::recvPropose(const uint256& prevLgr, uint32 proposeSeq, const ui
|
||||
// WRITEME
|
||||
|
||||
if (!mConsensus) return false;
|
||||
|
||||
return mConsensus->peerPosition(proposal);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef __NETWORK_OPS__
|
||||
#define __NETWORK_OPS__
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "Transaction.h"
|
||||
#include "LedgerMaster.h"
|
||||
#include "AccountState.h"
|
||||
#include "Ledger.h"
|
||||
#include "RippleState.h"
|
||||
|
||||
// #include <boost/asio.hpp>
|
||||
|
||||
// Operations that clients may wish to perform against the network
|
||||
// Master operational handler, server sequencer, network tracker
|
||||
@@ -35,8 +35,10 @@ protected:
|
||||
boost::asio::deadline_timer mNetTimer;
|
||||
boost::shared_ptr<LedgerConsensus> mConsensus;
|
||||
|
||||
LedgerMaster* mLedgerMaster;
|
||||
|
||||
public:
|
||||
NetworkOPs(boost::asio::io_service& io_service);
|
||||
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
|
||||
|
||||
// network information
|
||||
uint64 getNetworkTimeNC();
|
||||
@@ -44,25 +46,45 @@ public:
|
||||
uint32 getCurrentLedgerID();
|
||||
OperatingMode getOperatingMode() { return mMode; }
|
||||
inline bool available() {
|
||||
// XXX don't consider network available till have a closed ledger.
|
||||
return omDISCONNECTED != mMode;
|
||||
}
|
||||
|
||||
uint256 getClosedLedger()
|
||||
{ return mLedgerMaster->getClosedLedger()->getHash(); }
|
||||
|
||||
// transaction operations
|
||||
Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL);
|
||||
Transaction::pointer findTransactionByID(const uint256& transactionID);
|
||||
int findTransactionsBySource(std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
|
||||
int findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
|
||||
uint32 minSeq, uint32 maxSeq);
|
||||
int findTransactionsByDestination(std::list<Transaction::pointer>&, const NewcoinAddress& destinationAccount,
|
||||
uint32 startLedgerSeq, uint32 endLedgerSeq, int maxTransactions);
|
||||
|
||||
// account operations
|
||||
AccountState::pointer getAccountState(const NewcoinAddress& accountID);
|
||||
//
|
||||
// Account functions
|
||||
//
|
||||
|
||||
AccountState::pointer getAccountState(const uint256& uLedger, const NewcoinAddress& accountID);
|
||||
SLE::pointer getGenerator(const uint256& uLedger, const uint160& uGeneratorID);
|
||||
|
||||
//
|
||||
// Directory functions
|
||||
//
|
||||
|
||||
bool getDirInfo(const uint256& uLedger, const uint256& uBase,
|
||||
const LedgerEntryType letKind,
|
||||
uint256& uDirNodeFirst, uint256& uDirNodeLast);
|
||||
STVector256 getDirNode(const uint256& uLedger, const uint256& uDirLineNode);
|
||||
|
||||
//
|
||||
// Ripple functions
|
||||
//
|
||||
bool getDirLineInfo(const NewcoinAddress& naAccount, uint64& uDirLineNodeFirst, uint64& uDirLineNodeLast) { return false; }
|
||||
std::vector<uint256> getDirLineNode(const uint64 uDirLineNode) { std::vector<uint256> empty; return empty; }
|
||||
|
||||
bool getDirLineInfo(const uint256& uLedger, const NewcoinAddress& naAccount, uint256& uDirLineNodeFirst, uint256& uDirLineNodeLast)
|
||||
{ return getDirInfo(uLedger, uint160extend256(naAccount.getAccountID(), 0), ltRIPPLE_STATE, uDirLineNodeFirst, uDirLineNodeLast); }
|
||||
|
||||
RippleState::pointer getRippleState(const uint256& uLedger, const uint256& uIndex);
|
||||
|
||||
// raw object operations
|
||||
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "PackedMessage.h"
|
||||
#include "Ledger.h"
|
||||
#include "Transaction.h"
|
||||
#include "NetworkOPs.h"
|
||||
|
||||
enum PeerPunish
|
||||
{
|
||||
|
||||
@@ -171,20 +171,18 @@ bool RPCServer::extractString(std::string& param, const Json::Value& params, int
|
||||
}
|
||||
|
||||
// Given a seed and a source account get the public and private key for authorizing transactions for the account.
|
||||
Json::Value RPCServer::authorize(const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID,
|
||||
Json::Value RPCServer::authorize(const uint256& uLedger,
|
||||
const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID,
|
||||
NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate,
|
||||
SLE::pointer& sleSrc)
|
||||
AccountState::pointer& asSrc)
|
||||
{
|
||||
Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger();
|
||||
LedgerStateParms qry = lepNONE;
|
||||
|
||||
sleSrc = ledger->getAccountRoot(qry, naSrcAccountID);
|
||||
if (!sleSrc)
|
||||
asSrc = mNetOps->getAccountState(uLedger, naSrcAccountID);
|
||||
if (!asSrc)
|
||||
{
|
||||
return JSONRPCError(500, "source account does not exist");
|
||||
}
|
||||
|
||||
if (!sleSrc->getIFieldPresent(sfAuthorizedKey))
|
||||
if (!asSrc->bHaveAuthorizedKey())
|
||||
{
|
||||
return JSONRPCError(500, "source account has not been claimed");
|
||||
}
|
||||
@@ -197,8 +195,7 @@ Json::Value RPCServer::authorize(const NewcoinAddress& naSeed, const NewcoinAddr
|
||||
na0Public.setAccountPublic(naGenerator, 0);
|
||||
na0Private.setAccountPrivate(naGenerator, naSeed, 0);
|
||||
|
||||
qry = lepNONE;
|
||||
SLE::pointer sleGen = ledger->getGenerator(qry, na0Public.getAccountID());
|
||||
SLE::pointer sleGen = mNetOps->getGenerator(uLedger, na0Public.getAccountID());
|
||||
|
||||
if (!sleGen)
|
||||
{
|
||||
@@ -234,10 +231,10 @@ Json::Value RPCServer::authorize(const NewcoinAddress& naSeed, const NewcoinAddr
|
||||
naAccountPublic.setAccountPublic(naGenerator, iIndex);
|
||||
naAccountPrivate.setAccountPrivate(naGenerator, naSeed, iIndex);
|
||||
|
||||
if (sleSrc->getIFieldH160(sfAuthorizedKey) != naAccountPublic.getAccountID())
|
||||
if (asSrc->getAuthorizedKey() != naAccountPublic.getAccountID())
|
||||
{
|
||||
std::cerr << "iIndex: " << iIndex << std::endl;
|
||||
std::cerr << "sfAuthorizedKey: " << strHex(sleSrc->getIFieldH160(sfAuthorizedKey)) << std::endl;
|
||||
std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey()) << std::endl;
|
||||
std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl;
|
||||
|
||||
return JSONRPCError(500, "wrong password (changed)");
|
||||
@@ -247,7 +244,7 @@ Json::Value RPCServer::authorize(const NewcoinAddress& naSeed, const NewcoinAddr
|
||||
}
|
||||
|
||||
// <-- bIndex: true if iIndex > 0 and used the index.
|
||||
Json::Value RPCServer::accountFromString(NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex)
|
||||
Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex)
|
||||
{
|
||||
NewcoinAddress naSeed;
|
||||
|
||||
@@ -275,10 +272,7 @@ Json::Value RPCServer::accountFromString(NewcoinAddress& naAccount, bool& bIndex
|
||||
naRegular0Private.setAccountPrivate(naGenerator, naSeed, 0);
|
||||
|
||||
uint160 uGeneratorID = naRegular0Public.getAccountID();
|
||||
|
||||
Ledger::pointer ledger = theApp->getMasterLedger().getCurrentLedger();
|
||||
LedgerStateParms qry = lepNONE;
|
||||
SLE::pointer sleGen = ledger->getGenerator(qry, naRegular0Public.getAccountID());
|
||||
SLE::pointer sleGen = mNetOps->getGenerator(uLedger, naRegular0Public.getAccountID());
|
||||
if (!sleGen)
|
||||
{
|
||||
// Didn't find a generator map, assume it is a master generator.
|
||||
@@ -325,7 +319,9 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms)
|
||||
|
||||
Json::Value ret;
|
||||
|
||||
ret = accountFromString(naAccount, bIndex, strIdent, iIndex);
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
|
||||
ret = accountFromString(uLedger, naAccount, bIndex, strIdent, iIndex);
|
||||
|
||||
if (!ret.empty())
|
||||
return ret;
|
||||
@@ -333,7 +329,7 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms)
|
||||
// Get info on account.
|
||||
ret = Json::Value(Json::objectValue);
|
||||
|
||||
AccountState::pointer as=mNetOps->getAccountState(naAccount);
|
||||
AccountState::pointer as = mNetOps->getAccountState(uLedger, naAccount);
|
||||
if (as)
|
||||
{
|
||||
as->addJson(ret);
|
||||
@@ -365,11 +361,14 @@ Json::Value RPCServer::doAccountLines(Json::Value ¶ms)
|
||||
std::string strIdent = params[0u].asString();
|
||||
bool bIndex;
|
||||
int iIndex = 2 == params.size()? boost::lexical_cast<int>(params[1u].asString()) : 0;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
|
||||
NewcoinAddress naAccount;
|
||||
|
||||
Json::Value ret;
|
||||
|
||||
ret = accountFromString(naAccount, bIndex, strIdent, iIndex);
|
||||
// This needs to use a ledger.
|
||||
ret = accountFromString(uLedger, naAccount, bIndex, strIdent, iIndex);
|
||||
|
||||
if (!ret.empty())
|
||||
return ret;
|
||||
@@ -383,47 +382,48 @@ Json::Value RPCServer::doAccountLines(Json::Value ¶ms)
|
||||
if (bIndex)
|
||||
ret["index"] = iIndex;
|
||||
|
||||
AccountState::pointer as = mNetOps->getAccountState(naAccount);
|
||||
AccountState::pointer as = mNetOps->getAccountState(uLedger, naAccount);
|
||||
if (as)
|
||||
{
|
||||
ret["account"] = naAccount.humanAccountID();
|
||||
|
||||
// We access a committed ledger and need not worry about changes.
|
||||
uint64 uDirLineNodeFirst;
|
||||
uint64 uDirLineNodeLast;
|
||||
// XXX We need to get the ID of the commited ledger for a conistent view.
|
||||
uint256 uDirLineNodeFirst;
|
||||
uint256 uDirLineNodeLast;
|
||||
|
||||
if (!mNetOps->getDirLineInfo(naAccount, uDirLineNodeFirst, uDirLineNodeLast))
|
||||
if (!mNetOps->getDirLineInfo(uLedger, naAccount, uDirLineNodeFirst, uDirLineNodeLast))
|
||||
{
|
||||
ret["lines"] = Json::Value(Json::objectValue);
|
||||
}
|
||||
else if (uDirLineNodeFirst)
|
||||
else
|
||||
{
|
||||
Json::Value jsonLines = Json::Value(Json::objectValue);
|
||||
|
||||
for (; uDirLineNodeFirst <= uDirLineNodeLast; uDirLineNodeFirst++)
|
||||
{
|
||||
std::vector<uint256> vuRippleNodes = mNetOps->getDirLineNode(uDirLineNodeFirst);
|
||||
STVector256 svRippleNodes = mNetOps->getDirNode(uLedger, uDirLineNodeFirst);
|
||||
|
||||
BOOST_FOREACH(uint256& uNode, vuRippleNodes)
|
||||
BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue())
|
||||
{
|
||||
NewcoinAddress naAccountPeer;
|
||||
uint64 uBalance = 0;
|
||||
// uint160 uCurrency;
|
||||
STAmount saBalance;
|
||||
STAmount saLimit;
|
||||
STAmount saLimitPeer;
|
||||
#if 0
|
||||
RippleState::pointer rsLine = mNetOps->getRippleState(uNode);
|
||||
|
||||
RippleState::pointer rsLine = mNetOps->getRippleState(uLedger, uNode);
|
||||
|
||||
rsLine->setViewAccount(naAccount);
|
||||
rsLine->getAccountPeer(naAccountPeer);
|
||||
// ->getBalance(iBalance);
|
||||
// ->getCurrency(uCurrency);
|
||||
rsLine->getLimit(saLimit)
|
||||
rsLine->getLimitPeer(saPeerLimit);
|
||||
#endif
|
||||
|
||||
naAccountPeer = rsLine->getAccountIDPeer();
|
||||
saBalance = rsLine->getBalance();
|
||||
saLimit = rsLine->getLimit();
|
||||
saLimitPeer = rsLine->getLimitPeer();
|
||||
|
||||
Json::Value jPeer = Json::Value(Json::objectValue);
|
||||
|
||||
jPeer["balance"] = Json::Value::UInt(uBalance); // XXX Raw number.
|
||||
jPeer["balance"] = saBalance.getText();
|
||||
jPeer["currency"] = saBalance.getCurrencyHuman();
|
||||
jPeer["limit"] = saLimit.getJson(0);
|
||||
jPeer["limit_peer"] = saLimitPeer.getJson(0);
|
||||
|
||||
@@ -514,15 +514,16 @@ Json::Value RPCServer::doCreditSet(Json::Value& params)
|
||||
}
|
||||
else
|
||||
{
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
SLE::pointer sleSrc;
|
||||
Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc);
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
AccountState::pointer asSrc;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc);
|
||||
|
||||
if (!obj.empty())
|
||||
return obj;
|
||||
|
||||
STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance);
|
||||
STAmount saSrcBalance = asSrc->getBalance();
|
||||
|
||||
if (saSrcBalance < theConfig.FEE_DEFAULT)
|
||||
{
|
||||
@@ -533,7 +534,7 @@ Json::Value RPCServer::doCreditSet(Json::Value& params)
|
||||
Transaction::pointer trans = Transaction::sharedCreditSet(
|
||||
naAccountPublic, naAccountPrivate,
|
||||
naSrcAccountID,
|
||||
sleSrc->getIFieldU32(sfSequence),
|
||||
asSrc->getSeq(),
|
||||
theConfig.FEE_DEFAULT,
|
||||
0, // YYY No source tag
|
||||
naDstAccountID,
|
||||
@@ -601,10 +602,11 @@ Json::Value RPCServer::doSend(Json::Value& params)
|
||||
}
|
||||
else
|
||||
{
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
SLE::pointer sleSrc;
|
||||
Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc);
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
AccountState::pointer asSrc;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc);
|
||||
|
||||
if (!obj.empty())
|
||||
{
|
||||
@@ -616,7 +618,7 @@ Json::Value RPCServer::doSend(Json::Value& params)
|
||||
|
||||
// XXX Confirm saSrcAmount >= saDstAmount.
|
||||
|
||||
STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance);
|
||||
STAmount saSrcBalance = asSrc->getBalance();
|
||||
|
||||
if (saSrcBalance < theConfig.FEE_DEFAULT)
|
||||
{
|
||||
@@ -628,7 +630,7 @@ Json::Value RPCServer::doSend(Json::Value& params)
|
||||
Transaction::pointer trans = Transaction::sharedPayment(
|
||||
naAccountPublic, naAccountPrivate,
|
||||
naSrcAccountID,
|
||||
sleSrc->getIFieldU32(sfSequence),
|
||||
asSrc->getSeq(),
|
||||
theConfig.FEE_DEFAULT,
|
||||
0, // YYY No source tag
|
||||
naDstAccountID,
|
||||
@@ -691,17 +693,18 @@ Json::Value RPCServer::doTransitSet(Json::Value& params)
|
||||
}
|
||||
else
|
||||
{
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
SLE::pointer sleSrc;
|
||||
Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc);
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
AccountState::pointer asSrc;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc);
|
||||
|
||||
if (!obj.empty())
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance);
|
||||
STAmount saSrcBalance = asSrc->getBalance();
|
||||
|
||||
uTransitRate = 0;
|
||||
uTransitStart = 0;
|
||||
@@ -716,7 +719,7 @@ Json::Value RPCServer::doTransitSet(Json::Value& params)
|
||||
Transaction::pointer trans = Transaction::sharedTransitSet(
|
||||
naAccountPublic, naAccountPrivate,
|
||||
naSrcAccountID,
|
||||
sleSrc->getIFieldU32(sfSequence),
|
||||
asSrc->getSeq(),
|
||||
theConfig.FEE_DEFAULT,
|
||||
0, // YYY No source tag
|
||||
uTransitRate,
|
||||
@@ -980,6 +983,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
|
||||
NewcoinAddress naSrcAccountID;
|
||||
NewcoinAddress naDstAccountID;
|
||||
NewcoinAddress naSeed;
|
||||
uint256 uLedger;
|
||||
|
||||
if (params.size() < 3 || params.size() > 4)
|
||||
{
|
||||
@@ -1001,7 +1005,11 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
|
||||
// We require access to the paying account's sequence number and key information.
|
||||
return JSONRPCError(503, "network not available");
|
||||
}
|
||||
else if (mNetOps->getAccountState(naDstAccountID))
|
||||
else if ((uLedger = mNetOps->getClosedLedger()).isZero())
|
||||
{
|
||||
return JSONRPCError(503, "no closed ledger");
|
||||
}
|
||||
else if (mNetOps->getAccountState(uLedger, naDstAccountID))
|
||||
{
|
||||
return "account already exists";
|
||||
}
|
||||
@@ -1010,13 +1018,14 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
|
||||
// Trying to build:
|
||||
// peer_wallet_create <paying_account> <paying_signature> <account_id> [<initial_funds>] [<annotation>]
|
||||
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
SLE::pointer sleSrc;
|
||||
Json::Value obj = authorize(naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, sleSrc);
|
||||
NewcoinAddress naAccountPublic;
|
||||
NewcoinAddress naAccountPrivate;
|
||||
AccountState::pointer asSrc;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, asSrc);
|
||||
|
||||
STAmount saSrcBalance = sleSrc->getIValueFieldAmount(sfBalance);
|
||||
STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast<uint64>(params[3u].asString());
|
||||
STAmount saSrcBalance = asSrc->getBalance();
|
||||
STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast<uint64>(params[3u].asString());
|
||||
|
||||
if (!obj.empty())
|
||||
{
|
||||
@@ -1031,7 +1040,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params)
|
||||
Transaction::pointer trans = Transaction::sharedCreate(
|
||||
naAccountPublic, naAccountPrivate,
|
||||
naSrcAccountID,
|
||||
sleSrc->getIFieldU32(sfSequence),
|
||||
asSrc->getSeq(),
|
||||
theConfig.FEE_CREATE,
|
||||
0, // YYY No source tag
|
||||
naDstAccountID,
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include "HttpRequest.h"
|
||||
#include "RequestParser.h"
|
||||
#include "NewcoinAddress.h"
|
||||
#include "SerializedLedger.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "SerializedLedger.h"
|
||||
|
||||
class RPCServer : public boost::enable_shared_from_this<RPCServer>
|
||||
{
|
||||
@@ -39,11 +39,11 @@ private:
|
||||
int getParamCount(const Json::Value& params);
|
||||
bool extractString(std::string& param, const Json::Value& params, int index);
|
||||
|
||||
Json::Value authorize(const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID,
|
||||
Json::Value authorize(const uint256& uLedger, const NewcoinAddress& naSeed, const NewcoinAddress& naSrcAccountID,
|
||||
NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate,
|
||||
SerializedLedgerEntry::pointer& sleSrc);
|
||||
AccountState::pointer& asSrc);
|
||||
|
||||
Json::Value accountFromString(NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex);
|
||||
Json::Value accountFromString(const uint256& uLedger, NewcoinAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex);
|
||||
|
||||
Json::Value doAccountInfo(Json::Value& params);
|
||||
Json::Value doAccountLines(Json::Value ¶ms);
|
||||
|
||||
32
src/RippleState.cpp
Normal file
32
src/RippleState.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "RippleState.h"
|
||||
|
||||
RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) :
|
||||
mLedgerEntry(ledgerEntry),
|
||||
mValid(false),
|
||||
mViewLowest(true)
|
||||
{
|
||||
if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return;
|
||||
|
||||
mLowID = mLedgerEntry->getIValueFieldAccount(sfLowID);
|
||||
mHighID = mLedgerEntry->getIValueFieldAccount(sfHighID);
|
||||
|
||||
mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit);
|
||||
mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit);
|
||||
|
||||
// YYY Should never fail.
|
||||
if (mLowID.isValid() && mHighID.isValid())
|
||||
mValid = true;
|
||||
}
|
||||
|
||||
void RippleState::setViewAccount(const NewcoinAddress& naView)
|
||||
{
|
||||
bool bViewLowestNew = mLowID.getAccountID() == naView.getAccountID();
|
||||
|
||||
if (bViewLowestNew != mViewLowest)
|
||||
{
|
||||
mViewLowest = bViewLowestNew;
|
||||
mBalance.changeSign();
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
51
src/RippleState.h
Normal file
51
src/RippleState.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef __RIPPLESTATE__
|
||||
#define __RIPPLESTATE__
|
||||
|
||||
//
|
||||
// A ripple line's state.
|
||||
//
|
||||
|
||||
#include "SerializedLedger.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class RippleState
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<RippleState> pointer;
|
||||
|
||||
private:
|
||||
SerializedLedgerEntry::pointer mLedgerEntry;
|
||||
|
||||
NewcoinAddress mLowID;
|
||||
NewcoinAddress mHighID;
|
||||
|
||||
STAmount mLowLimit;
|
||||
STAmount mHighLimit;
|
||||
|
||||
STAmount mBalance;
|
||||
|
||||
bool mValid;
|
||||
bool mViewLowest;
|
||||
|
||||
public:
|
||||
RippleState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
|
||||
|
||||
void setViewAccount(const NewcoinAddress& naView);
|
||||
|
||||
const NewcoinAddress getAccountID() const { return mViewLowest ? mLowID : mHighID; }
|
||||
const NewcoinAddress getAccountIDPeer() const { return mViewLowest ? mHighID : mLowID; }
|
||||
|
||||
STAmount getBalance() const { return mBalance; }
|
||||
|
||||
STAmount getLimit() const { return mViewLowest ? mLowLimit : mHighLimit; }
|
||||
STAmount getLimitPeer() const { return mViewLowest ? mHighLimit : mLowLimit; }
|
||||
|
||||
SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; }
|
||||
const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; }
|
||||
SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; }
|
||||
|
||||
std::vector<unsigned char> getRaw() const;
|
||||
};
|
||||
#endif
|
||||
// vim:ts=4
|
||||
Reference in New Issue
Block a user