/****************************************************************************** * 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.Account; import nxt.AccountLedger.LedgerEntry; import nxt.AccountRestrictions; import nxt.Alias; import nxt.Appendix; import nxt.Asset; import nxt.AssetDelete; import nxt.AssetTransfer; import nxt.Attachment; import nxt.Block; import nxt.Constants; import nxt.Currency; import nxt.CurrencyExchangeOffer; import nxt.CurrencyFounder; import nxt.CurrencyTransfer; import nxt.CurrencyType; import nxt.DigitalGoodsStore; import nxt.Exchange; import nxt.ExchangeRequest; import nxt.Generator; import nxt.HoldingType; import nxt.MonetarySystem; import nxt.Nxt; import nxt.Order; import nxt.PhasingPoll; import nxt.PhasingVote; import nxt.Poll; import nxt.PrunableMessage; import nxt.Shuffler; import nxt.Shuffling; import nxt.ShufflingParticipant; import nxt.TaggedData; import nxt.Token; import nxt.Trade; import nxt.Transaction; import nxt.Vote; import nxt.VoteWeighting; import nxt.crypto.Crypto; import nxt.crypto.EncryptedData; import nxt.db.DbIterator; import nxt.peer.Hallmark; import nxt.peer.Peer; import nxt.util.Convert; import nxt.util.Filter; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import java.util.Collections; import java.util.List; import java.util.Map; final class JSONData { static JSONObject alias(Alias alias) { JSONObject json = new JSONObject(); putAccount(json, "account", alias.getAccountId()); json.put("aliasName", alias.getAliasName()); json.put("aliasURI", alias.getAliasURI()); json.put("timestamp", alias.getTimestamp()); json.put("alias", Long.toUnsignedString(alias.getId())); Alias.Offer offer = Alias.getOffer(alias); if (offer != null) { json.put("priceNQT", String.valueOf(offer.getPriceNQT())); if (offer.getBuyerId() != 0) { json.put("buyer", Long.toUnsignedString(offer.getBuyerId())); } } return json; } static JSONObject accountBalance(Account account, boolean includeEffectiveBalance) { JSONObject json = new JSONObject(); if (account == null) { json.put("balanceNQT", "0"); json.put("unconfirmedBalanceNQT", "0"); json.put("forgedBalanceNQT", "0"); if (includeEffectiveBalance) { json.put("effectiveBalanceNXT", "0"); json.put("guaranteedBalanceNQT", "0"); } } else { json.put("balanceNQT", String.valueOf(account.getBalanceNQT())); json.put("unconfirmedBalanceNQT", String.valueOf(account.getUnconfirmedBalanceNQT())); json.put("forgedBalanceNQT", String.valueOf(account.getForgedBalanceNQT())); if (includeEffectiveBalance) { json.put("effectiveBalanceNXT", account.getEffectiveBalanceNXT()); json.put("guaranteedBalanceNQT", String.valueOf(account.getGuaranteedBalanceNQT())); } } return json; } static JSONObject lessor(Account account, boolean includeEffectiveBalance) { JSONObject json = new JSONObject(); Account.AccountLease accountLease = account.getAccountLease(); if (accountLease.getCurrentLesseeId() != 0) { putAccount(json, "currentLessee", accountLease.getCurrentLesseeId()); json.put("currentHeightFrom", String.valueOf(accountLease.getCurrentLeasingHeightFrom())); json.put("currentHeightTo", String.valueOf(accountLease.getCurrentLeasingHeightTo())); if (includeEffectiveBalance) { json.put("effectiveBalanceNXT", String.valueOf(account.getGuaranteedBalanceNQT() / Constants.ONE_NXT)); } } if (accountLease.getNextLesseeId() != 0) { putAccount(json, "nextLessee", accountLease.getNextLesseeId()); json.put("nextHeightFrom", String.valueOf(accountLease.getNextLeasingHeightFrom())); json.put("nextHeightTo", String.valueOf(accountLease.getNextLeasingHeightTo())); } return json; } static JSONObject asset(Asset asset, boolean includeCounts) { JSONObject json = new JSONObject(); putAccount(json, "account", asset.getAccountId()); json.put("name", asset.getName()); json.put("description", asset.getDescription()); json.put("decimals", asset.getDecimals()); json.put("initialQuantityQNT", String.valueOf(asset.getInitialQuantityQNT())); json.put("quantityQNT", String.valueOf(asset.getQuantityQNT())); json.put("asset", Long.toUnsignedString(asset.getId())); if (includeCounts) { json.put("numberOfTrades", Trade.getTradeCount(asset.getId())); json.put("numberOfTransfers", AssetTransfer.getTransferCount(asset.getId())); json.put("numberOfAccounts", Account.getAssetAccountCount(asset.getId())); } return json; } static JSONObject currency(Currency currency, boolean includeCounts) { JSONObject json = new JSONObject(); json.put("currency", Long.toUnsignedString(currency.getId())); putAccount(json, "account", currency.getAccountId()); json.put("name", currency.getName()); json.put("code", currency.getCode()); json.put("description", currency.getDescription()); json.put("type", currency.getType()); json.put("initialSupply", String.valueOf(currency.getInitialSupply())); json.put("currentSupply", String.valueOf(currency.getCurrentSupply())); json.put("reserveSupply", String.valueOf(currency.getReserveSupply())); json.put("maxSupply", String.valueOf(currency.getMaxSupply())); json.put("creationHeight", currency.getCreationHeight()); json.put("issuanceHeight", currency.getIssuanceHeight()); json.put("minReservePerUnitNQT", String.valueOf(currency.getMinReservePerUnitNQT())); json.put("currentReservePerUnitNQT", String.valueOf(currency.getCurrentReservePerUnitNQT())); json.put("minDifficulty", currency.getMinDifficulty()); json.put("maxDifficulty", currency.getMaxDifficulty()); json.put("algorithm", currency.getAlgorithm()); json.put("decimals", currency.getDecimals()); if (includeCounts) { json.put("numberOfExchanges", Exchange.getExchangeCount(currency.getId())); json.put("numberOfTransfers", CurrencyTransfer.getTransferCount(currency.getId())); } JSONArray types = new JSONArray(); for (CurrencyType type : CurrencyType.values()) { if (currency.is(type)) { types.add(type.toString()); } } json.put("types", types); return json; } static JSONObject currencyFounder(CurrencyFounder founder) { JSONObject json = new JSONObject(); json.put("currency", Long.toUnsignedString(founder.getCurrencyId())); putAccount(json, "account", founder.getAccountId()); json.put("amountPerUnitNQT", String.valueOf(founder.getAmountPerUnitNQT())); return json; } static JSONObject accountAsset(Account.AccountAsset accountAsset, boolean includeAccount, boolean includeAssetInfo) { JSONObject json = new JSONObject(); if (includeAccount) { putAccount(json, "account", accountAsset.getAccountId()); } json.put("asset", Long.toUnsignedString(accountAsset.getAssetId())); json.put("quantityQNT", String.valueOf(accountAsset.getQuantityQNT())); json.put("unconfirmedQuantityQNT", String.valueOf(accountAsset.getUnconfirmedQuantityQNT())); if (includeAssetInfo) { putAssetInfo(json, accountAsset.getAssetId()); } return json; } static JSONObject accountCurrency(Account.AccountCurrency accountCurrency, boolean includeAccount, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); if (includeAccount) { putAccount(json, "account", accountCurrency.getAccountId()); } json.put("currency", Long.toUnsignedString(accountCurrency.getCurrencyId())); json.put("units", String.valueOf(accountCurrency.getUnits())); json.put("unconfirmedUnits", String.valueOf(accountCurrency.getUnconfirmedUnits())); if (includeCurrencyInfo) { putCurrencyInfo(json, accountCurrency.getCurrencyId()); } return json; } static JSONObject accountProperty(Account.AccountProperty accountProperty, boolean includeAccount, boolean includeSetter) { JSONObject json = new JSONObject(); if (includeAccount) { putAccount(json, "recipient", accountProperty.getRecipientId()); } if (includeSetter) { putAccount(json, "setter", accountProperty.getSetterId()); } json.put("property", accountProperty.getProperty()); json.put("value", accountProperty.getValue()); return json; } static JSONObject askOrder(Order.Ask order) { JSONObject json = order(order); json.put("type", "ask"); return json; } static JSONObject bidOrder(Order.Bid order) { JSONObject json = order(order); json.put("type", "bid"); return json; } private static JSONObject order(Order order) { JSONObject json = new JSONObject(); json.put("order", Long.toUnsignedString(order.getId())); json.put("asset", Long.toUnsignedString(order.getAssetId())); putAccount(json, "account", order.getAccountId()); json.put("quantityQNT", String.valueOf(order.getQuantityQNT())); json.put("priceNQT", String.valueOf(order.getPriceNQT())); json.put("height", order.getHeight()); json.put("transactionIndex", order.getTransactionIndex()); json.put("transactionHeight", order.getTransactionHeight()); return json; } static JSONObject expectedAskOrder(Transaction transaction) { JSONObject json = expectedOrder(transaction); json.put("type", "ask"); return json; } static JSONObject expectedBidOrder(Transaction transaction) { JSONObject json = expectedOrder(transaction); json.put("type", "bid"); return json; } private static JSONObject expectedOrder(Transaction transaction) { JSONObject json = new JSONObject(); Attachment.ColoredCoinsOrderPlacement attachment = (Attachment.ColoredCoinsOrderPlacement)transaction.getAttachment(); json.put("order", transaction.getStringId()); json.put("asset", Long.toUnsignedString(attachment.getAssetId())); putAccount(json, "account", transaction.getSenderId()); json.put("quantityQNT", String.valueOf(attachment.getQuantityQNT())); json.put("priceNQT", String.valueOf(attachment.getPriceNQT())); putExpectedTransaction(json, transaction); return json; } static JSONObject expectedOrderCancellation(Transaction transaction) { JSONObject json = new JSONObject(); Attachment.ColoredCoinsOrderCancellation attachment = (Attachment.ColoredCoinsOrderCancellation)transaction.getAttachment(); json.put("order", Long.toUnsignedString(attachment.getOrderId())); putAccount(json, "account", transaction.getSenderId()); putExpectedTransaction(json, transaction); return json; } static JSONObject offer(CurrencyExchangeOffer offer) { JSONObject json = new JSONObject(); json.put("offer", Long.toUnsignedString(offer.getId())); putAccount(json, "account", offer.getAccountId()); json.put("height", offer.getHeight()); json.put("expirationHeight", offer.getExpirationHeight()); json.put("currency", Long.toUnsignedString(offer.getCurrencyId())); json.put("rateNQT", String.valueOf(offer.getRateNQT())); json.put("limit", String.valueOf(offer.getLimit())); json.put("supply", String.valueOf(offer.getSupply())); return json; } static JSONObject expectedBuyOffer(Transaction transaction) { JSONObject json = expectedOffer(transaction); Attachment.MonetarySystemPublishExchangeOffer attachment = (Attachment.MonetarySystemPublishExchangeOffer)transaction.getAttachment(); json.put("rateNQT", String.valueOf(attachment.getBuyRateNQT())); json.put("limit", String.valueOf(attachment.getTotalBuyLimit())); json.put("supply", String.valueOf(attachment.getInitialBuySupply())); return json; } static JSONObject expectedSellOffer(Transaction transaction) { JSONObject json = expectedOffer(transaction); Attachment.MonetarySystemPublishExchangeOffer attachment = (Attachment.MonetarySystemPublishExchangeOffer)transaction.getAttachment(); json.put("rateNQT", String.valueOf(attachment.getSellRateNQT())); json.put("limit", String.valueOf(attachment.getTotalSellLimit())); json.put("supply", String.valueOf(attachment.getInitialSellSupply())); return json; } private static JSONObject expectedOffer(Transaction transaction) { Attachment.MonetarySystemPublishExchangeOffer attachment = (Attachment.MonetarySystemPublishExchangeOffer)transaction.getAttachment(); JSONObject json = new JSONObject(); json.put("offer", transaction.getStringId()); putAccount(json, "account", transaction.getSenderId()); json.put("expirationHeight", attachment.getExpirationHeight()); json.put("currency", Long.toUnsignedString(attachment.getCurrencyId())); putExpectedTransaction(json, transaction); return json; } static JSONObject availableOffers(CurrencyExchangeOffer.AvailableOffers availableOffers) { JSONObject json = new JSONObject(); json.put("rateNQT", String.valueOf(availableOffers.getRateNQT())); json.put("units", String.valueOf(availableOffers.getUnits())); json.put("amountNQT", String.valueOf(availableOffers.getAmountNQT())); return json; } static JSONObject shuffling(Shuffling shuffling, boolean includeHoldingInfo) { JSONObject json = new JSONObject(); json.put("shuffling", Long.toUnsignedString(shuffling.getId())); putAccount(json, "issuer", shuffling.getIssuerId()); json.put("holding", Long.toUnsignedString(shuffling.getHoldingId())); json.put("holdingType", shuffling.getHoldingType().getCode()); if (shuffling.getAssigneeAccountId() != 0) { putAccount(json, "assignee", shuffling.getAssigneeAccountId()); } json.put("amount", String.valueOf(shuffling.getAmount())); json.put("blocksRemaining", shuffling.getBlocksRemaining()); json.put("participantCount", shuffling.getParticipantCount()); json.put("registrantCount", shuffling.getRegistrantCount()); json.put("stage", shuffling.getStage().getCode()); json.put("shufflingStateHash", Convert.toHexString(shuffling.getStateHash())); json.put("shufflingFullHash", Convert.toHexString(shuffling.getFullHash())); JSONArray recipientPublicKeys = new JSONArray(); for (byte[] recipientPublicKey : shuffling.getRecipientPublicKeys()) { recipientPublicKeys.add(Convert.toHexString(recipientPublicKey)); } if (recipientPublicKeys.size() > 0) { json.put("recipientPublicKeys", recipientPublicKeys); } if (includeHoldingInfo && shuffling.getHoldingType() != HoldingType.NXT) { JSONObject holdingJson = new JSONObject(); if (shuffling.getHoldingType() == HoldingType.ASSET) { putAssetInfo(holdingJson, shuffling.getHoldingId()); } else if (shuffling.getHoldingType() == HoldingType.CURRENCY) { putCurrencyInfo(holdingJson, shuffling.getHoldingId()); } json.put("holdingInfo", holdingJson); } return json; } static JSONObject participant(ShufflingParticipant participant) { JSONObject json = new JSONObject(); json.put("shuffling", Long.toUnsignedString(participant.getShufflingId())); putAccount(json, "account", participant.getAccountId()); putAccount(json, "nextAccount", participant.getNextAccountId()); json.put("state", participant.getState().getCode()); return json; } static JSONObject shuffler(Shuffler shuffler, boolean includeParticipantState) { JSONObject json = new JSONObject(); putAccount(json, "account", shuffler.getAccountId()); putAccount(json, "recipient", Account.getId(shuffler.getRecipientPublicKey())); json.put("shufflingFullHash", Convert.toHexString(shuffler.getShufflingFullHash())); json.put("shuffling", Long.toUnsignedString(Convert.fullHashToId(shuffler.getShufflingFullHash()))); if (shuffler.getFailedTransaction() != null) { json.put("failedTransaction", unconfirmedTransaction(shuffler.getFailedTransaction())); json.put("failureCause", shuffler.getFailureCause().getMessage()); } if (includeParticipantState) { ShufflingParticipant participant = ShufflingParticipant.getParticipant(Convert.fullHashToId(shuffler.getShufflingFullHash()), shuffler.getAccountId()); if (participant != null) { json.put("participantState", participant.getState().getCode()); } } return json; } static JSONObject block(Block block, boolean includeTransactions, boolean includeExecutedPhased) { JSONObject json = new JSONObject(); json.put("block", block.getStringId()); json.put("height", block.getHeight()); putAccount(json, "generator", block.getGeneratorId()); json.put("generatorPublicKey", Convert.toHexString(block.getGeneratorPublicKey())); json.put("timestamp", block.getTimestamp()); json.put("numberOfTransactions", block.getTransactions().size()); json.put("totalAmountNQT", String.valueOf(block.getTotalAmountNQT())); json.put("totalFeeNQT", String.valueOf(block.getTotalFeeNQT())); json.put("payloadLength", block.getPayloadLength()); json.put("version", block.getVersion()); json.put("baseTarget", Long.toUnsignedString(block.getBaseTarget())); json.put("cumulativeDifficulty", block.getCumulativeDifficulty().toString()); if (block.getPreviousBlockId() != 0) { json.put("previousBlock", Long.toUnsignedString(block.getPreviousBlockId())); } if (block.getNextBlockId() != 0) { json.put("nextBlock", Long.toUnsignedString(block.getNextBlockId())); } json.put("payloadHash", Convert.toHexString(block.getPayloadHash())); json.put("generationSignature", Convert.toHexString(block.getGenerationSignature())); if (block.getVersion() > 1) { json.put("previousBlockHash", Convert.toHexString(block.getPreviousBlockHash())); } json.put("blockSignature", Convert.toHexString(block.getBlockSignature())); JSONArray transactions = new JSONArray(); if (includeTransactions) { block.getTransactions().forEach(transaction -> transactions.add(transaction(transaction))); } else { block.getTransactions().forEach(transaction -> transactions.add(transaction.getStringId())); } json.put("transactions", transactions); if (includeExecutedPhased) { JSONArray phasedTransactions = new JSONArray(); try (DbIterator<PhasingPoll.PhasingPollResult> phasingPollResults = PhasingPoll.getApproved(block.getHeight())) { for (PhasingPoll.PhasingPollResult phasingPollResult : phasingPollResults) { long phasedTransactionId = phasingPollResult.getId(); if (includeTransactions) { phasedTransactions.add(transaction(Nxt.getBlockchain().getTransaction(phasedTransactionId))); } else { phasedTransactions.add(Long.toUnsignedString(phasedTransactionId)); } } } json.put("executedPhasedTransactions", phasedTransactions); } return json; } static JSONObject encryptedData(EncryptedData encryptedData) { JSONObject json = new JSONObject(); json.put("data", Convert.toHexString(encryptedData.getData())); json.put("nonce", Convert.toHexString(encryptedData.getNonce())); return json; } static JSONObject goods(DigitalGoodsStore.Goods goods, boolean includeCounts) { JSONObject json = new JSONObject(); json.put("goods", Long.toUnsignedString(goods.getId())); json.put("name", goods.getName()); json.put("description", goods.getDescription()); json.put("quantity", goods.getQuantity()); json.put("priceNQT", String.valueOf(goods.getPriceNQT())); putAccount(json, "seller", goods.getSellerId()); json.put("tags", goods.getTags()); JSONArray tagsJSON = new JSONArray(); Collections.addAll(tagsJSON, goods.getParsedTags()); json.put("parsedTags", tagsJSON); json.put("delisted", goods.isDelisted()); json.put("timestamp", goods.getTimestamp()); if (includeCounts) { json.put("numberOfPurchases", DigitalGoodsStore.Purchase.getGoodsPurchaseCount(goods.getId(), false, true)); json.put("numberOfPublicFeedbacks", DigitalGoodsStore.Purchase.getGoodsPurchaseCount(goods.getId(), true, true)); } return json; } static JSONObject tag(DigitalGoodsStore.Tag tag) { JSONObject json = new JSONObject(); json.put("tag", tag.getTag()); json.put("inStockCount", tag.getInStockCount()); json.put("totalCount", tag.getTotalCount()); return json; } static JSONObject hallmark(Hallmark hallmark) { JSONObject json = new JSONObject(); putAccount(json, "account", Account.getId(hallmark.getPublicKey())); json.put("host", hallmark.getHost()); json.put("port", hallmark.getPort()); json.put("weight", hallmark.getWeight()); String dateString = Hallmark.formatDate(hallmark.getDate()); json.put("date", dateString); json.put("valid", hallmark.isValid()); return json; } static JSONObject token(Token token) { JSONObject json = new JSONObject(); putAccount(json, "account", Account.getId(token.getPublicKey())); json.put("timestamp", token.getTimestamp()); json.put("valid", token.isValid()); return json; } static JSONObject peer(Peer peer) { JSONObject json = new JSONObject(); json.put("address", peer.getHost()); json.put("port", peer.getPort()); json.put("state", peer.getState().ordinal()); json.put("announcedAddress", peer.getAnnouncedAddress()); json.put("shareAddress", peer.shareAddress()); if (peer.getHallmark() != null) { json.put("hallmark", peer.getHallmark().getHallmarkString()); } json.put("weight", peer.getWeight()); json.put("downloadedVolume", peer.getDownloadedVolume()); json.put("uploadedVolume", peer.getUploadedVolume()); json.put("application", peer.getApplication()); json.put("version", peer.getVersion()); json.put("platform", peer.getPlatform()); if (peer.getApiPort() != 0) { json.put("apiPort", peer.getApiPort()); } if (peer.getApiSSLPort() != 0) { json.put("apiSSLPort", peer.getApiSSLPort()); } json.put("blacklisted", peer.isBlacklisted()); json.put("lastUpdated", peer.getLastUpdated()); json.put("lastConnectAttempt", peer.getLastConnectAttempt()); json.put("inbound", peer.isInbound()); json.put("inboundWebSocket", peer.isInboundWebSocket()); json.put("outboundWebSocket", peer.isOutboundWebSocket()); if (peer.isBlacklisted()) { json.put("blacklistingCause", peer.getBlacklistingCause()); } JSONArray servicesArray = new JSONArray(); for (Peer.Service service : Peer.Service.values()) { if (peer.providesService(service)) { servicesArray.add(service.name()); } } json.put("services", servicesArray); return json; } static JSONObject poll(Poll poll) { JSONObject json = new JSONObject(); putAccount(json, "account", poll.getAccountId()); json.put("poll", Long.toUnsignedString(poll.getId())); json.put("name", poll.getName()); json.put("description", poll.getDescription()); JSONArray options = new JSONArray(); Collections.addAll(options, poll.getOptions()); json.put("options", options); json.put("finishHeight", poll.getFinishHeight()); json.put("minNumberOfOptions", poll.getMinNumberOfOptions()); json.put("maxNumberOfOptions", poll.getMaxNumberOfOptions()); json.put("minRangeValue", poll.getMinRangeValue()); json.put("maxRangeValue", poll.getMaxRangeValue()); putVoteWeighting(json, poll.getVoteWeighting()); json.put("finished", poll.isFinished()); json.put("timestamp", poll.getTimestamp()); return json; } static JSONObject pollResults(Poll poll, List<Poll.OptionResult> results, VoteWeighting voteWeighting) { JSONObject json = new JSONObject(); json.put("poll", Long.toUnsignedString(poll.getId())); if (voteWeighting.getMinBalanceModel() == VoteWeighting.MinBalanceModel.ASSET) { json.put("decimals", Asset.getAsset(voteWeighting.getHoldingId()).getDecimals()); } else if(voteWeighting.getMinBalanceModel() == VoteWeighting.MinBalanceModel.CURRENCY) { Currency currency = Currency.getCurrency(voteWeighting.getHoldingId()); if (currency != null) { json.put("decimals", currency.getDecimals()); } else { Transaction currencyIssuance = Nxt.getBlockchain().getTransaction(voteWeighting.getHoldingId()); Attachment.MonetarySystemCurrencyIssuance currencyIssuanceAttachment = (Attachment.MonetarySystemCurrencyIssuance) currencyIssuance.getAttachment(); json.put("decimals", currencyIssuanceAttachment.getDecimals()); } } putVoteWeighting(json, voteWeighting); json.put("finished", poll.isFinished()); JSONArray options = new JSONArray(); Collections.addAll(options, poll.getOptions()); json.put("options", options); JSONArray resultsJson = new JSONArray(); for (Poll.OptionResult option : results) { JSONObject optionJSON = new JSONObject(); if (option != null) { optionJSON.put("result", String.valueOf(option.getResult())); optionJSON.put("weight", String.valueOf(option.getWeight())); } else { optionJSON.put("result", ""); optionJSON.put("weight", "0"); } resultsJson.add(optionJSON); } json.put("results", resultsJson); return json; } interface VoteWeighter { long calcWeight(long voterId); } static JSONObject vote(Vote vote, VoteWeighter weighter) { JSONObject json = new JSONObject(); putAccount(json, "voter", vote.getVoterId()); json.put("transaction", Long.toUnsignedString(vote.getId())); JSONArray votesJson = new JSONArray(); for (byte v : vote.getVoteBytes()) { if (v == Constants.NO_VOTE_VALUE) { votesJson.add(""); } else { votesJson.add(Byte.toString(v)); } } json.put("votes", votesJson); if (weighter != null) { json.put("weight", String.valueOf(weighter.calcWeight(vote.getVoterId()))); } return json; } static JSONObject phasingPoll(PhasingPoll poll, boolean countVotes) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(poll.getId())); json.put("transactionFullHash", Convert.toHexString(poll.getFullHash())); json.put("finishHeight", poll.getFinishHeight()); json.put("quorum", String.valueOf(poll.getQuorum())); putAccount(json, "account", poll.getAccountId()); JSONArray whitelistJson = new JSONArray(); for (long accountId : poll.getWhitelist()) { JSONObject whitelisted = new JSONObject(); putAccount(whitelisted, "whitelisted", accountId); whitelistJson.add(whitelisted); } json.put("whitelist", whitelistJson); List<byte[]> linkedFullHashes = poll.getLinkedFullHashes(); if (linkedFullHashes.size() > 0) { JSONArray linkedFullHashesJSON = new JSONArray(); for (byte[] hash : linkedFullHashes) { linkedFullHashesJSON.add(Convert.toHexString(hash)); } json.put("linkedFullHashes", linkedFullHashesJSON); } if (poll.getHashedSecret() != null) { json.put("hashedSecret", Convert.toHexString(poll.getHashedSecret())); } putVoteWeighting(json, poll.getVoteWeighting()); PhasingPoll.PhasingPollResult phasingPollResult = PhasingPoll.getResult(poll.getId()); json.put("finished", phasingPollResult != null); if (phasingPollResult != null) { json.put("approved", phasingPollResult.isApproved()); json.put("result", String.valueOf(phasingPollResult.getResult())); json.put("executionHeight", phasingPollResult.getHeight()); } else if (countVotes) { json.put("result", String.valueOf(poll.countVotes())); } return json; } static JSONObject phasingPollResult(PhasingPoll.PhasingPollResult phasingPollResult) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(phasingPollResult.getId())); json.put("approved", phasingPollResult.isApproved()); json.put("result", String.valueOf(phasingPollResult.getResult())); json.put("executionHeight", phasingPollResult.getHeight()); return json; } static JSONObject phasingPollVote(PhasingVote vote) { JSONObject json = new JSONObject(); JSONData.putAccount(json, "voter", vote.getVoterId()); json.put("transaction", Long.toUnsignedString(vote.getVoteId())); return json; } private static void putVoteWeighting(JSONObject json, VoteWeighting voteWeighting) { json.put("votingModel", voteWeighting.getVotingModel().getCode()); json.put("minBalance", String.valueOf(voteWeighting.getMinBalance())); json.put("minBalanceModel", voteWeighting.getMinBalanceModel().getCode()); if (voteWeighting.getHoldingId() != 0) { json.put("holding", Long.toUnsignedString(voteWeighting.getHoldingId())); } } static JSONObject phasingOnly(AccountRestrictions.PhasingOnly phasingOnly) { JSONObject json = new JSONObject(); putAccount(json, "account", phasingOnly.getAccountId()); json.put("quorum", String.valueOf(phasingOnly.getPhasingParams().getQuorum())); JSONArray whitelistJson = new JSONArray(); for (long accountId : phasingOnly.getPhasingParams().getWhitelist()) { JSONObject whitelisted = new JSONObject(); putAccount(whitelisted, "whitelisted", accountId); whitelistJson.add(whitelisted); } json.put("whitelist", whitelistJson); json.put("maxFees", String.valueOf(phasingOnly.getMaxFees())); json.put("minDuration", phasingOnly.getMinDuration()); json.put("maxDuration", phasingOnly.getMaxDuration()); putVoteWeighting(json, phasingOnly.getPhasingParams().getVoteWeighting()); return json; } static JSONObject purchase(DigitalGoodsStore.Purchase purchase) { JSONObject json = new JSONObject(); json.put("purchase", Long.toUnsignedString(purchase.getId())); json.put("goods", Long.toUnsignedString(purchase.getGoodsId())); json.put("name", purchase.getName()); putAccount(json, "seller", purchase.getSellerId()); json.put("priceNQT", String.valueOf(purchase.getPriceNQT())); json.put("quantity", purchase.getQuantity()); putAccount(json, "buyer", purchase.getBuyerId()); json.put("timestamp", purchase.getTimestamp()); json.put("deliveryDeadlineTimestamp", purchase.getDeliveryDeadlineTimestamp()); if (purchase.getNote() != null) { json.put("note", encryptedData(purchase.getNote())); } json.put("pending", purchase.isPending()); if (purchase.getEncryptedGoods() != null) { json.put("goodsData", encryptedData(purchase.getEncryptedGoods())); json.put("goodsIsText", purchase.goodsIsText()); } if (purchase.getFeedbackNotes() != null) { JSONArray feedbacks = new JSONArray(); for (EncryptedData encryptedData : purchase.getFeedbackNotes()) { feedbacks.add(0, encryptedData(encryptedData)); } json.put("feedbackNotes", feedbacks); } if (purchase.getPublicFeedbacks() != null) { JSONArray publicFeedbacks = new JSONArray(); for (String publicFeedback : purchase.getPublicFeedbacks()) { publicFeedbacks.add(0, publicFeedback); } json.put("publicFeedbacks", publicFeedbacks); } if (purchase.getRefundNote() != null) { json.put("refundNote", encryptedData(purchase.getRefundNote())); } if (purchase.getDiscountNQT() > 0) { json.put("discountNQT", String.valueOf(purchase.getDiscountNQT())); } if (purchase.getRefundNQT() > 0) { json.put("refundNQT", String.valueOf(purchase.getRefundNQT())); } return json; } static JSONObject trade(Trade trade, boolean includeAssetInfo) { JSONObject json = new JSONObject(); json.put("timestamp", trade.getTimestamp()); json.put("quantityQNT", String.valueOf(trade.getQuantityQNT())); json.put("priceNQT", String.valueOf(trade.getPriceNQT())); json.put("asset", Long.toUnsignedString(trade.getAssetId())); json.put("askOrder", Long.toUnsignedString(trade.getAskOrderId())); json.put("bidOrder", Long.toUnsignedString(trade.getBidOrderId())); json.put("askOrderHeight", trade.getAskOrderHeight()); json.put("bidOrderHeight", trade.getBidOrderHeight()); putAccount(json, "seller", trade.getSellerId()); putAccount(json, "buyer", trade.getBuyerId()); json.put("block", Long.toUnsignedString(trade.getBlockId())); json.put("height", trade.getHeight()); json.put("tradeType", trade.isBuy() ? "buy" : "sell"); if (includeAssetInfo) { putAssetInfo(json, trade.getAssetId()); } return json; } static JSONObject assetTransfer(AssetTransfer assetTransfer, boolean includeAssetInfo) { JSONObject json = new JSONObject(); json.put("assetTransfer", Long.toUnsignedString(assetTransfer.getId())); json.put("asset", Long.toUnsignedString(assetTransfer.getAssetId())); putAccount(json, "sender", assetTransfer.getSenderId()); putAccount(json, "recipient", assetTransfer.getRecipientId()); json.put("quantityQNT", String.valueOf(assetTransfer.getQuantityQNT())); json.put("height", assetTransfer.getHeight()); json.put("timestamp", assetTransfer.getTimestamp()); if (includeAssetInfo) { putAssetInfo(json, assetTransfer.getAssetId()); } return json; } static JSONObject expectedAssetTransfer(Transaction transaction, boolean includeAssetInfo) { JSONObject json = new JSONObject(); Attachment.ColoredCoinsAssetTransfer attachment = (Attachment.ColoredCoinsAssetTransfer)transaction.getAttachment(); json.put("assetTransfer", transaction.getStringId()); json.put("asset", Long.toUnsignedString(attachment.getAssetId())); putAccount(json, "sender", transaction.getSenderId()); putAccount(json, "recipient", transaction.getRecipientId()); json.put("quantityQNT", String.valueOf(attachment.getQuantityQNT())); if (includeAssetInfo) { putAssetInfo(json, attachment.getAssetId()); } putExpectedTransaction(json, transaction); return json; } static JSONObject assetDelete(AssetDelete assetDelete, boolean includeAssetInfo) { JSONObject json = new JSONObject(); json.put("assetDelete", Long.toUnsignedString(assetDelete.getId())); json.put("asset", Long.toUnsignedString(assetDelete.getAssetId())); putAccount(json, "account", assetDelete.getAccountId()); json.put("quantityQNT", String.valueOf(assetDelete.getQuantityQNT())); json.put("height", assetDelete.getHeight()); json.put("timestamp", assetDelete.getTimestamp()); if (includeAssetInfo) { putAssetInfo(json, assetDelete.getAssetId()); } return json; } static JSONObject expectedAssetDelete(Transaction transaction, boolean includeAssetInfo) { JSONObject json = new JSONObject(); Attachment.ColoredCoinsAssetDelete attachment = (Attachment.ColoredCoinsAssetDelete)transaction.getAttachment(); json.put("assetDelete", transaction.getStringId()); json.put("asset", Long.toUnsignedString(attachment.getAssetId())); putAccount(json, "account", transaction.getSenderId()); json.put("quantityQNT", String.valueOf(attachment.getQuantityQNT())); if (includeAssetInfo) { putAssetInfo(json, attachment.getAssetId()); } putExpectedTransaction(json, transaction); return json; } static JSONObject currencyTransfer(CurrencyTransfer transfer, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); json.put("transfer", Long.toUnsignedString(transfer.getId())); json.put("currency", Long.toUnsignedString(transfer.getCurrencyId())); putAccount(json, "sender", transfer.getSenderId()); putAccount(json, "recipient", transfer.getRecipientId()); json.put("units", String.valueOf(transfer.getUnits())); json.put("height", transfer.getHeight()); json.put("timestamp", transfer.getTimestamp()); if (includeCurrencyInfo) { putCurrencyInfo(json, transfer.getCurrencyId()); } return json; } static JSONObject expectedCurrencyTransfer(Transaction transaction, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); Attachment.MonetarySystemCurrencyTransfer attachment = (Attachment.MonetarySystemCurrencyTransfer)transaction.getAttachment(); json.put("transfer", transaction.getStringId()); json.put("currency", Long.toUnsignedString(attachment.getCurrencyId())); putAccount(json, "sender", transaction.getSenderId()); putAccount(json, "recipient", transaction.getRecipientId()); json.put("units", String.valueOf(attachment.getUnits())); if (includeCurrencyInfo) { putCurrencyInfo(json, attachment.getCurrencyId()); } putExpectedTransaction(json, transaction); return json; } static JSONObject exchange(Exchange exchange, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(exchange.getTransactionId())); json.put("timestamp", exchange.getTimestamp()); json.put("units", String.valueOf(exchange.getUnits())); json.put("rateNQT", String.valueOf(exchange.getRate())); json.put("currency", Long.toUnsignedString(exchange.getCurrencyId())); json.put("offer", Long.toUnsignedString(exchange.getOfferId())); putAccount(json, "seller", exchange.getSellerId()); putAccount(json, "buyer", exchange.getBuyerId()); json.put("block", Long.toUnsignedString(exchange.getBlockId())); json.put("height", exchange.getHeight()); if (includeCurrencyInfo) { putCurrencyInfo(json, exchange.getCurrencyId()); } return json; } static JSONObject exchangeRequest(ExchangeRequest exchangeRequest, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(exchangeRequest.getId())); json.put("subtype", exchangeRequest.isBuy() ? MonetarySystem.EXCHANGE_BUY.getSubtype() : MonetarySystem.EXCHANGE_SELL.getSubtype()); json.put("timestamp", exchangeRequest.getTimestamp()); json.put("units", String.valueOf(exchangeRequest.getUnits())); json.put("rateNQT", String.valueOf(exchangeRequest.getRate())); json.put("height", exchangeRequest.getHeight()); if (includeCurrencyInfo) { putCurrencyInfo(json, exchangeRequest.getCurrencyId()); } return json; } static JSONObject expectedExchangeRequest(Transaction transaction, boolean includeCurrencyInfo) { JSONObject json = new JSONObject(); json.put("transaction", transaction.getStringId()); json.put("subtype", transaction.getType().getSubtype()); Attachment.MonetarySystemExchange attachment = (Attachment.MonetarySystemExchange)transaction.getAttachment(); json.put("units", String.valueOf(attachment.getUnits())); json.put("rateNQT", String.valueOf(attachment.getRateNQT())); if (includeCurrencyInfo) { putCurrencyInfo(json, attachment.getCurrencyId()); } putExpectedTransaction(json, transaction); return json; } static JSONObject unconfirmedTransaction(Transaction transaction) { return unconfirmedTransaction(transaction, null); } static JSONObject unconfirmedTransaction(Transaction transaction, Filter<Appendix> filter) { JSONObject json = new JSONObject(); json.put("type", transaction.getType().getType()); json.put("subtype", transaction.getType().getSubtype()); json.put("phased", transaction.getPhasing() != null); json.put("timestamp", transaction.getTimestamp()); json.put("deadline", transaction.getDeadline()); json.put("senderPublicKey", Convert.toHexString(transaction.getSenderPublicKey())); if (transaction.getRecipientId() != 0) { putAccount(json, "recipient", transaction.getRecipientId()); } json.put("amountNQT", String.valueOf(transaction.getAmountNQT())); json.put("feeNQT", String.valueOf(transaction.getFeeNQT())); String referencedTransactionFullHash = transaction.getReferencedTransactionFullHash(); if (referencedTransactionFullHash != null) { json.put("referencedTransactionFullHash", referencedTransactionFullHash); } byte[] signature = Convert.emptyToNull(transaction.getSignature()); if (signature != null) { json.put("signature", Convert.toHexString(signature)); json.put("signatureHash", Convert.toHexString(Crypto.sha256().digest(signature))); json.put("fullHash", transaction.getFullHash()); json.put("transaction", transaction.getStringId()); } JSONObject attachmentJSON = new JSONObject(); if (filter == null) { for (Appendix appendage : transaction.getAppendages(true)) { attachmentJSON.putAll(appendage.getJSONObject()); } } else { for (Appendix appendage : transaction.getAppendages(filter, true)) { attachmentJSON.putAll(appendage.getJSONObject()); } } if (! attachmentJSON.isEmpty()) { for (Map.Entry entry : (Iterable<Map.Entry>) attachmentJSON.entrySet()) { if (entry.getValue() instanceof Long) { entry.setValue(String.valueOf(entry.getValue())); } } json.put("attachment", attachmentJSON); } putAccount(json, "sender", transaction.getSenderId()); json.put("height", transaction.getHeight()); json.put("version", transaction.getVersion()); if (transaction.getVersion() > 0) { json.put("ecBlockId", Long.toUnsignedString(transaction.getECBlockId())); json.put("ecBlockHeight", transaction.getECBlockHeight()); } return json; } static JSONObject transaction(Transaction transaction) { return transaction(transaction, false); } static JSONObject transaction(Transaction transaction, boolean includePhasingResult) { JSONObject json = transaction(transaction, null); if (includePhasingResult && transaction.getPhasing() != null) { PhasingPoll.PhasingPollResult phasingPollResult = PhasingPoll.getResult(transaction.getId()); if (phasingPollResult != null) { json.put("approved", phasingPollResult.isApproved()); json.put("result", String.valueOf(phasingPollResult.getResult())); json.put("executionHeight", phasingPollResult.getHeight()); } } return json; } static JSONObject transaction(Transaction transaction, Filter<Appendix> filter) { JSONObject json = unconfirmedTransaction(transaction, filter); json.put("block", Long.toUnsignedString(transaction.getBlockId())); json.put("confirmations", Nxt.getBlockchain().getHeight() - transaction.getHeight()); json.put("blockTimestamp", transaction.getBlockTimestamp()); json.put("transactionIndex", transaction.getIndex()); return json; } static JSONObject generator(Generator generator, int elapsedTime) { JSONObject response = new JSONObject(); long deadline = generator.getDeadline(); putAccount(response, "account", generator.getAccountId()); response.put("deadline", deadline); response.put("hitTime", generator.getHitTime()); response.put("remaining", Math.max(deadline - elapsedTime, 0)); return response; } static JSONObject prunableMessage(PrunableMessage prunableMessage, long readerAccountId, String secretPhrase) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(prunableMessage.getId())); if (prunableMessage.getMessage() == null || prunableMessage.getEncryptedData() == null) { json.put("isText", prunableMessage.getMessage() != null ? prunableMessage.messageIsText() : prunableMessage.encryptedMessageIsText()); } putAccount(json, "sender", prunableMessage.getSenderId()); if (prunableMessage.getRecipientId() != 0) { putAccount(json, "recipient", prunableMessage.getRecipientId()); } json.put("transactionTimestamp", prunableMessage.getTransactionTimestamp()); json.put("blockTimestamp", prunableMessage.getBlockTimestamp()); EncryptedData encryptedData = prunableMessage.getEncryptedData(); if (encryptedData != null) { json.put("encryptedMessage", encryptedData(prunableMessage.getEncryptedData())); json.put("encryptedMessageIsText", prunableMessage.encryptedMessageIsText()); if (secretPhrase != null) { byte[] publicKey = prunableMessage.getSenderId() == readerAccountId ? Account.getPublicKey(prunableMessage.getRecipientId()) : Account.getPublicKey(prunableMessage.getSenderId()); if (publicKey != null) { try { byte[] decrypted = Account.decryptFrom(publicKey, encryptedData, secretPhrase, prunableMessage.isCompressed()); json.put("decryptedMessage", Convert.toString(decrypted, prunableMessage.encryptedMessageIsText())); } catch (RuntimeException e) { putException(json, e, "Decryption failed"); } } } json.put("isCompressed", prunableMessage.isCompressed()); } if (prunableMessage.getMessage() != null) { json.put("message", Convert.toString(prunableMessage.getMessage(), prunableMessage.messageIsText())); json.put("messageIsText", prunableMessage.messageIsText()); } return json; } static JSONObject taggedData(TaggedData taggedData, boolean includeData) { JSONObject json = new JSONObject(); json.put("transaction", Long.toUnsignedString(taggedData.getId())); putAccount(json, "account", taggedData.getAccountId()); json.put("name", taggedData.getName()); json.put("description", taggedData.getDescription()); json.put("tags", taggedData.getTags()); JSONArray tagsJSON = new JSONArray(); Collections.addAll(tagsJSON, taggedData.getParsedTags()); json.put("parsedTags", tagsJSON); json.put("type", taggedData.getType()); json.put("channel", taggedData.getChannel()); json.put("filename", taggedData.getFilename()); json.put("isText", taggedData.isText()); if (includeData) { json.put("data", taggedData.isText() ? Convert.toString(taggedData.getData()) : Convert.toHexString(taggedData.getData())); } json.put("transactionTimestamp", taggedData.getTransactionTimestamp()); json.put("blockTimestamp", taggedData.getBlockTimestamp()); return json; } static JSONObject dataTag(TaggedData.Tag tag) { JSONObject json = new JSONObject(); json.put("tag", tag.getTag()); json.put("count", tag.getCount()); return json; } static void putPrunableAttachment(JSONObject json, Transaction transaction) { JSONObject prunableAttachment = transaction.getPrunableAttachmentJSON(); if (prunableAttachment != null) { json.put("prunableAttachmentJSON", prunableAttachment); } } static void putException(JSONObject json, Exception e) { putException(json, e, ""); } static void putException(JSONObject json, Exception e, String error) { json.put("errorCode", 4); if (error.length() > 0) { error += ": "; } json.put("error", e.toString()); json.put("errorDescription", error + e.getMessage()); } static void putAccount(JSONObject json, String name, long accountId) { json.put(name, Long.toUnsignedString(accountId)); json.put(name + "RS", Convert.rsAccount(accountId)); } private static void putCurrencyInfo(JSONObject json, long currencyId) { Currency currency = Currency.getCurrency(currencyId); if (currency == null) { return; } json.put("name", currency.getName()); json.put("code", currency.getCode()); json.put("type", currency.getType()); json.put("decimals", currency.getDecimals()); json.put("issuanceHeight", currency.getIssuanceHeight()); putAccount(json, "issuerAccount", currency.getAccountId()); } private static void putAssetInfo(JSONObject json, long assetId) { Asset asset = Asset.getAsset(assetId); json.put("name", asset.getName()); json.put("decimals", asset.getDecimals()); } private static void putExpectedTransaction(JSONObject json, Transaction transaction) { json.put("height", Nxt.getBlockchain().getHeight() + 1); json.put("phased", transaction.getPhasing() != null); if (transaction.getBlockId() != 0) { // those values may be wrong for unconfirmed transactions json.put("transactionHeight", transaction.getHeight()); json.put("confirmations", Nxt.getBlockchain().getHeight() - transaction.getHeight()); } } static void ledgerEntry(JSONObject json, LedgerEntry entry, boolean includeTransactions) { putAccount(json, "account", entry.getAccountId()); json.put("ledgerId", Long.toUnsignedString(entry.getLedgerId())); json.put("block", Long.toUnsignedString(entry.getBlockId())); json.put("height", entry.getHeight()); json.put("timestamp", entry.getTimestamp()); json.put("eventType", entry.getEvent().name()); json.put("event", Long.toUnsignedString(entry.getEventId())); json.put("isTransactionEvent", entry.getEvent().isTransaction()); json.put("change", String.valueOf(entry.getChange())); json.put("balance", String.valueOf(entry.getBalance())); if (entry.getHolding() != null) { json.put("holdingType", entry.getHolding().name()); if (entry.getHoldingId() != null) { json.put("holding", Long.toUnsignedString(entry.getHoldingId())); } } if (includeTransactions && entry.getEvent().isTransaction()) { Transaction transaction = Nxt.getBlockchain().getTransaction(entry.getEventId()); json.put("transaction", JSONData.transaction(transaction)); } } private JSONData() {} // never }