Search in sources :

Example 11 with AccountBalance

use of com.hedera.mirror.common.domain.balance.AccountBalance in project hedera-mirror-node by hashgraph.

the class AccountBalanceLineParserV2Test method parse.

@DisplayName("Parse account balance line")
@ParameterizedTest(name = "from \"{0}\"")
@CsvSource(value = { "'0,0,123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';false;" + "0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0,0,123,700,';false;" + "0;123;700;;", "'0,0,123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgo';true;;;;", "' 0,0,123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0, 0,123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0,0, 123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0,0,123, 700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0,0,123,700, CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'0,0,123,700,CggKAxjsBxCEBwoHCgMY7QcQGQoKCgMY7gcQwKilBAoICgMY8gcQhAcKBwoDGPMHEBkKCgoDGPQHEMCopQQ ';" + "false;0;123;700;1004=900,1005=25,1006=9000000,1010=900,1011=25,1012=9000000", "'1,0,123,700,';true;;;;", "'x,0,123,700,';true;;;;", "'0,x,123,700,';true;;;;", "'0,0,x,700,';true;;;;", "'0,0,123,a00,';true;;;;", "'1000000000000000000000000000,0,123,700,';true;;;;", "'0,1000000000000000000000000000,123,700,';true;;;;", "'0,0,1000000000000000000000000000,700,';true;;;;", "'0,0,123,1000000000000000000000000000,';true;;;;", "'-1,0,123,700,';true;;;;", "'0,-1,123,700,';true;;;;", "'0,0,-1,700,';true;;;;", "'0,0,123,-1,';true;;;;", "'foobar';true;;;;", "'';true;;;;", ";true;;;;" }, delimiter = ';')
void parse(String line, boolean expectThrow, Long expectedRealm, Long expectedAccount, Long expectedBalance, String tokenBalances) throws IOException {
    if (!expectThrow) {
        AccountBalance accountBalance = parser.parse(line, timestamp);
        var id = accountBalance.getId();
        assertThat(accountBalance.getBalance()).isEqualTo(expectedBalance);
        assertThat(id).isNotNull();
        assertThat(id.getAccountId().getRealmNum()).isEqualTo(expectedRealm);
        assertThat(id.getAccountId().getEntityNum()).isEqualTo(expectedAccount);
        assertThat(id.getConsensusTimestamp()).isEqualTo(timestamp);
        List<TokenBalance> actualTokenBalanceList = accountBalance.getTokenBalances();
        if (StringUtils.isNotBlank(tokenBalances)) {
            Map<Long, Long> expectedTokenBalances = Splitter.on(',').withKeyValueSeparator('=').split(tokenBalances).entrySet().stream().collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), entry -> Long.parseLong(entry.getValue())));
            assertThat(actualTokenBalanceList.size()).isEqualTo(expectedTokenBalances.size());
            for (int i = 0; i < actualTokenBalanceList.size(); i++) {
                TokenBalance actualTokenBalance = actualTokenBalanceList.get(i);
                TokenBalance.Id actualId = actualTokenBalance.getId();
                assertThat(expectedTokenBalances).containsKey(actualId.getTokenId().getEntityNum());
                assertThat(actualTokenBalance.getBalance()).isEqualTo(expectedTokenBalances.get(actualId.getTokenId().getEntityNum()));
                assertThat(actualId).isNotNull();
                assertThat(actualId.getConsensusTimestamp()).isEqualTo(timestamp);
                assertThat(actualId.getAccountId().getShardNum()).isEqualTo(mirrorProperties.getShard());
                assertThat(actualId.getAccountId().getRealmNum()).isEqualTo(expectedRealm);
                assertThat(actualId.getAccountId().getEntityNum()).isEqualTo(expectedAccount);
                assertThat(actualId.getTokenId().getShardNum()).isEqualTo(mirrorProperties.getShard());
                assertThat(actualId.getTokenId().getRealmNum()).isEqualTo(expectedRealm);
                assertThat(actualId.getTokenId().getType()).isEqualTo(EntityType.TOKEN);
            }
        } else {
            assertThat(actualTokenBalanceList.size()).isEqualTo(0);
        }
    } else {
        assertThrows(InvalidDatasetException.class, () -> {
            parser.parse(line, timestamp);
        });
    }
}
Also used : BeforeEach(org.junit.jupiter.api.BeforeEach) CsvSource(org.junit.jupiter.params.provider.CsvSource) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) IOException(java.io.IOException) TokenBalance(com.hedera.mirror.common.domain.balance.TokenBalance) Collectors(java.util.stream.Collectors) EntityType(com.hedera.mirror.common.domain.entity.EntityType) StringUtils(org.apache.commons.lang3.StringUtils) DisplayName(org.junit.jupiter.api.DisplayName) Test(org.junit.jupiter.api.Test) List(java.util.List) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance) MirrorProperties(com.hedera.mirror.importer.MirrorProperties) Map(java.util.Map) Assertions(org.junit.jupiter.api.Assertions) Splitter(com.google.common.base.Splitter) InvalidDatasetException(com.hedera.mirror.importer.exception.InvalidDatasetException) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance) TokenBalance(com.hedera.mirror.common.domain.balance.TokenBalance) CsvSource(org.junit.jupiter.params.provider.CsvSource) DisplayName(org.junit.jupiter.api.DisplayName) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 12 with AccountBalance

use of com.hedera.mirror.common.domain.balance.AccountBalance in project hedera-mirror-node by hashgraph.

the class CsvBalanceFileReader method read.

@Override
public AccountBalanceFile read(StreamFileData streamFileData) {
    MessageDigest messageDigest = DigestUtils.getSha384Digest();
    int bufferSize = balanceParserProperties.getFileBufferSize();
    try (InputStream inputStream = new DigestInputStream(streamFileData.getInputStream(), messageDigest);
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET), bufferSize)) {
        long consensusTimestamp = parseConsensusTimestamp(reader);
        AtomicLong count = new AtomicLong(0L);
        List<AccountBalance> items = new ArrayList<>();
        AccountBalanceFile accountBalanceFile = new AccountBalanceFile();
        accountBalanceFile.setBytes(streamFileData.getBytes());
        accountBalanceFile.setConsensusTimestamp(consensusTimestamp);
        accountBalanceFile.setLoadStart(Instant.now().getEpochSecond());
        accountBalanceFile.setName(streamFileData.getFilename());
        reader.lines().map(line -> {
            try {
                AccountBalance accountBalance = parser.parse(line, consensusTimestamp);
                count.incrementAndGet();
                return accountBalance;
            } catch (InvalidDatasetException ex) {
                log.error(ex);
                return null;
            }
        }).filter(Objects::nonNull).forEachOrdered(items::add);
        accountBalanceFile.setCount(count.get());
        accountBalanceFile.setFileHash(DomainUtils.bytesToHex(messageDigest.digest()));
        accountBalanceFile.setItems(Flux.fromIterable(items));
        return accountBalanceFile;
    } catch (IOException ex) {
        throw new InvalidDatasetException("Error reading account balance file", ex);
    }
}
Also used : DigestInputStream(java.security.DigestInputStream) InputStreamReader(java.io.InputStreamReader) DigestInputStream(java.security.DigestInputStream) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) IOException(java.io.IOException) AtomicLong(java.util.concurrent.atomic.AtomicLong) AccountBalanceFile(com.hedera.mirror.common.domain.balance.AccountBalanceFile) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance) InvalidDatasetException(com.hedera.mirror.importer.exception.InvalidDatasetException) BufferedReader(java.io.BufferedReader) MessageDigest(java.security.MessageDigest)

Example 13 with AccountBalance

use of com.hedera.mirror.common.domain.balance.AccountBalance in project hedera-mirror-node by hashgraph.

the class ProtoBalanceFileReader method toAccountBalance.

private AccountBalance toAccountBalance(long consensusTimestamp, SingleAccountBalances balances) {
    EntityId accountId = EntityId.of(balances.getAccountID());
    List<TokenBalance> tokenBalances = balances.getTokenUnitBalancesList().stream().map(tokenBalance -> {
        EntityId tokenId = EntityId.of(tokenBalance.getTokenId());
        TokenBalance.Id id = new TokenBalance.Id(consensusTimestamp, accountId, tokenId);
        return new TokenBalance(tokenBalance.getBalance(), id);
    }).collect(Collectors.toList());
    return new AccountBalance(balances.getHbarBalance(), tokenBalances, new AccountBalance.Id(consensusTimestamp, accountId));
}
Also used : EntityId(com.hedera.mirror.common.domain.entity.EntityId) EntityId(com.hedera.mirror.common.domain.entity.EntityId) AccountBalanceFile(com.hedera.mirror.common.domain.balance.AccountBalanceFile) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance) ExtensionRegistryLite(com.google.protobuf.ExtensionRegistryLite) Named(javax.inject.Named) SingleAccountBalances(com.hedera.services.stream.proto.SingleAccountBalances) Timestamp(com.hederahashgraph.api.proto.java.Timestamp) UnknownFieldSet(com.google.protobuf.UnknownFieldSet) StreamFileReaderException(com.hedera.mirror.importer.exception.StreamFileReaderException) DomainUtils(com.hedera.mirror.common.util.DomainUtils) IOException(java.io.IOException) Instant(java.time.Instant) TokenBalance(com.hedera.mirror.common.domain.balance.TokenBalance) Collectors(java.util.stream.Collectors) AtomicLong(java.util.concurrent.atomic.AtomicLong) IOUtils(org.apache.commons.io.IOUtils) Flux(reactor.core.publisher.Flux) InvalidStreamFileException(com.hedera.mirror.importer.exception.InvalidStreamFileException) List(java.util.List) CodedInputStream(com.google.protobuf.CodedInputStream) Log4j2(lombok.extern.log4j.Log4j2) DigestUtils(org.apache.commons.codec.digest.DigestUtils) InputStream(java.io.InputStream) Assert(org.springframework.util.Assert) StreamFileData(com.hedera.mirror.importer.domain.StreamFileData) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance) TokenBalance(com.hedera.mirror.common.domain.balance.TokenBalance) EntityId(com.hedera.mirror.common.domain.entity.EntityId)

Example 14 with AccountBalance

use of com.hedera.mirror.common.domain.balance.AccountBalance in project hedera-mirror-node by hashgraph.

the class AccountBalanceLineParserV1 method parse.

/**
 * Parses an account balance line to extract shard, realm, account, and balance. If the shard matches
 * systemShardNum, creates and returns an {@code AccountBalance} entity object. The account balance line should be
 * in the format of "shard,realm,account,balance"
 *
 * @param line               The account balance line
 * @param consensusTimestamp The consensus timestamp of the account balance line
 * @return {@code AccountBalance} entity object
 * @throws InvalidDatasetException if the line is malformed or the shard does not match {@code systemShardNum}
 */
@Override
public AccountBalance parse(String line, long consensusTimestamp) {
    try {
        if (line == null) {
            throw new InvalidDatasetException("Null line cannot be parsed");
        }
        List<String> parts = SPLITTER.splitToList(line);
        if (parts.size() != 4) {
            throw new InvalidDatasetException("Invalid account balance line: " + line);
        }
        long shardNum = Long.parseLong(parts.get(0));
        int realmNum = Integer.parseInt(parts.get(1));
        int accountNum = Integer.parseInt(parts.get(2));
        long balance = Long.parseLong(parts.get(3));
        if (shardNum < 0 || realmNum < 0 || accountNum < 0 || balance < 0) {
            throw new InvalidDatasetException("Invalid account balance line: " + line);
        }
        if (shardNum != mirrorProperties.getShard()) {
            throw new InvalidDatasetException(String.format("Invalid account balance line: %s. Expect " + "shard (%d), got shard (%d)", line, mirrorProperties.getShard(), shardNum));
        }
        return new AccountBalance(balance, Collections.emptyList(), new AccountBalance.Id(consensusTimestamp, EntityId.of(shardNum, realmNum, accountNum, EntityType.ACCOUNT)));
    } catch (NumberFormatException ex) {
        throw new InvalidDatasetException("Invalid account balance line: " + line, ex);
    }
}
Also used : InvalidDatasetException(com.hedera.mirror.importer.exception.InvalidDatasetException) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance)

Example 15 with AccountBalance

use of com.hedera.mirror.common.domain.balance.AccountBalance in project hedera-mirror-node by hashgraph.

the class AccountBalanceLineParserV2 method parse.

/**
 * Parses an account balance line to extract shard, realm, account, balance, and token balances. If the shard
 * matches systemShardNum, creates and returns an {@code AccountBalance} entity object. The account balance line
 * should be in the format of "shard,realm,account,balance"
 *
 * @param line               The account balance line
 * @param consensusTimestamp The consensus timestamp of the account balance line
 * @return {@code AccountBalance} entity object
 * @throws InvalidDatasetException if the line is malformed or the shard does not match {@code systemShardNum}
 */
@Override
public AccountBalance parse(String line, long consensusTimestamp) {
    try {
        if (line == null) {
            throw new InvalidDatasetException("Null line cannot be parsed");
        }
        List<String> parts = SPLITTER.splitToList(line);
        boolean hasTokenBalance;
        if (parts.size() == 5) {
            hasTokenBalance = true;
        } else if (parts.size() == 4) {
            hasTokenBalance = false;
        } else {
            throw new InvalidDatasetException("Invalid account balance line: " + line);
        }
        long shardNum = Long.parseLong(parts.get(0));
        int realmNum = Integer.parseInt(parts.get(1));
        int accountNum = Integer.parseInt(parts.get(2));
        long balance = Long.parseLong(parts.get(3));
        if (shardNum < 0 || realmNum < 0 || accountNum < 0 || balance < 0) {
            throw new InvalidDatasetException("Invalid account balance line: " + line);
        }
        if (shardNum != mirrorProperties.getShard()) {
            throw new InvalidDatasetException(String.format("Invalid account balance line: %s. Expect " + "shard (%d), got shard (%d)", line, mirrorProperties.getShard(), shardNum));
        }
        EntityId accountId = EntityId.of(shardNum, realmNum, accountNum, EntityType.ACCOUNT);
        List<TokenBalance> tokenBalances = hasTokenBalance ? parseTokenBalanceList(parts.get(4), consensusTimestamp, accountId) : Collections.emptyList();
        return new AccountBalance(balance, tokenBalances, new AccountBalance.Id(consensusTimestamp, accountId));
    } catch (NumberFormatException | InvalidProtocolBufferException ex) {
        throw new InvalidDatasetException("Invalid account balance line: " + line, ex);
    }
}
Also used : InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) TokenBalance(com.hedera.mirror.common.domain.balance.TokenBalance) EntityId(com.hedera.mirror.common.domain.entity.EntityId) InvalidDatasetException(com.hedera.mirror.importer.exception.InvalidDatasetException) AccountBalance(com.hedera.mirror.common.domain.balance.AccountBalance)

Aggregations

AccountBalance (com.hedera.mirror.common.domain.balance.AccountBalance)18 AccountBalanceFile (com.hedera.mirror.common.domain.balance.AccountBalanceFile)10 TokenBalance (com.hedera.mirror.common.domain.balance.TokenBalance)7 Test (org.junit.jupiter.api.Test)7 EntityId (com.hedera.mirror.common.domain.entity.EntityId)6 InvalidDatasetException (com.hedera.mirror.importer.exception.InvalidDatasetException)5 IOException (java.io.IOException)5 Instant (java.time.Instant)5 List (java.util.List)5 IntegrationTest (com.hedera.mirror.importer.IntegrationTest)4 InputStream (java.io.InputStream)4 Collectors (java.util.stream.Collectors)4 CodedInputStream (com.google.protobuf.CodedInputStream)3 UnknownFieldSet (com.google.protobuf.UnknownFieldSet)3 DomainUtils (com.hedera.mirror.common.util.DomainUtils)3 StreamFileData (com.hedera.mirror.importer.domain.StreamFileData)3 InvalidStreamFileException (com.hedera.mirror.importer.exception.InvalidStreamFileException)3 StreamFileReaderException (com.hedera.mirror.importer.exception.StreamFileReaderException)3 SingleAccountBalances (com.hedera.services.stream.proto.SingleAccountBalances)3 Timestamp (com.hederahashgraph.api.proto.java.Timestamp)3