/****************************************************************************** * Copyright © 2013-2016 The Nxt Core Developers. * * * * See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * Nxt software, including this file, may be copied, modified, propagated, * * or distributed except according to the terms contained in the LICENSE.txt * * file. * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ package nxt.http; import nxt.AccountLedger; import nxt.AccountLedger.LedgerEntry; import nxt.AccountLedger.LedgerEvent; import nxt.AccountLedger.LedgerHolding; import nxt.NxtException; import nxt.util.Convert; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONStreamAware; import javax.servlet.http.HttpServletRequest; import java.util.List; /** * <p> * The GetAccountLedger API will return entries from the account ledger. The * account ledger tracks all account changes as determined by the nxt.ledgerAccounts, * nxt.ledgerLogUnconfirmed and nxt.ledgerTrimKeep properties. * </p> * <table> * <caption><b>Request parameters</b></caption> * <thead> * <tr> * <th>Name</th> * <th>Description</th> * </tr> * </thead> * <tbody> * <tr> * <td>account</td> * <td>Account identifier or Reed-Solomon identifier * This is an optional parameter and restricts the search to entries matching the account identifier. * </td> * </tr> * <tr> * <td>adminPassword</td> * <td>Administrator password. * The administrator password is required if more than nxt.maxAPIRecords entries are to be searched. * </td> * </tr> * <tr> * <td>event</td> * <td>Event identifier. * The event identifier is ignored unless 'eventType' is also specified. * This is an optional parameter and restricts the search to entries matching both 'eventType' * and 'event'. Note that the asset identifier, currency identifier or digital goods identifier * is the same as the transaction identifier of the creating transaction. * </td> * </tr> * <tr> * <td>eventType</td> * <td>Event type. * This is an optional parameter and restricts the search to entries matching 'eventType'. * </td> * </tr> * <tr> * <td>holding</td> * <td>Holding identifier. * The holding identifier is ignored unless 'holdingType' is also specified. * This is an optional parameter and restricts the search to entries matching both 'holdingType' * and 'holding'. * </td> * </tr> * <tr> * <td>holdingType</td> * <td>Holding type. * This is an optional parameter and restricts the search to entries matching 'holdingType'. * </td> * </tr> * <tr> * <td>includeTransactions</td> * <td>Specify TRUE to include the transaction associated with a ledger entry. The default is FALSE.</td> * </tr> * <tr> * <td>firstIndex</td> * <td>The first ledger entry to search. The default is 0 if 'firstIndex' is not specified. * If an account identifier is specified, the index refers to entries for the specified account and * index 0 is the latest entry for the account. * Otherwise, the index refers to the entry block height and index 0 is the latest block. * </td> * </tr> * <tr> * <td>lastIndex</td> * <td>The last ledger entry to search. The default is the earliest ledger entry if 'lastIndex' * is not specified. * The maximum number of entries searched is determined by the nxt.maxAPIRecords property * unless the administrator password is specified. * </td> * </tr> * </tbody> * </table> * <br> * <table> * <caption><b>Ledger entry fields</b></caption> * <thead> * <tr> * <th>Name</th> * <th>Description</th> * </tr> * </thead> * <tbody> * <tr> * <td>account</td> * <td>Account identifier.</td> * </tr> * <tr> * <td>accountRS</td> * <td>Account Reed-Solomon identifier.</td> * </tr> * <tr> * <td>balance</td> * <td>Update balance for the holding identified by 'holdingType'.</td> * </tr> * <tr> * <td>block</td> * <td>Block that created the ledger entry. The current ledger entry will be removed if the block is * removed from the blockchain. A new ledger entry will be created when either the block is * added to the blockchain again or the transaction is included in a different block.</td> * </tr> * <tr> * <td>change</td> * <td>Change in the balance for the holding identified by 'holdingType'.</td> * </tr> * <tr> * <td>event</td> * <td>The block or transaction associated with the event.</td> * </tr> * <tr> * <td>eventType</td> * <td>Event causing the account change.</td> * </tr> * <tr> * <td>height</td> * <td>The block height associated with the event.</td> * </tr> * <tr> * <td>holding</td> * <td>The item identifier for an asset or currency balance.</td> * </tr> * <tr> * <td>holdingType</td> * <td>The item being changed (account balance, asset balance or currency balance).</td> * </tr> * <tr> * <td>isTransactionEvent</td> * <td>TRUE if the event is associated with a transaction and FALSE if it is associated with a block.</td> * </tr> * <tr> * <td>ledgerId</td> * <td>The ledger entry identifier. This is a counter that is incremented each time * a new entry is added to the account ledger. The ledger entry identifier is unique * to the peer returning the ledger entry and will be different for each peer in the * network. A new ledger entry identifier will be assigned if a ledger entry is removed * and then added again. * </td> * </tr> * <tr> * <td>timestamp</td> * <td>The block timestamp associated with the event.</td> * </tr> * <tr> * <td>transaction</td> * <td>Transaction associated with the event if 'includeTransactions' is TRUE.</td> * </tr> * </tbody> * </table> * <br> * <table> * <caption><b>Values returned for 'holdingType'</b></caption> * <thead> * <tr> * <th>Name</th> * <th>Description</th> * </tr> * </thead> * <tbody> * <tr> * <td>ASSET_BALANCE</td> * <td>Change in the asset balance. The asset identifier is the 'holding'.</td> * </tr> * <tr> * <td>CURRENCY_BALANCE</td> * <td>Change in the currency balance. The currency identifier is the 'holding'.</td> * </tr> * <tr> * <td>NXT_BALANCE</td> * <td>Change in the NXT balance for the account. There is no 'holding'.</td> * </tr> * <tr> * <td>UNCONFIRMED_ASSET_BALANCE</td> * <td>Change in the unconfirmed asset balance. The asset identifier is the 'holding'.</td> * </tr> * <tr> * <td>UNCONFIRMED_CURRENCY_BALANCE</td> * <td>Change in the unconfirmed currency balance. The currency identifier is the 'holding'.</td> * </tr> * <tr> * <td>UNCONFIRMED_NXT_BALANCE</td> * <td>Change in the unconfirmed NXT balance for the account. There is no 'holding'.</td> * </tr> * </tbody> * </table> */ public class GetAccountLedger extends APIServlet.APIRequestHandler { /** GetAccountLedger instance */ static final GetAccountLedger instance = new GetAccountLedger(); /** * Create the GetAccountLedger instance */ private GetAccountLedger() { super(new APITag[] {APITag.ACCOUNTS}, "account", "firstIndex", "lastIndex", "eventType", "event", "holdingType", "holding", "includeTransactions"); } /** * Process the GetAccountLedger API request * * @param req API request * @return API response * @throws NxtException Invalid request */ @Override JSONStreamAware processRequest(HttpServletRequest req) throws NxtException { // // Process the request parameters // long accountId = ParameterParser.getAccountId(req, "account", false); int firstIndex = ParameterParser.getFirstIndex(req); int lastIndex = ParameterParser.getLastIndex(req); String eventType = Convert.emptyToNull(req.getParameter("eventType")); LedgerEvent event = null; long eventId = 0; if (eventType != null) { try { event = LedgerEvent.valueOf(eventType); eventId = ParameterParser.getUnsignedLong(req, "event", false); } catch (RuntimeException e) { throw new ParameterException(JSONResponses.incorrect("eventType")); } } String holdingType = Convert.emptyToNull(req.getParameter("holdingType")); LedgerHolding holding = null; long holdingId = 0; if (holdingType != null) { try { holding = LedgerHolding.valueOf(holdingType); holdingId = ParameterParser.getUnsignedLong(req, "holding", false); } catch (RuntimeException e) { throw new ParameterException(JSONResponses.incorrect("holdingType")); } } boolean includeTransactions = "true".equalsIgnoreCase(req.getParameter("includeTransactions")); // // Get the ledger entries // List<LedgerEntry> ledgerEntries = AccountLedger.getEntries(accountId, event, eventId, holding, holdingId, firstIndex, lastIndex); // // Return the response // JSONArray responseEntries = new JSONArray(); ledgerEntries.forEach((entry) -> { JSONObject responseEntry = new JSONObject(); JSONData.ledgerEntry(responseEntry, entry, includeTransactions); responseEntries.add(responseEntry); }); JSONObject response = new JSONObject(); response.put("entries", responseEntries); return response; } }