package com.ripple.core.coretypes.hash; import com.ripple.core.coretypes.AccountID; import com.ripple.core.coretypes.Currency; import com.ripple.core.coretypes.Issue; import com.ripple.core.coretypes.hash.prefixes.HashPrefix; import com.ripple.core.coretypes.hash.prefixes.LedgerSpace; import com.ripple.core.coretypes.uint.UInt32; import com.ripple.core.coretypes.uint.UInt64; import com.ripple.core.serialized.SerializedType; import java.util.Arrays; import java.util.List; import static com.ripple.core.coretypes.hash.HalfSha512.prefixed256; import static java.util.Collections.sort; public class Index { private static Hash256 createBookBase(Issue pays, Issue gets) { return prefixed256(LedgerSpace.bookDir) .add(pays.currency()) .add(gets.currency()) .add(pays.issuer()) .add(gets.issuer()) .finish(); } /** * * @return a copy of index, with quality overlaid in lowest 8 bytes */ public static Hash256 quality(Hash256 index, UInt64 quality) { byte[] qi = new byte[32]; System.arraycopy(index.bytes(), 0, qi, 0, 24); if (quality != null) System.arraycopy(quality.toBytes(), 0, qi, 24, 8); return new Hash256(qi); } /** * @return A copy of index, with the lowest 8 bytes all zeroed. */ private static Hash256 zeroQuality(Hash256 fullIndex) { return quality(fullIndex, null); } public static Hash256 rippleState(AccountID a1, AccountID a2, Currency currency) { List<AccountID> accounts = Arrays.asList(a1, a2); sort(accounts); return rippleState(accounts, currency); } public static Hash256 rippleState(List<AccountID> accounts, Currency currency) { HalfSha512 hasher = prefixed256(LedgerSpace.ripple); // Low then High for (AccountID account : accounts) account.toBytesSink(hasher); // Currency currency.toBytesSink(hasher); return hasher.finish(); } /** * * @param rootIndex The RootIndex index for the directory node * @param nodeIndex nullable LowNode, HighNode, OwnerNode, BookNode etc * defining a `page` number. * * @return A hash of rootIndex and nodeIndex when nodeIndex is non default * else the rootIndex. This hash is used as an index for the next * DirectoryNode page. */ public static Hash256 directoryNode(Hash256 rootIndex, UInt64 nodeIndex) { if (nodeIndex == null || nodeIndex.isZero()) { return rootIndex; } return prefixed256(LedgerSpace.dirNode) .add(rootIndex) .add(nodeIndex) .finish(); } public static Hash256 accountRoot(AccountID accountID) { return prefixed256(LedgerSpace.account).add(accountID).finish(); } public static Hash256 ownerDirectory(AccountID account) { return Hash256.prefixedHalfSha512(LedgerSpace.ownerDir, account.bytes()); } public static Hash256 transactionID(byte[] blob) { return Hash256.prefixedHalfSha512(HashPrefix.transactionID, blob); } public static Hash256 bookStart(Issue pays, Issue gets) { return zeroQuality(createBookBase(pays, gets)); } public static Hash256 bookStart(Hash256 indexFromBookRange) { return zeroQuality(indexFromBookRange); } public static Hash256 bookEnd(Hash256 base) { byte[] end = base.bigInteger().add(Hash256.bookBaseSize).toByteArray(); if (end.length > 32) { byte[] source = end; end = new byte[32]; System.arraycopy(source, source.length - 32, end, 0, 32); } return new Hash256(end); } public static Hash256 ledgerHashes(long prev) { return prefixed256(LedgerSpace.skipList) .add(new UInt32(prev >> 16)) .finish(); } public static Hash256 ledgerHashes() { return prefixed256(LedgerSpace.skipList).finish(); } }