diff --git a/.github/workflows/mvn-publish.yml b/.github/workflows/mvn-publish.yml index 5b2c638..272489c 100644 --- a/.github/workflows/mvn-publish.yml +++ b/.github/workflows/mvn-publish.yml @@ -9,42 +9,18 @@ on: - v[0-9].[0-9]+.[0-9]+ pull_request: +permissions: + id-token: write + contents: read + jobs: publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - uses: actions/cache@v2 - with: - key: ${{ hashFiles('pom.xml') }} - path: ~/.m2/repository - - name: Prepare version - id: maven-version - run: | - mvn_version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - git_ref=${GITHUB_REF##*/} - pr_number=${{ github.event.number }} - if [[ $git_ref =~ v[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then - if [[ v$mvn_version != $git_ref ]] ; then - echo Maven version $mvn_version does not match tag $git_ref - exit 1 - fi - elif [[ $pr_number != "" && $mvn_version =~ -SNAPSHOT$ ]] ; then - pattern="s/(.+)-SNAPSHOT/\1-"$pr_number"-SNAPSHOT/g" - mvn_version=$(echo $mvn_version | sed -E $pattern) - mvn versions:set -DnewVersion=$mvn_version -DgenerateBackupPoms=false -q -DforceStdout - elif [[ ! $mvn_version =~ -SNAPSHOT$ ]] ; then - echo Refusing to publish non-snapshot version $mvn_version - echo '::set-output name=skip-publish::true' - fi - - uses: samuelmeuli/action-maven-publish@v1.4.0 - if: - ${{ steps.maven-version.outputs.skip-publish != 'true' }} - with: - gpg_private_key: ${{ secrets.OSSRH_GPG_KEY_ASCII }} - gpg_passphrase: ${{ secrets.OSSRH_GPG_PASSPHRASE }} - nexus_username: ${{ secrets.OSSRH_USERNAME }} - nexus_password: ${{ secrets.OSSRH_PASSWORD }} + uses: wavesplatform/protobuf-schemas/.github/workflows/mvn-publish.yml@e7cf7fb33a89e52117ac932596a7338f1e23e82b + with: + github-ref-name: ${{ github.ref_name }} + github-event-number: ${{ github.event.number }} + secrets: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + OSSRH_GPG_KEY: ${{ secrets.OSSRH_GPG_KEY }} + OSSRH_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_PASSPHRASE }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ef836d0..9f92129 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,31 +10,14 @@ on: jobs: run_tests: - runs-on: ubuntu-latest - steps: - - name: Checkout the repository - uses: actions/checkout@v2 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: - fetch-depth: 1 - - - name: Set up JDK 8 - uses: actions/setup-java@v1 - with: - java-version: 8 - - - name: Cache Maven packages - uses: actions/cache@v2 - with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 - - - name: Run tests - run: mvn -B test -Dmaven.test.failure.ignore=true - + java-version: 11 + distribution: temurin + cache: maven + - run: mvn -B test -Dmaven.test.failure.ignore=true - name: Publish test report uses: scacap/action-surefire-report@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/pom.xml b/pom.xml index e300db8..0974bad 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.wavesplatform wavesj - 1.6.2 + 1.6.3-SNAPSHOT jar @@ -43,55 +43,84 @@ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - gt260 - https://nexus.gt260.com/repository/maven-public/ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + + + central + https://central.sonatype.com/repository/maven-snapshots/ + + + - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 + org.apache.maven.plugins + maven-enforcer-plugin + 3.6.2 + + + enforce-maven + + enforce + + + + + 3.9.2 + + + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 true - ossrh - https://oss.sonatype.org/ - true + true + published + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.8 + + + sign-artifacts + verify + + sign + + + + org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.14.1 - 1.8 - 1.8 - true + 11 org.apache.maven.plugins maven-source-plugin - 2.2.1 + 3.4.0 attach-sources @@ -104,19 +133,14 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M3 - - - org.jacoco - jacoco-maven-plugin - 0.8.7 + 3.5.4 org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + 3.12.0 - 8 + 11 @@ -128,78 +152,59 @@ - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - - --pinentry-mode - loopback - - + dev.sigstore + sigstore-maven-plugin + 2.0.0 - sign-artifacts - verify + sign sign - - org.apache.maven.plugins - maven-dependency-plugin - 3.5.0 - - - org.codehaus.mojo - flatten-maven-plugin - 1.2.2 - - ossrh - - - - flatten - process-resources - - flatten - - - - flatten.clean - clean - - clean - - - - + + + + com.google.protobuf + protobuf-java + 4.33.2 + + + commons-codec + commons-codec + 1.20.0 + + + org.apache.commons + commons-compress + 1.28.0 + + + com.fasterxml.jackson.core + jackson-core + 2.20.1 + + + + com.wavesplatform waves-transactions - 1.2.5 + 1.2.6 - com.wavesplatform lang - 1.5.3 - - - - org.scala-lang - scala-library - 2.13.13 + 1.6.0 @@ -213,21 +218,21 @@ ch.qos.logback logback-classic - 1.3.14 + 1.5.23 org.apache.commons commons-lang3 - 3.14.0 + 3.20.0 org.junit.jupiter junit-jupiter - 5.10.2 + 5.14.1 test @@ -239,19 +244,19 @@ org.testcontainers testcontainers - 1.19.6 + 2.0.3 test org.testcontainers junit-jupiter - 1.19.6 + 1.21.4 test org.mockito mockito-core - 4.11.0 + 5.21.0 test diff --git a/src/main/java/com/wavesplatform/wavesj/Block.java b/src/main/java/com/wavesplatform/wavesj/Block.java index 79ad735..b810b6e 100644 --- a/src/main/java/com/wavesplatform/wavesj/Block.java +++ b/src/main/java/com/wavesplatform/wavesj/Block.java @@ -3,10 +3,12 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.wavesplatform.transactions.account.Address; +import com.wavesplatform.transactions.account.PublicKey; import com.wavesplatform.transactions.common.Base58String; import com.wavesplatform.wavesj.info.TransactionWithStatus; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -28,6 +30,9 @@ public Block( @JsonProperty("features") List features, @JsonProperty("desiredReward") long desiredReward, @JsonProperty("generator") Address generator, + @JsonProperty("generatorPublicKey") PublicKey generatorPublicKey, + @JsonProperty("stateHash") Base58String stateHash, + @JsonProperty("rewardShares") Map rewardShares, @JsonProperty("signature") Base58String signature, @JsonProperty("blocksize") int size, @JsonProperty("transactionCount") int transactionsCount, @@ -36,9 +41,13 @@ public Block( @JsonProperty("reward") long reward, @JsonProperty("VRF") Base58String vrf, @JsonProperty("fee") long fee, + @JsonProperty("challengedHeader") ChallengedHeader challengedHeader, + @JsonProperty("finalizationVoting") FinalizationVoting finalizationVoting, @JsonProperty("transactions") List transactions) { - super(version, timestamp, reference, transactionsRoot, id, features, desiredReward, generator, - signature, size, transactionsCount, height, totalFee, reward, vrf); + super(version, timestamp, reference, transactionsRoot, id, features, desiredReward, + generator, generatorPublicKey, stateHash, rewardShares, signature, + size, transactionsCount, height, totalFee, reward, vrf, + challengedHeader, finalizationVoting); this.fee = fee; this.transactions = Common.notNull(transactions, "Transactions"); } diff --git a/src/main/java/com/wavesplatform/wavesj/BlockHeaders.java b/src/main/java/com/wavesplatform/wavesj/BlockHeaders.java index 877c9f9..e43c610 100644 --- a/src/main/java/com/wavesplatform/wavesj/BlockHeaders.java +++ b/src/main/java/com/wavesplatform/wavesj/BlockHeaders.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.wavesplatform.transactions.account.Address; +import com.wavesplatform.transactions.account.PublicKey; import com.wavesplatform.transactions.common.Base58String; import java.util.ArrayList; @@ -25,6 +26,7 @@ public class BlockHeaders { private final List features; private final long desiredReward; private final Address generator; + private final PublicKey generatorPublicKey; private final Base58String signature; private final int size; private final int transactionsCount; @@ -32,6 +34,10 @@ public class BlockHeaders { private final long totalFee; private final long reward; private final Base58String vrf; + private final ChallengedHeader challengedHeader; + private final FinalizationVoting finalizationVoting; + private final Base58String stateHash; + private final Map rewardShares; @JsonCreator public BlockHeaders( @@ -43,18 +49,26 @@ public BlockHeaders( @JsonProperty("features") List features, @JsonProperty("desiredReward") long desiredReward, @JsonProperty("generator") Address generator, + @JsonProperty("generatorPublicKey") PublicKey generatorPublicKey, + @JsonProperty("stateHash") Base58String stateHash, + @JsonProperty("rewardShares") Map rewardShares, @JsonProperty("signature") Base58String signature, @JsonProperty("blocksize") int size, @JsonProperty("transactionCount") int transactionsCount, @JsonProperty("height") int height, @JsonProperty("totalFee") long totalFee, @JsonProperty("reward") long reward, - @JsonProperty("VRF") Base58String vrf) { + @JsonProperty("VRF") Base58String vrf, + @JsonProperty("challengedHeader") ChallengedHeader challengedHeader, + @JsonProperty("finalizationVoting") FinalizationVoting finalizationVoting) { this.height = height; this.version = version; this.timestamp = timestamp; this.reference = Common.notNull(reference, "Reference"); this.generator = Common.notNull(generator, "Generator"); + this.generatorPublicKey = generatorPublicKey; + this.stateHash = stateHash == null ? Base58String.empty() : stateHash; + this.rewardShares = rewardShares == null ? Map.of() : rewardShares; this.signature = Common.notNull(signature, "Signature"); this.id = id == null ? this.signature : id; this.vrf = vrf == null ? Base58String.empty() : vrf; @@ -65,15 +79,25 @@ public BlockHeaders( this.reward = reward; this.desiredReward = desiredReward; this.features = features == null ? new ArrayList<>() : features; + this.challengedHeader = challengedHeader; + this.finalizationVoting = finalizationVoting; } @JsonProperty("nxt-consensus") private void nxtConsensus(Map nxtConsensus) { Object baseTargetObj = nxtConsensus.get("base-target"); - this.baseTarget = baseTargetObj instanceof Long ? (Long) baseTargetObj : (Integer) baseTargetObj; + this.baseTarget = ((Number) nxtConsensus.get("base-target")).longValue(); this.generationSignature = new Base58String((String) nxtConsensus.get("generation-signature")); } + public ChallengedHeader challengedHeader() { + return challengedHeader; + } + + public FinalizationVoting finalizationVoting() { + return finalizationVoting; + } + public int version() { return version; } @@ -114,6 +138,18 @@ public Address generator() { return generator; } + public PublicKey generatorPublicKey() { + return generatorPublicKey; + } + + public Base58String stateHash() { + return stateHash; + } + + public Map rewardShares() { + return rewardShares; + } + public Base58String signature() { return signature; } @@ -162,13 +198,41 @@ public boolean equals(Object o) { Objects.equals(id, that.id) && Objects.equals(features, that.features) && Objects.equals(generator, that.generator) && + Objects.equals(generatorPublicKey, that.generatorPublicKey) && + Objects.equals(stateHash, that.stateHash) && + Objects.equals(rewardShares, that.rewardShares) && Objects.equals(signature, that.signature) && - Objects.equals(vrf, that.vrf); + Objects.equals(vrf, that.vrf) && + Objects.equals(challengedHeader, that.challengedHeader) && + Objects.equals(finalizationVoting, that.finalizationVoting); } @Override public int hashCode() { - return Objects.hash(version, timestamp, reference, baseTarget, generationSignature, transactionsRoot, id, features, desiredReward, generator, signature, size, transactionsCount, height, totalFee, reward, vrf); + return Objects.hash( + version, + timestamp, + reference, + baseTarget, + generationSignature, + transactionsRoot, + id, + features, + desiredReward, + generator, + generatorPublicKey, + stateHash, + rewardShares, + signature, + size, + transactionsCount, + height, + totalFee, + reward, + vrf, + challengedHeader, + finalizationVoting + ); } @Override @@ -178,19 +242,24 @@ public String toString() { ", height=" + height + ", timestamp=" + timestamp + ", generator=" + generator + + ", generatorPublicKey=" + generatorPublicKey + ", version=" + version + ", reference=" + reference + ", baseTarget=" + baseTarget + - ", generationSignature='" + generationSignature + '\'' + + ", generationSignature=" + generationSignature + + (stateHash != null ? ", stateHash=" + stateHash : "") + ", vrf=" + vrf + ", features=" + features + - ", signature='" + signature + '\'' + + ", signature=" + signature + ", desiredReward=" + desiredReward + ", reward=" + reward + + (rewardShares != null ? ", rewardShares=" + rewardShares : "") + ", totalFee=" + totalFee + ", transactionsCount=" + transactionsCount + - ", transactionsRoot='" + transactionsRoot + '\'' + + ", transactionsRoot=" + transactionsRoot + ", size=" + size + + (challengedHeader != null ? ", challengedHeader=" + challengedHeader : "") + + (finalizationVoting != null ? ", finalizationVoting=" + finalizationVoting : "") + '}'; } } diff --git a/src/main/java/com/wavesplatform/wavesj/ChallengedHeader.java b/src/main/java/com/wavesplatform/wavesj/ChallengedHeader.java new file mode 100644 index 0000000..533367d --- /dev/null +++ b/src/main/java/com/wavesplatform/wavesj/ChallengedHeader.java @@ -0,0 +1,100 @@ +package com.wavesplatform.wavesj; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wavesplatform.transactions.account.Address; +import com.wavesplatform.transactions.common.Base58String; + +import java.util.List; +import java.util.Objects; + +public class ChallengedHeader { + + private final Base58String headerSignature; + private final List features; + private final Address generator; + private final Base58String generatorPublicKey; + private final long desiredReward; + private final Base58String stateHash; + private final FinalizationVoting finalizationVoting; + + @JsonCreator + public ChallengedHeader( + @JsonProperty("headerSignature") Base58String headerSignature, + @JsonProperty("features") List features, + @JsonProperty("generator") Address generator, + @JsonProperty("generatorPublicKey") Base58String generatorPublicKey, + @JsonProperty("desiredReward") long desiredReward, + @JsonProperty("stateHash") Base58String stateHash, + @JsonProperty("finalizationVoting") FinalizationVoting finalizationVoting + ) { + this.headerSignature = headerSignature; + this.features = features == null ? List.of() : features; + this.generator = generator; + this.generatorPublicKey = generatorPublicKey; + this.desiredReward = desiredReward; + this.stateHash = stateHash; + this.finalizationVoting = finalizationVoting; + } + + public Base58String getHeaderSignature() { + return headerSignature; + } + + public List getFeatures() { + return features; + } + + public Address getGenerator() { + return generator; + } + + public Base58String getGeneratorPublicKey() { + return generatorPublicKey; + } + + public long getDesiredReward() { + return desiredReward; + } + + public Base58String getStateHash() { + return stateHash; + } + + public FinalizationVoting getFinalizationVoting() { + return finalizationVoting; + } + + @Override + public String toString() { + return "ChallengedHeader{" + + "headerSignature=" + headerSignature + + ", features=" + features + + ", generator=" + generator + + ", generatorPublicKey=" + generatorPublicKey + + ", desiredReward=" + desiredReward + + ", stateHash=" + stateHash + + (finalizationVoting != null ? ", finalizationVoting=" + finalizationVoting : "") + + '}'; + + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ChallengedHeader)) return false; + ChallengedHeader that = (ChallengedHeader) o; + return desiredReward == that.desiredReward && + Objects.equals(headerSignature, that.headerSignature) && + Objects.equals(features, that.features) && + Objects.equals(generator, that.generator) && + Objects.equals(generatorPublicKey, that.generatorPublicKey) && + Objects.equals(stateHash, that.stateHash) && + Objects.equals(finalizationVoting, that.finalizationVoting); + } + + @Override + public int hashCode() { + return Objects.hash(headerSignature, features, generator, generatorPublicKey, desiredReward, stateHash, finalizationVoting); + } +} diff --git a/src/main/java/com/wavesplatform/wavesj/CommittedGenerator.java b/src/main/java/com/wavesplatform/wavesj/CommittedGenerator.java new file mode 100644 index 0000000..95fb772 --- /dev/null +++ b/src/main/java/com/wavesplatform/wavesj/CommittedGenerator.java @@ -0,0 +1,69 @@ +package com.wavesplatform.wavesj; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wavesplatform.transactions.account.Address; +import com.wavesplatform.transactions.common.Id; + +import java.util.Objects; + +public class CommittedGenerator { + + private final Address address; + private final long balance; + private final Id transactionId; + private final Integer conflictHeight; + + @JsonCreator + public CommittedGenerator(@JsonProperty("address") Address address, + @JsonProperty("balance") long balance, + @JsonProperty("transactionId") Id transactionId, + @JsonProperty("conflictHeight") Integer conflictHeight) { + this.address = address; + this.balance = balance; + this.transactionId = transactionId; + this.conflictHeight = conflictHeight; + } + + public Address address(){ + return address; + } + + public long balance() { + return balance; + } + + public Id transactionId(){ + return transactionId; + } + + public Integer conflictHeight() { + return conflictHeight; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CommittedGenerator that = (CommittedGenerator) o; + return address == that.address && + balance == that.balance && + transactionId == that.transactionId && + Objects.equals(conflictHeight, that.conflictHeight); + } + + @Override + public int hashCode() { + return Objects.hash(address, balance, transactionId); + } + + @Override + public String toString() { + return "CommittedGenerator{" + + "address=" + address.toString() + + ", balance=" + balance + + ", transactionId=" + transactionId + + (conflictHeight != null ? ", conflictHeight=" + conflictHeight : "") + + '}'; + } +} diff --git a/src/main/java/com/wavesplatform/wavesj/ConflictEndorsement.java b/src/main/java/com/wavesplatform/wavesj/ConflictEndorsement.java new file mode 100644 index 0000000..b683daf --- /dev/null +++ b/src/main/java/com/wavesplatform/wavesj/ConflictEndorsement.java @@ -0,0 +1,72 @@ +package com.wavesplatform.wavesj; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wavesplatform.transactions.account.BlsSignature; +import com.wavesplatform.transactions.common.Base58String; +import com.wavesplatform.transactions.common.Id; + +import java.util.Objects; + +public class ConflictEndorsement { + + private final int endorserIndex; + private final Base58String finalizedBlockId; + private final BlsSignature signature; + private final int finalizedHeight; + + @JsonCreator + public ConflictEndorsement( + @JsonProperty("endorserIndex") int endorserIndex, + @JsonProperty("finalizedBlockId") Id finalizedBlockId, + @JsonProperty("finalizedHeight") int finalizedHeight, + @JsonProperty("signature") BlsSignature signature + ) { + this.endorserIndex = endorserIndex; + this.finalizedBlockId = finalizedBlockId; + this.finalizedHeight = finalizedHeight; + this.signature = signature; + } + + public int getEndorserIndex() { + return endorserIndex; + } + + public Base58String getFinalizedBlockId() { + return finalizedBlockId; + } + + public int getFinalizedHeight() { + return finalizedHeight; + } + + public BlsSignature getSignature() { + return signature; + } + + @Override + public String toString() { + return "ConflictEndorsement{" + + "endorserIndex=" + endorserIndex + + ", finalizedBlockId=" + finalizedBlockId + + ", finalizedHeight=" + finalizedHeight + + ", signature=" + signature + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ConflictEndorsement)) return false; + ConflictEndorsement that = (ConflictEndorsement) o; + return endorserIndex == that.endorserIndex && + Objects.equals(finalizedBlockId, that.finalizedBlockId) && + Objects.equals(finalizedHeight, that.finalizedHeight) && + Objects.equals(signature, that.signature); + } + + @Override + public int hashCode() { + return Objects.hash(endorserIndex, finalizedBlockId, finalizedHeight, signature); + } +} diff --git a/src/main/java/com/wavesplatform/wavesj/FinalizationVoting.java b/src/main/java/com/wavesplatform/wavesj/FinalizationVoting.java new file mode 100644 index 0000000..f2ba74f --- /dev/null +++ b/src/main/java/com/wavesplatform/wavesj/FinalizationVoting.java @@ -0,0 +1,72 @@ +package com.wavesplatform.wavesj; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wavesplatform.transactions.account.BlsSignature; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class FinalizationVoting { + + private final List endorserIndexes; + private final BlsSignature aggregatedEndorsementSignature; + private final List conflictEndorsements; + private final int finalizedHeight; + + @JsonCreator + public FinalizationVoting( + @JsonProperty("endorserIndexes") List endorserIndexes, + @JsonProperty("aggregatedEndorsementSignature") BlsSignature aggregatedEndorsementSignature, + @JsonProperty("conflictEndorsements") List conflictEndorsements, + @JsonProperty("finalizedHeight") int finalizedHeight + ) { + this.endorserIndexes = endorserIndexes == null ? Collections.emptyList() : endorserIndexes; + this.aggregatedEndorsementSignature = aggregatedEndorsementSignature; + this.finalizedHeight = finalizedHeight; + this.conflictEndorsements = conflictEndorsements == null ? Collections.emptyList() : conflictEndorsements; + } + + public List getEndorserIndexes() { + return endorserIndexes; + } + + public BlsSignature getAggregatedEndorsementSignature() { + return aggregatedEndorsementSignature; + } + + public int getFinalizedHeight() { + return finalizedHeight; + } + + public List getConflictEndorsements() { + return conflictEndorsements; + } + + @Override + public String toString() { + return "FinalizationVoting{" + + "endorserIndexes=" + endorserIndexes + + ", aggregatedEndorsementSignature=" + aggregatedEndorsementSignature + + ", finalizedHeight=" + finalizedHeight + + (!conflictEndorsements.isEmpty() ? ", conflictEndorsements=" + conflictEndorsements : "") + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FinalizationVoting that = (FinalizationVoting) o; + return Objects.equals(endorserIndexes, that.endorserIndexes) && + Objects.equals(aggregatedEndorsementSignature, that.aggregatedEndorsementSignature) && + Objects.equals(finalizedHeight, that.finalizedHeight) && + Objects.equals(conflictEndorsements, that.conflictEndorsements); + } + + @Override + public int hashCode() { + return Objects.hash(endorserIndexes, aggregatedEndorsementSignature, finalizedHeight, conflictEndorsements); + } +} diff --git a/src/main/java/com/wavesplatform/wavesj/Node.java b/src/main/java/com/wavesplatform/wavesj/Node.java index b2d6fa6..b198757 100644 --- a/src/main/java/com/wavesplatform/wavesj/Node.java +++ b/src/main/java/com/wavesplatform/wavesj/Node.java @@ -44,6 +44,7 @@ import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; +import java.util.stream.IntStream; import static com.wavesplatform.transactions.serializers.json.JsonSerializer.JSON_MAPPER; import static com.wavesplatform.wavesj.Status.CONFIRMED; @@ -364,6 +365,13 @@ public BlockHeaders getBlockHeaders(int height) throws IOException, NodeExceptio return asType(get("/blocks/headers/at/" + height), TypeRef.BLOCK_HEADERS); } + /** + * Returns block header at given height. + * + * @param blockId block id + * @return block object without transactions + * @throws IOException if no block exists at the given height + */ public BlockHeaders getBlockHeaders(Base58String blockId) throws IOException, NodeException { return asType(get("/blocks/headers/" + blockId.toString()), TypeRef.BLOCK_HEADERS); } @@ -381,7 +389,7 @@ public List getBlocksHeaders(int fromHeight, int toHeight) throws } /** - * Returns last block header + * Returns last block headers * * @return block object without transactions * @throws IOException if no block exists at the given height @@ -390,6 +398,16 @@ public BlockHeaders getLastBlockHeaders() throws IOException, NodeException { return asType(get("/blocks/headers/last"), TypeRef.BLOCK_HEADERS); } + /** + * Returns last finalized block headers + * + * @return block object without transactions + * @throws IOException if no block exists at the given height + */ + public BlockHeaders getFinalizedBlockHeaders() throws IOException, NodeException { + return asType(get("/blocks/headers/finalized"), TypeRef.BLOCK_HEADERS); + } + /** * Returns block at given height. * @@ -417,7 +435,7 @@ public List getBlocks(int fromHeight, int toHeight) throws IOException, N } public Block getGenesisBlock() throws IOException, NodeException { - return asType(get("/blocks/first"), TypeRef.BLOCK); + return asType(get("/blocks/at/1"), TypeRef.BLOCK); } public Block getLastBlock() throws IOException, NodeException { @@ -429,6 +447,31 @@ public List getBlocksGeneratedBy(Address generator, int fromHeight, int t "/blocks/address/" + generator.toString() + "/" + fromHeight + "/" + toHeight), TypeRef.BLOCKS); } + /** + * Returns committed generators at given height. + * + * @param height blockchain height + * @return list of committed generators + */ + public List getCommittedGeneratorsAt(int height) throws IOException, NodeException { + return asType(get("/generators/at/" + height), TypeRef.COMMITTED_GENERATORS); + } + + /** + * Returns committed generator index at given height. + * + * @param address address of commited generator + * @param height blockchain height + * @return index of committed generator + */ + public int getCommittedGeneratorIndex(Address address, int height) throws IOException, NodeException { + List committedGeneratorList = getCommittedGeneratorsAt(height); + return IntStream.range(0, committedGeneratorList.size()) + .filter(i -> committedGeneratorList.get(i).address().equals(address)) + .findFirst() + .orElse(-1); + } + //=============== // NODE //=============== @@ -750,6 +793,8 @@ public void waitForTransactions(List ids, int waitingInSeconds) throws IOExc return; } catch (Exception e) { lastException = e; + break; + } finally { try { Thread.sleep(pollingIntervalInMillis); } catch (InterruptedException ignored) { diff --git a/src/main/java/com/wavesplatform/wavesj/info/CommitToGenerationTransactionInfo.java b/src/main/java/com/wavesplatform/wavesj/info/CommitToGenerationTransactionInfo.java new file mode 100644 index 0000000..e84ba3e --- /dev/null +++ b/src/main/java/com/wavesplatform/wavesj/info/CommitToGenerationTransactionInfo.java @@ -0,0 +1,20 @@ +package com.wavesplatform.wavesj.info; + +import com.wavesplatform.transactions.CommitToGenerationTransaction; +import com.wavesplatform.transactions.Transaction; +import com.wavesplatform.wavesj.ApplicationStatus; + +public class CommitToGenerationTransactionInfo extends TransactionInfo{ + public CommitToGenerationTransactionInfo(Transaction tx, ApplicationStatus applicationStatus, int height) { + super(tx, applicationStatus, height); + } + + public CommitToGenerationTransaction tx() { + return (CommitToGenerationTransaction) super.tx(); + } + + @Override + public String toString() { + return "CommitToGenerationTransaction{} " + super.toString(); + } +} diff --git a/src/main/java/com/wavesplatform/wavesj/json/TypeRef.java b/src/main/java/com/wavesplatform/wavesj/json/TypeRef.java index 0583d2f..05a0694 100644 --- a/src/main/java/com/wavesplatform/wavesj/json/TypeRef.java +++ b/src/main/java/com/wavesplatform/wavesj/json/TypeRef.java @@ -39,6 +39,8 @@ public class TypeRef { public static final TypeReference> BLOCKS = new TypeReference>() {}; + public static final TypeReference> COMMITTED_GENERATORS = new TypeReference>() {}; + public static final TypeReference BLOCK_HEADERS = new TypeReference() {}; public static final TypeReference> BLOCKS_HEADERS = new TypeReference>() {}; diff --git a/src/main/java/com/wavesplatform/wavesj/json/deser/TransactionInfoDeser.java b/src/main/java/com/wavesplatform/wavesj/json/deser/TransactionInfoDeser.java index 2a7a673..09aa55f 100644 --- a/src/main/java/com/wavesplatform/wavesj/json/deser/TransactionInfoDeser.java +++ b/src/main/java/com/wavesplatform/wavesj/json/deser/TransactionInfoDeser.java @@ -75,6 +75,8 @@ else if (tx instanceof EthereumTransaction) stateChangesFromJson(codec, json), json.get("bytes").asText() ); + else if (tx instanceof CommitToGenerationTransaction) + return new CommitToGenerationTransactionInfo((CommitToGenerationTransaction) tx, status, height); else throw new IOException("Can't parse transaction info: " + json.toString()); } diff --git a/src/test/java/base/BaseTestWithNodeInDocker.java b/src/test/java/base/BaseTestWithNodeInDocker.java index e811eec..4ba1a91 100644 --- a/src/test/java/base/BaseTestWithNodeInDocker.java +++ b/src/test/java/base/BaseTestWithNodeInDocker.java @@ -29,7 +29,7 @@ public abstract class BaseTestWithNodeInDocker { NODE_CONTAINER = null; NODE_API_URL = Profile.LOCAL.uri().toString(); } else { - NODE_CONTAINER = new GenericContainer<>(DockerImageName.parse("wavesplatform/waves-private-node:v1.4.6")) + NODE_CONTAINER = new GenericContainer<>(DockerImageName.parse("wavesplatform/waves-private-node:v1.6.0")) .withExposedPorts(6869) .withStartupTimeout(Duration.of(5, MINUTES)); NODE_CONTAINER.start(); diff --git a/src/test/java/node/BlockMockTest.java b/src/test/java/node/BlockMockTest.java new file mode 100644 index 0000000..69d78ba --- /dev/null +++ b/src/test/java/node/BlockMockTest.java @@ -0,0 +1,138 @@ +package node; + +import com.wavesplatform.wavesj.*; +import com.wavesplatform.wavesj.exceptions.NodeException; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; + +import static node.mock.util.MockHttpRsUtil.mockGBlockHeadersRs; +import static node.mock.util.MockHttpRsUtil.mockHttpClient; +import static org.junit.jupiter.api.Assertions.*; + +public class BlockMockTest { + private final Node node = new Node(Profile.LOCAL, mockHttpClient("src/test/resources/stub/addressesD.json")); + + private static final byte CHAIN_ID = 'D'; + + public BlockMockTest() throws NodeException, IOException { + } + + @Test + void readBlocksHeadersWithFinalizationVoting() throws NodeException, IOException { + mockGBlockHeadersRs(node, + 16, + "src/test/resources/stub/blocks/block_with_voting.json" + ); + + BlockHeaders bh = node.getBlockHeaders(16); + + // ===== base fields ===== + assertEquals(5, bh.version()); + assertEquals(1766555613090L, bh.timestamp()); + assertEquals("6mb8A1dnf8zdvkuCHbqPi8qukALDm97in9wfiNFcbHNq", bh.reference().encoded()); + assertEquals("AdHHXpTvCPxQw6Ge57BaPpkLKHrVmAy4VBv2UPR3rzBu", bh.transactionsRoot().encoded()); + assertEquals("9xhR5xULkazyC5Po7bPfTHV8APbrH72N2KHfkV4nYDXi", bh.id().encoded()); + + assertEquals(-1, bh.desiredReward()); + assertEquals("3FZs7eqZSmG56AqfTdWj2wJ1NWTrUZNgS6Q", bh.generator().toString()); + + assertEquals( + "67HpHJnrEwJuqvn44JjgHJy5TuRLXfu4kAi1fujVHq8y356JFTmLs1LXJciBpJAbTRV9jkxZYGsUNfzS7G9i5LVN", + bh.signature().encoded() + ); + + assertEquals(1068, bh.size()); + assertEquals(3, bh.transactionsCount()); + assertEquals(16, bh.height()); + assertEquals(300_000L, bh.totalFee()); + assertEquals(6_000_000_000L, bh.reward()); + + assertEquals( + "5VjPUXb4NU9QQFoTsEET2xM9ncJfVzjQYZwpUQENStMH", + bh.vrf().encoded() + ); + + assertEquals(0, bh.features().size()); + assertEquals(20120L, bh.baseTarget()); + assertEquals( + "jUqHiYP7E7LZMS8facqNrjp9m6jLB31TjmCxX3aqubyApK9q6qEBUbqapXi6X38oYjYsW1qBA7rTmAo4GvTC8vSDVRWeLrwfxwsQCgUV7MNyqcMt3efJD6bHuuyUh7yfVie", + bh.generationSignature().encoded() + ); + + FinalizationVoting fv = bh.finalizationVoting(); + assertEquals(14, fv.getFinalizedHeight()); + assertEquals(List.of(1, 3), fv.getEndorserIndexes()); + assertEquals( + "xgHXeGVftVtfxEZhRrfC5Q3pb8DajoGnFed7PxDBC9JegLuW7e1jYjh9QXzU9AeDSB4dShS8id9oThaKwgG4wddevXbiBwenuVFdRXUM3hyqbkcgMCnDLexhZtWhxfrs7AU", + fv.getAggregatedEndorsementSignature().encoded() + ); + + assertEquals(1, fv.getConflictEndorsements().size()); + ConflictEndorsement ce = fv.getConflictEndorsements().get(0); + assertEquals(2, ce.getEndorserIndex()); + assertEquals( + "3LKirJGRvMcdaachGNEuWVSyGbpzWKcagrjsQQuaYXwq", + ce.getFinalizedBlockId().encoded() + ); + assertEquals(13, ce.getFinalizedHeight()); + assertEquals( + "omjkPiJX473jCxnScb5XXwi7MRf8Sb4Wom18X68eFodkMuSv3ztNK8fW3886cSqEDJ9PwWV9goJ4H6EPMSkoZmFNSkfnbZzRwrbrCdYFrjDgWzxw91tyWLtX7F2xKAcHsQq", + ce.getSignature().encoded() + ); + + assertEquals("BCuRAvrPqngYBKvJ3HKERz3nZZQRKEUMY81FJCEQPfNV", + bh.generatorPublicKey().encoded()); + assertEquals("HwLttQ7xwStDavkXbBtfaeUy3QoKJMbCbTkNEezivEL6", + bh.stateHash().encoded()); + assertEquals(3, bh.rewardShares().size()); + } + + @Test + public void readChallengedBlocksHeaders() throws IOException, NodeException { + mockGBlockHeadersRs(node, + 42, + "src/test/resources/stub/blocks/challenged_block.json" + ); + + BlockHeaders bh = node.getBlockHeaders(42); + assertEquals(5, bh.version()); + assertEquals(42, bh.height()); + assertNotNull(bh.generatorPublicKey()); + assertNotNull(bh.stateHash()); + assertNotNull(bh.rewardShares()); + assertEquals(2, bh.rewardShares().size()); + + ChallengedHeader ch = bh.challengedHeader(); + assertNotNull(ch); + assertEquals( + "52SXMJphW45QdshxfYUxH7w6FhXmGXU2zTmW6mDLvcaWVigKjtufQT7gTJ3gimKFx8mwKyGuTtzoMDf6CYWymjLE", + ch.getHeaderSignature().encoded() + ); + + assertNotNull(ch.getFeatures()); + assertTrue(ch.getFeatures().isEmpty()); + assertEquals( + "3Fgtiv5L5q4CXFfwuAfbkjy9ppehkNzjbEG", + ch.getGenerator().encoded() + ); + assertEquals( + "5FUsFwB6b8mE61VMbSB6X7m23NTy4yN8f1fApXo8tZs7", + ch.getGeneratorPublicKey().encoded() + ); + assertEquals(-1L, ch.getDesiredReward()); + assertEquals( + "11111111111111111111111111111111", + ch.getStateHash().encoded() + ); + FinalizationVoting fv = ch.getFinalizationVoting(); + assertNotNull(fv); + assertEquals(List.of(2, 1), fv.getEndorserIndexes()); + assertEquals( + "yEuHinUSJCG8LdNtvtstKp7edVGrwMmGQQ8qf6ghWc8BB9oiJryCMVmsBQrAJQZX7i8cC1d5mqH2jYLJT2QeJ7QSbMGBAWueVcYhUzpoPtwvtG5NxZUcvTsRUjiZEWPT7uD", + fv.getAggregatedEndorsementSignature().encoded() + ); + assertEquals(40, fv.getFinalizedHeight()); + } +} diff --git a/src/test/java/node/BlockchainTest.java b/src/test/java/node/BlockchainTest.java index 8efe615..f258fd9 100644 --- a/src/test/java/node/BlockchainTest.java +++ b/src/test/java/node/BlockchainTest.java @@ -26,7 +26,7 @@ void rewards() throws IOException, NodeException { assertThat(rewards.totalWavesAmount()).isGreaterThan(100000000_00000000L); assertThat(rewards.currentReward()).isBetween(5_00000000L, 7_00000000L); assertThat(rewards.minIncrement()).isEqualTo(50000000); - assertThat(rewards.term()).isEqualTo(6); + assertThat(rewards.term()).isEqualTo(3); assertThat(rewards.nextCheck()).isGreaterThan(rewards.votingIntervalStart()); assertThat(rewards.votingInterval()).isEqualTo(3); assertThat(rewards.votingThreshold()).isEqualTo(2); diff --git a/src/test/java/node/mock/util/MockHttpRsUtil.java b/src/test/java/node/mock/util/MockHttpRsUtil.java index 2c0f5b0..e5c177a 100644 --- a/src/test/java/node/mock/util/MockHttpRsUtil.java +++ b/src/test/java/node/mock/util/MockHttpRsUtil.java @@ -1,7 +1,6 @@ package node.mock.util; import com.wavesplatform.wavesj.Node; -import com.wavesplatform.wavesj.Profile; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; @@ -39,7 +38,17 @@ public static void mockGetBlockRs(Node nodeMock, int height, String rsFilePath) ).thenReturn(createBasicRs(rsFilePath)); } - public static HttpClient mockHttpClient() throws IOException { + public static void mockGBlockHeadersRs(Node nodeMock, int height, String rsFilePath) throws IOException { + when( + nodeMock.client().execute( + argThat(rq -> + rq != null && rq.getURI().equals(nodeMock.uri().resolve("/blocks/headers/at/" + height)) + ) + ) + ).thenReturn(createBasicRs(rsFilePath)); + } + + public static HttpClient mockHttpClient(String addressFilePath) throws IOException { HttpClient mockHttpClient = Mockito.mock(HttpClient.class); when( mockHttpClient.execute( @@ -47,7 +56,7 @@ public static HttpClient mockHttpClient() throws IOException { rq != null && rq.getURI().toString().endsWith("/addresses") ) ) - ).thenReturn(createBasicRs("src/test/resources/stub/addresses.json")); + ).thenReturn(createBasicRs(addressFilePath)); return mockHttpClient; } diff --git a/src/test/java/node/transactions/CommitToGenerationTxTest.java b/src/test/java/node/transactions/CommitToGenerationTxTest.java new file mode 100644 index 0000000..41e5487 --- /dev/null +++ b/src/test/java/node/transactions/CommitToGenerationTxTest.java @@ -0,0 +1,57 @@ +package node.transactions; + +import com.wavesplatform.transactions.CommitToGenerationTransaction; +import com.wavesplatform.transactions.common.Id; +import com.wavesplatform.wavesj.Node; +import com.wavesplatform.wavesj.Profile; +import com.wavesplatform.wavesj.exceptions.NodeException; +import com.wavesplatform.wavesj.info.CommitToGenerationTransactionInfo; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static com.wavesplatform.wavesj.ApplicationStatus.SUCCEEDED; +import static node.mock.util.MockHttpRsUtil.mockHttpClient; +import static node.mock.util.MockHttpRsUtil.mockTransactionInfoRs; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CommitToGenerationTxTest { + + private final Node node = new Node(Profile.LOCAL, mockHttpClient("src/test/resources/stub/addressesD.json")); + + private static final byte CHAIN_ID = 'D'; + + public CommitToGenerationTxTest() throws NodeException, IOException { + } + + @Test + void readCommitToGenerationTransactionByIdTest() throws NodeException, IOException { + mockTransactionInfoRs(node, + "2r6kpnJbGqNTmLxi9cPuavgxqumGufnisnN8vhuSCpaX", + "src/test/resources/stub/txs/commit_to_generation_tx.json" + ); + + CommitToGenerationTransactionInfo ctgTxInfo = + (CommitToGenerationTransactionInfo) node.getTransactionInfo( + new Id("2r6kpnJbGqNTmLxi9cPuavgxqumGufnisnN8vhuSCpaX") + ); + + CommitToGenerationTransaction ctgTx = ctgTxInfo.tx(); + + assertEquals(19, ctgTx.type()); + assertEquals("2r6kpnJbGqNTmLxi9cPuavgxqumGufnisnN8vhuSCpaX", ctgTx.id().encoded()); + assertEquals(100_00000, ctgTx.fee().value()); + assertEquals(1766488084192L, ctgTx.timestamp()); + assertEquals(1, ctgTx.version()); + assertEquals(CHAIN_ID, ctgTx.chainId()); + assertEquals(2941, ctgTx.generationPeriodStart()); + assertEquals("3FmjX4FAeDXE4ZdDj2JKxzE4QtbxaioXzxM", ctgTx.sender().address(CHAIN_ID).encoded()); + assertEquals("Bn21Eg8HbwZWZQMHXnTFnb64MhVjgH2HygDekQDbjjMq", ctgTx.sender().encoded()); + assertEquals("5t9zL1oqXW6kL3YUAuF8r4rKUaPwohPVrpMWR8Y1bAJtSMipP3TQJYZvpBFB7GWZwo", + ctgTx.endorserPublicKey().encoded()); + assertEquals("u9CTxLENQWyd5egnHrnbnnDKy7mvtrWJfR1AuCL4e4e7uuRTobzxVy1SQBz7ayoY5mRfiTG3PR8niJPT3fdVfsD97EkagBha8ehrLAzdutWSLbiQF2VDwPfi7uvTcp5csMC", + ctgTx.commitmentSignature().encoded()); + assertEquals(73, ctgTxInfo.height()); + assertEquals(SUCCEEDED, ctgTxInfo.applicationStatus()); + } +} diff --git a/src/test/java/node/transactions/EthereumTransactionFromJsonTest.java b/src/test/java/node/transactions/EthereumTransactionFromJsonTest.java index 11dafed..b0dbeb3 100644 --- a/src/test/java/node/transactions/EthereumTransactionFromJsonTest.java +++ b/src/test/java/node/transactions/EthereumTransactionFromJsonTest.java @@ -32,7 +32,7 @@ //todo move bytes attribute to inner transaction public class EthereumTransactionFromJsonTest { - private final Node node = new Node(Profile.LOCAL, mockHttpClient()); + private final Node node = new Node(Profile.LOCAL, mockHttpClient("src/test/resources/stub/addresses.json")); private static final byte PRIVATE_NODE_CHAIN_ID = 'R'; @@ -43,7 +43,7 @@ public EthereumTransactionFromJsonTest() throws NodeException, IOException { void readEthereumTransferTransactionByIdTest() throws NodeException, IOException { mockTransactionInfoRs(node, "Ba4pFx78Ueg3j6CZqjhuBdg5cjxTwTzJJSS6GPpH3Cn4", - "src/test/resources/stub/eth/eth_transfer_tx_info.json" + "src/test/resources/stub/txs/eth/eth_transfer_tx_info.json" ); EthereumTransactionInfo ethTransferTxInfo = @@ -62,7 +62,7 @@ void readEthereumTransferTransactionByIdTest() throws NodeException, IOException assertEquals(1, ethTransferTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, ethTransferTx.chainId()); assertEquals(transferBytes, ethTransferTxInfo.getBytes()); - assertEquals("3M86rqkCp9hYim1cEbRC8MiajcktM16ogVx", ethTransferTx.sender().address().encoded()); + assertEquals("3M86rqkCp9hYim1cEbRC8MiajcktM16ogVx", ethTransferTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("4WcqqW7mkz7AaBgpWQXbewk3wPSHZGqGj38d8HQZe1Umud2HXFswbGhZyoHZWd3thLjz4KW22JM5SB4yyzGiWjNx", ethTransferTx.sender().encoded()); assertEquals(1043438, ethTransferTxInfo.height()); @@ -78,7 +78,7 @@ public void readEthereumTransferTransactionFromBlockTest() throws NodeException, mockGetBlockRs( node, 1043438, - "src/test/resources/stub/eth/eth_transfer_tx_from_block.json" + "src/test/resources/stub/txs/eth/eth_transfer_tx_from_block.json" ); Block block = node.getBlock(1043438); @@ -93,7 +93,7 @@ public void readEthereumTransferTransactionFromBlockTest() throws NodeException, assertEquals(1, ethTransferTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, ethTransferTx.chainId()); //bytes - assertEquals("3M86rqkCp9hYim1cEbRC8MiajcktM16ogVx", ethTransferTx.sender().address().encoded()); + assertEquals("3M86rqkCp9hYim1cEbRC8MiajcktM16ogVx", ethTransferTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("4WcqqW7mkz7AaBgpWQXbewk3wPSHZGqGj38d8HQZe1Umud2HXFswbGhZyoHZWd3thLjz4KW22JM5SB4yyzGiWjNx", ethTransferTx.sender().encoded()); // application status @@ -103,7 +103,7 @@ public void readEthereumTransferTransactionFromBlockTest() throws NodeException, void readEthereumInvokeTransactionByIdTest() throws NodeException, IOException { mockTransactionInfoRs(node, "CWuFY42te67sLmc5gwt4NxwHmFjVfJdHkKuLyshTwEct", - "src/test/resources/stub/eth/eth_invoke_tx_info.json" + "src/test/resources/stub/txs/eth/eth_invoke_tx_info.json" ); EthereumTransactionInfo ethInvokeTxInfo = @@ -122,7 +122,7 @@ void readEthereumInvokeTransactionByIdTest() throws NodeException, IOException { assertEquals(1, ethInvokeTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, ethInvokeTx.chainId()); assertEquals(invokeBytes, ethInvokeTxInfo.getBytes()); - assertEquals("3MCMsdDqmhoz4wFHus4XKD1xJ8SAsimgBTW", ethInvokeTx.sender().address().encoded()); + assertEquals("3MCMsdDqmhoz4wFHus4XKD1xJ8SAsimgBTW", ethInvokeTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("2HAk5dPx7Jx7fwbehqA9JRM9de9E7ZXtxVA2u92vYAp9ttZQiVgChPwBdoJ7ck2wcXmgfGxiAK9a6PPmmtEZmhvd", ethInvokeTx.sender().encoded()); assertEquals(1043725, ethInvokeTxInfo.height()); @@ -145,7 +145,7 @@ void readEthereumInvokeTransactionFromBlockTest() throws NodeException, IOExcept mockGetBlockRs( node, 1043725, - "src/test/resources/stub/eth/eth_invoke_tx_from_block.json" + "src/test/resources/stub/txs/eth/eth_invoke_tx_from_block.json" ); Block block = node.getBlock(1043725); @@ -159,7 +159,7 @@ void readEthereumInvokeTransactionFromBlockTest() throws NodeException, IOExcept assertEquals(1, ethInvokeTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, ethInvokeTx.chainId()); //assertEquals(invokeBytes, ethInvokeTxInfo.getBytes()); - assertEquals("3MCMsdDqmhoz4wFHus4XKD1xJ8SAsimgBTW", ethInvokeTx.sender().address().encoded()); + assertEquals("3MCMsdDqmhoz4wFHus4XKD1xJ8SAsimgBTW", ethInvokeTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("2HAk5dPx7Jx7fwbehqA9JRM9de9E7ZXtxVA2u92vYAp9ttZQiVgChPwBdoJ7ck2wcXmgfGxiAK9a6PPmmtEZmhvd", ethInvokeTx.sender().encoded()); } @@ -168,7 +168,7 @@ void readEthereumInvokeTransactionFromBlockTest() throws NodeException, IOExcept void readExchangeTransactionInfoWithEthereumSignatureTest() throws IOException, NodeException { mockTransactionInfoRs(node, "3ZPyxs4p7abkj5cf43pUkaHaMPRuBaWC89RX93d2AB6R", - "src/test/resources/stub/eth/exchange_tx_info_with_eth_sign.json" + "src/test/resources/stub/txs/eth/exchange_tx_info_with_eth_sign.json" ); ExchangeTransactionInfo exchangeTxInfo = @@ -185,7 +185,7 @@ void readExchangeTransactionInfoWithEthereumSignatureTest() throws IOException, assertEquals(1652441936773L, exchangeTx.timestamp()); assertEquals(3, exchangeTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, exchangeTx.chainId()); - assertEquals("3MNUQ7dgUpRVnY84PJHy33rMPD8v4zm3FDJ", exchangeTx.sender().address().encoded()); + assertEquals("3MNUQ7dgUpRVnY84PJHy33rMPD8v4zm3FDJ", exchangeTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("CsdeJPgJebkW4tsvAaWtfzNvaFd7nWJUGiHrqrtEGN9p", exchangeTx.sender().encoded()); assertEquals("3vbCSYNC6T3BrooeULFpHewphHKLV8p6cDz9NFYQEpkGzA8HCaL7EDTYRYEyNs26AiqS1gdHnxb4H6AYUqdmH8pd", exchangeTx.proofs().get(0).encoded()); @@ -194,7 +194,7 @@ void readExchangeTransactionInfoWithEthereumSignatureTest() throws IOException, assertEquals(4, order1.version()); assertEquals("GozxekHa86f9TqMiibckWKJR8V2FJzYuksBV2ESWVyHF", order1.id().encoded()); - assertEquals("3M6zKVa3cshzkPRRobLaZjzkrT4fHtuSn3Z", order1.sender().address().encoded()); + assertEquals("3M6zKVa3cshzkPRRobLaZjzkrT4fHtuSn3Z", order1.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("4USoKrfmyQ2xFB8jSjpF95Ma2RFgNDkAbk3td5PhEjrk", order1.sender().encoded()); assertEquals("CsdeJPgJebkW4tsvAaWtfzNvaFd7nWJUGiHrqrtEGN9p", order1.matcher().encoded()); assertEquals("CDyHKz5S5dmnBceTxix1cGQpetXAwWVXKiez2TpvpVLw", order1.assetPair().left().encoded()); @@ -214,7 +214,7 @@ void readExchangeTransactionInfoWithEthereumSignatureTest() throws IOException, Order order2 = exchangeTx.sellOrder(); assertEquals(4, order2.version()); assertEquals("3qnirddnVRKeFR84RPdxDUeFmqcV3SGyQpwgkgEz6SYM", order2.id().encoded()); - assertEquals("3M2jsLHQgaewRmP6BChR2LEjpsef2VZSixf", order2.sender().address().encoded()); + assertEquals("3M2jsLHQgaewRmP6BChR2LEjpsef2VZSixf", order2.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals( "26Djzne1dkfLBMu6nkf4RS9TETmGhMRiaoao1nEkhj5NeqSmwkGXr9WP6zAU4h1rZFSTjgn3EkfTUonZutRNEBSm", order2.sender().encoded() @@ -248,7 +248,7 @@ void readExchangeTransactionWithEthereumSignatureFormBlockTest() throws IOExcept mockGetBlockRs( node, 1099637, - "src/test/resources/stub/eth/exchange_tx_with_eth_sign_from_block.json" + "src/test/resources/stub/txs/eth/exchange_tx_with_eth_sign_from_block.json" ); ExchangeTransaction exchangeTx = @@ -261,7 +261,7 @@ void readExchangeTransactionWithEthereumSignatureFormBlockTest() throws IOExcept assertEquals(1652441936773L, exchangeTx.timestamp()); assertEquals(3, exchangeTx.version()); assertEquals(PRIVATE_NODE_CHAIN_ID, exchangeTx.chainId()); - assertEquals("3MNUQ7dgUpRVnY84PJHy33rMPD8v4zm3FDJ", exchangeTx.sender().address().encoded()); + assertEquals("3MNUQ7dgUpRVnY84PJHy33rMPD8v4zm3FDJ", exchangeTx.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("CsdeJPgJebkW4tsvAaWtfzNvaFd7nWJUGiHrqrtEGN9p", exchangeTx.sender().encoded()); assertEquals("3vbCSYNC6T3BrooeULFpHewphHKLV8p6cDz9NFYQEpkGzA8HCaL7EDTYRYEyNs26AiqS1gdHnxb4H6AYUqdmH8pd", exchangeTx.proofs().get(0).encoded()); @@ -270,7 +270,7 @@ void readExchangeTransactionWithEthereumSignatureFormBlockTest() throws IOExcept assertEquals(4, order1.version()); assertEquals("GozxekHa86f9TqMiibckWKJR8V2FJzYuksBV2ESWVyHF", order1.id().encoded()); - assertEquals("3M6zKVa3cshzkPRRobLaZjzkrT4fHtuSn3Z", order1.sender().address().encoded()); + assertEquals("3M6zKVa3cshzkPRRobLaZjzkrT4fHtuSn3Z", order1.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals("4USoKrfmyQ2xFB8jSjpF95Ma2RFgNDkAbk3td5PhEjrk", order1.sender().encoded()); assertEquals("CsdeJPgJebkW4tsvAaWtfzNvaFd7nWJUGiHrqrtEGN9p", order1.matcher().encoded()); assertEquals("CDyHKz5S5dmnBceTxix1cGQpetXAwWVXKiez2TpvpVLw", order1.assetPair().left().encoded()); @@ -290,7 +290,7 @@ void readExchangeTransactionWithEthereumSignatureFormBlockTest() throws IOExcept Order order2 = exchangeTx.sellOrder(); assertEquals(4, order2.version()); assertEquals("3qnirddnVRKeFR84RPdxDUeFmqcV3SGyQpwgkgEz6SYM", order2.id().encoded()); - assertEquals("3M2jsLHQgaewRmP6BChR2LEjpsef2VZSixf", order2.sender().address().encoded()); + assertEquals("3M2jsLHQgaewRmP6BChR2LEjpsef2VZSixf", order2.sender().address(PRIVATE_NODE_CHAIN_ID).encoded()); assertEquals( "26Djzne1dkfLBMu6nkf4RS9TETmGhMRiaoao1nEkhj5NeqSmwkGXr9WP6zAU4h1rZFSTjgn3EkfTUonZutRNEBSm", order2.sender().encoded() diff --git a/src/test/java/util/CompilerTest.java b/src/test/java/util/CompilerTest.java index ab578fc..f560251 100644 --- a/src/test/java/util/CompilerTest.java +++ b/src/test/java/util/CompilerTest.java @@ -4,41 +4,41 @@ import com.wavesplatform.wavesj.ScriptInfo; import com.wavesplatform.wavesj.exceptions.CompilationException; import com.wavesplatform.wavesj.util.CompilationUtil; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class CompilerTest { @Test public void compileContract() throws CompilationException { ScriptInfo scriptInfo = CompilationUtil.compile(contract); - Assert.assertEquals(new Base64String(compiledContract), scriptInfo.script()); - Assert.assertEquals(207, scriptInfo.complexity()); - Assert.assertEquals(207, scriptInfo.verifierComplexity()); - Assert.assertEquals(Integer.valueOf(21), scriptInfo.callableComplexities().get("issueNft")); - Assert.assertEquals(Integer.valueOf(4), scriptInfo.callableComplexities().get("setPrice")); - Assert.assertEquals(Integer.valueOf(207), scriptInfo.callableComplexities().get("pullTheLever")); - Assert.assertEquals(0L, scriptInfo.extraFee()); + Assertions.assertEquals(new Base64String(compiledContract), scriptInfo.script()); + Assertions.assertEquals(207, scriptInfo.complexity()); + Assertions.assertEquals(207, scriptInfo.verifierComplexity()); + Assertions.assertEquals(Integer.valueOf(21), scriptInfo.callableComplexities().get("issueNft")); + Assertions.assertEquals(Integer.valueOf(4), scriptInfo.callableComplexities().get("setPrice")); + Assertions.assertEquals(Integer.valueOf(207), scriptInfo.callableComplexities().get("pullTheLever")); + Assertions.assertEquals(0L, scriptInfo.extraFee()); } @Test public void compileExpression() throws CompilationException { ScriptInfo scriptInfo = CompilationUtil.compile(expression); - Assert.assertEquals(new Base64String(compiledExpression), scriptInfo.script()); - Assert.assertEquals(3, scriptInfo.complexity()); - Assert.assertEquals(3, scriptInfo.verifierComplexity()); - Assert.assertTrue(scriptInfo.callableComplexities().isEmpty()); - Assert.assertEquals(0L, scriptInfo.extraFee()); + Assertions.assertEquals(new Base64String(compiledExpression), scriptInfo.script()); + Assertions.assertEquals(3, scriptInfo.complexity()); + Assertions.assertEquals(3, scriptInfo.verifierComplexity()); + Assertions.assertTrue(scriptInfo.callableComplexities().isEmpty()); + Assertions.assertEquals(0L, scriptInfo.extraFee()); } @Test public void compileLibrary() throws CompilationException { ScriptInfo scriptInfo = CompilationUtil.compile(library); - Assert.assertEquals(new Base64String(compiledLibrary), scriptInfo.script()); - Assert.assertEquals(0, scriptInfo.complexity()); - Assert.assertEquals(0, scriptInfo.verifierComplexity()); - Assert.assertTrue(scriptInfo.callableComplexities().isEmpty()); - Assert.assertEquals(0L, scriptInfo.extraFee()); + Assertions.assertEquals(new Base64String(compiledLibrary), scriptInfo.script()); + Assertions.assertEquals(0, scriptInfo.complexity()); + Assertions.assertEquals(0, scriptInfo.verifierComplexity()); + Assertions.assertTrue(scriptInfo.callableComplexities().isEmpty()); + Assertions.assertEquals(0L, scriptInfo.extraFee()); } @Test @@ -51,15 +51,15 @@ public void compileV8() throws CompilationException { "let b = [1, 2, 3].replaceByIndex(1, 0)\n" + "a == b[0]"; ScriptInfo scriptInfo = CompilationUtil.compile(script); - Assert.assertEquals(12, scriptInfo.complexity()); - Assert.assertEquals(12, scriptInfo.verifierComplexity()); - Assert.assertTrue(scriptInfo.callableComplexities().isEmpty()); - Assert.assertEquals(0, scriptInfo.extraFee()); + Assertions.assertEquals(12, scriptInfo.complexity()); + Assertions.assertEquals(12, scriptInfo.verifierComplexity()); + Assertions.assertTrue(scriptInfo.callableComplexities().isEmpty()); + Assertions.assertEquals(0, scriptInfo.extraFee()); } - @Test(expected = CompilationException.class) - public void compilationError() throws CompilationException { - CompilationUtil.compile("{-# STDLIB_V 1 #-}"); + @Test + public void compilationError() { + Assertions.assertThrows(CompilationException.class, () -> CompilationUtil.compile("{-# STDLIB_V 1 #-}")); } private static final String contract = "{-# STDLIB_VERSION 6 #-}\n" + diff --git a/src/test/resources/stub/addressesD.json b/src/test/resources/stub/addressesD.json new file mode 100644 index 0000000..f43a273 --- /dev/null +++ b/src/test/resources/stub/addressesD.json @@ -0,0 +1,3 @@ +[ + "3FSgXpgbT6m1speWgVx3cVxAZKmdr4barHU" +] \ No newline at end of file diff --git a/src/test/resources/stub/blocks/block_with_voting.json b/src/test/resources/stub/blocks/block_with_voting.json new file mode 100644 index 0000000..d7a3d56 --- /dev/null +++ b/src/test/resources/stub/blocks/block_with_voting.json @@ -0,0 +1,44 @@ +{ + "version": 5, + "timestamp": 1766555613090, + "reference": "6mb8A1dnf8zdvkuCHbqPi8qukALDm97in9wfiNFcbHNq", + "nxt-consensus": { + "base-target": 20120, + "generation-signature": "jUqHiYP7E7LZMS8facqNrjp9m6jLB31TjmCxX3aqubyApK9q6qEBUbqapXi6X38oYjYsW1qBA7rTmAo4GvTC8vSDVRWeLrwfxwsQCgUV7MNyqcMt3efJD6bHuuyUh7yfVie" + }, + "transactionsRoot": "AdHHXpTvCPxQw6Ge57BaPpkLKHrVmAy4VBv2UPR3rzBu", + "id": "9xhR5xULkazyC5Po7bPfTHV8APbrH72N2KHfkV4nYDXi", + "features": [], + "desiredReward": -1, + "generator": "3FZs7eqZSmG56AqfTdWj2wJ1NWTrUZNgS6Q", + "generatorPublicKey": "BCuRAvrPqngYBKvJ3HKERz3nZZQRKEUMY81FJCEQPfNV", + "stateHash": "HwLttQ7xwStDavkXbBtfaeUy3QoKJMbCbTkNEezivEL6", + "finalizationVoting": { + "endorserIndexes": [ + 1, + 3 + ], + "aggregatedEndorsementSignature": "xgHXeGVftVtfxEZhRrfC5Q3pb8DajoGnFed7PxDBC9JegLuW7e1jYjh9QXzU9AeDSB4dShS8id9oThaKwgG4wddevXbiBwenuVFdRXUM3hyqbkcgMCnDLexhZtWhxfrs7AU", + "finalizedHeight": 14, + "conflictEndorsements": [ + { + "endorserIndex": 2, + "finalizedBlockId": "3LKirJGRvMcdaachGNEuWVSyGbpzWKcagrjsQQuaYXwq", + "finalizedHeight": 13, + "signature": "omjkPiJX473jCxnScb5XXwi7MRf8Sb4Wom18X68eFodkMuSv3ztNK8fW3886cSqEDJ9PwWV9goJ4H6EPMSkoZmFNSkfnbZzRwrbrCdYFrjDgWzxw91tyWLtX7F2xKAcHsQq" + } + ] + }, + "signature": "67HpHJnrEwJuqvn44JjgHJy5TuRLXfu4kAi1fujVHq8y356JFTmLs1LXJciBpJAbTRV9jkxZYGsUNfzS7G9i5LVN", + "blocksize": 1068, + "transactionCount": 3, + "height": 16, + "totalFee": 300000, + "reward": 6000000000, + "rewardShares": { + "3FVGizGxjdi8m4e8WKjbwtzg4rdiiUGkLCu": 2000000000, + "3FZQMZsyypqDUk2r5katP1AUChe7Uzc9dC4": 2000000000, + "3FZs7eqZSmG56AqfTdWj2wJ1NWTrUZNgS6Q": 2000000000 + }, + "VRF": "5VjPUXb4NU9QQFoTsEET2xM9ncJfVzjQYZwpUQENStMH" +} \ No newline at end of file diff --git a/src/test/resources/stub/blocks/challenged_block.json b/src/test/resources/stub/blocks/challenged_block.json new file mode 100644 index 0000000..b7f5e14 --- /dev/null +++ b/src/test/resources/stub/blocks/challenged_block.json @@ -0,0 +1,43 @@ +{ + "version": 5, + "timestamp": 1766556383068, + "reference": "Cgiw4DxerYuir2Eb1J9Efao7MRv6mqNJhhb9DDFT1nyn", + "nxt-consensus": { + "base-target": 20313, + "generation-signature": "zSgfZWVSvDouvPpqn1x4DCaeozoBz9uxorMqmAk9JhgfqpkHa4KRySVfM8WGMnR3qwiQT2DKr7Yym9SeL9YgtLX5u7sa7VTzCtSFABJfLumrYYvberx7BcNtyCx8nUT86m1" + }, + "transactionsRoot": "HUS3QDVUEFXjrDZbUwNoW6zHXvieUfhCRf5fvaGRN3Ft", + "id": "8peDPrKBNC6cXkwXTTXgr18pR9rK8Kr3hmMPuL1M3Y4J", + "features": [], + "desiredReward": -1, + "generator": "3FmGmZaKHxjb2Q1rRc9KXJxirRtPUUQUdPe", + "generatorPublicKey": "BMY9f5tzFwtLPS2VeaKu12sunVo3ydMvXNd8cVNa5cE9", + "stateHash": "E5p1UQAg77FyoYVdt1NKVvczK6w5QNnZKvhN6fbRbs56", + "challengedHeader": { + "headerSignature": "52SXMJphW45QdshxfYUxH7w6FhXmGXU2zTmW6mDLvcaWVigKjtufQT7gTJ3gimKFx8mwKyGuTtzoMDf6CYWymjLE", + "features": [], + "generator": "3Fgtiv5L5q4CXFfwuAfbkjy9ppehkNzjbEG", + "generatorPublicKey": "5FUsFwB6b8mE61VMbSB6X7m23NTy4yN8f1fApXo8tZs7", + "desiredReward": -1, + "stateHash": "11111111111111111111111111111111", + "finalizationVoting": { + "endorserIndexes": [ + 2, + 1 + ], + "aggregatedEndorsementSignature": "yEuHinUSJCG8LdNtvtstKp7edVGrwMmGQQ8qf6ghWc8BB9oiJryCMVmsBQrAJQZX7i8cC1d5mqH2jYLJT2QeJ7QSbMGBAWueVcYhUzpoPtwvtG5NxZUcvTsRUjiZEWPT7uD", + "finalizedHeight": 40 + } + }, + "signature": "3MLuE6nDYH4AZEMsNJuNye3TyYn9rK1VLtzaiaxs73TpHTNqfXATwaq2vY8n2w23TnVYR8FMyRU3QYa1ekLKu1ar", + "blocksize": 981, + "transactionCount": 2, + "height": 42, + "totalFee": 200000, + "reward": 6000000000, + "rewardShares": { + "3FVGizGxjdi8m4e8WKjbwtzg4rdiiUGkLCu": 2000000000, + "3FmGmZaKHxjb2Q1rRc9KXJxirRtPUUQUdPe": 4000000000 + }, + "VRF": "8cVE9ye2suvz5Z6citp8WmAQzifrgmXD7WxUSix8Cqvp" +} \ No newline at end of file diff --git a/src/test/resources/stub/txs/commit_to_generation_tx.json b/src/test/resources/stub/txs/commit_to_generation_tx.json new file mode 100644 index 0000000..d042d9f --- /dev/null +++ b/src/test/resources/stub/txs/commit_to_generation_tx.json @@ -0,0 +1,18 @@ +{ + "id": "2r6kpnJbGqNTmLxi9cPuavgxqumGufnisnN8vhuSCpaX", + "type": 19, + "version": 1, + "chainId": 68, + "senderPublicKey": "Bn21Eg8HbwZWZQMHXnTFnb64MhVjgH2HygDekQDbjjMq", + "sender": "3FmjX4FAeDXE4ZdDj2JKxzE4QtbxaioXzxM", + "generationPeriodStart": 2941, + "endorserPublicKey": "5t9zL1oqXW6kL3YUAuF8r4rKUaPwohPVrpMWR8Y1bAJtSMipP3TQJYZvpBFB7GWZwo", + "commitmentSignature": "u9CTxLENQWyd5egnHrnbnnDKy7mvtrWJfR1AuCL4e4e7uuRTobzxVy1SQBz7ayoY5mRfiTG3PR8niJPT3fdVfsD97EkagBha8ehrLAzdutWSLbiQF2VDwPfi7uvTcp5csMC", + "fee": 10000000, + "feeAssetId": null, + "timestamp": 1766488084192, + "proofs": [ + "2H7TeCFEBSq6gb325Up2iZPr1jbZk99XugFijYTLbvgH2Ts8NQyCusG5p84FxKySEsVz7RUqsmQQJcCGU3xx75jt" + ], + "height": 73 +} \ No newline at end of file diff --git a/src/test/resources/stub/eth/eth_invoke_tx_from_block.json b/src/test/resources/stub/txs/eth/eth_invoke_tx_from_block.json similarity index 100% rename from src/test/resources/stub/eth/eth_invoke_tx_from_block.json rename to src/test/resources/stub/txs/eth/eth_invoke_tx_from_block.json diff --git a/src/test/resources/stub/eth/eth_invoke_tx_info.json b/src/test/resources/stub/txs/eth/eth_invoke_tx_info.json similarity index 100% rename from src/test/resources/stub/eth/eth_invoke_tx_info.json rename to src/test/resources/stub/txs/eth/eth_invoke_tx_info.json diff --git a/src/test/resources/stub/eth/eth_transfer_tx_from_block.json b/src/test/resources/stub/txs/eth/eth_transfer_tx_from_block.json similarity index 100% rename from src/test/resources/stub/eth/eth_transfer_tx_from_block.json rename to src/test/resources/stub/txs/eth/eth_transfer_tx_from_block.json diff --git a/src/test/resources/stub/eth/eth_transfer_tx_info.json b/src/test/resources/stub/txs/eth/eth_transfer_tx_info.json similarity index 100% rename from src/test/resources/stub/eth/eth_transfer_tx_info.json rename to src/test/resources/stub/txs/eth/eth_transfer_tx_info.json diff --git a/src/test/resources/stub/eth/exchange_tx_info_with_eth_sign.json b/src/test/resources/stub/txs/eth/exchange_tx_info_with_eth_sign.json similarity index 100% rename from src/test/resources/stub/eth/exchange_tx_info_with_eth_sign.json rename to src/test/resources/stub/txs/eth/exchange_tx_info_with_eth_sign.json diff --git a/src/test/resources/stub/eth/exchange_tx_with_eth_sign_from_block.json b/src/test/resources/stub/txs/eth/exchange_tx_with_eth_sign_from_block.json similarity index 100% rename from src/test/resources/stub/eth/exchange_tx_with_eth_sign_from_block.json rename to src/test/resources/stub/txs/eth/exchange_tx_with_eth_sign_from_block.json