Skip to content

Commit

Permalink
Stabilize HapiSpec ledger id assertions (#8703)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Tinker <[email protected]>
  • Loading branch information
tinker-michaelj authored Sep 19, 2023
1 parent d1c5a53 commit a4ee62a
Show file tree
Hide file tree
Showing 20 changed files with 148 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ files.throttleDefinitions=123
hedera.firstUserEntity=1001
hedera.realm=0
hedera.shard=0
ledger.id=0x03
ledger.id=0x00
ledger.numSystemAccounts=100
ledger.totalTinyBarFloat=5000000000000000000
staking.maxStakeRewarded=5000000000000000000
Expand Down Expand Up @@ -76,7 +76,7 @@ contracts.freeStorageTierLimit=100
contracts.itemizeStorageFees=true
contracts.keys.legacyActivations=1058134by[1062784]
contracts.knownBlockHash=
contracts.localCall.estRetBytes=32
contracts.localCall.estRetBytes=4096
contracts.maxGasPerSec=15000000
contracts.maxKvPairs.aggregate=500_000_000
contracts.maxKvPairs.individual=163_840
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public abstract class HapiSpecOperation {
protected boolean useRandomNode = false;
protected boolean unavailableNode = false;
protected Set<HederaFunctionality> skipIfAutoScheduling = Collections.emptySet();
protected Optional<String> expectedLedgerId = Optional.empty();
protected Optional<ByteString> expectedLedgerId = Optional.empty();
protected Optional<Integer> hardcodedNumPayerKeys = Optional.empty();
protected Optional<SigMapGenerator> sigMapGen = Optional.empty();
protected Optional<List<Function<HapiSpec, Key>>> signers = Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static java.lang.Thread.sleep;
import static java.util.stream.Collectors.toList;

import com.google.protobuf.ByteString;
import com.hedera.node.app.hapi.utils.fee.SigValueObj;
import com.hedera.services.bdd.spec.HapiPropertySource;
import com.hedera.services.bdd.spec.HapiSpec;
Expand Down Expand Up @@ -417,7 +418,7 @@ public T numPayerSigs(int hardcoded) {
return self();
}

public T hasExpectedLedgerId(String ledgerId) {
public T hasEncodedLedgerId(ByteString ledgerId) {
this.expectedLedgerId = Optional.of(ledgerId);
return self();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ protected void assertExpectationsGiven(HapiSpec spec) {
if (hasNoAdminKey) {
assertFalse(info.hasAdminKey(), "Should have no admin key!");
}
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(rationalize(id), info.getLedgerId()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(id, info.getLedgerId()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected void assertExpectationsGiven(HapiSpec spec) throws Throwable {
var actualTokenRels = actualInfo.getTokenRelationshipsList();
assertExpectedRels(contract, relationships, actualTokenRels, spec);
assertNoUnexpectedRels(contract, absentRelationships, actualTokenRels, spec);
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(rationalize(id), actualInfo.getLedgerId()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(id, actualInfo.getLedgerId()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ protected void assertExpectationsGiven(HapiSpec spec) throws Throwable {
}
assertEquals(actualCount, usedCount);
});
expectedLedgerId.ifPresent(id -> assertEquals(rationalize(id), details.getLedgerId()));
expectedLedgerId.ifPresent(id -> assertEquals(id, details.getLedgerId()));

tokenAssociationsCount.ifPresent(count -> assertEquals(count, details.getTokenRelationshipsCount()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public class HapiGetAccountInfo extends HapiQueryOp<HapiGetAccountInfo> {
@Nullable
private Consumer<byte[]> aliasObserver = null;

@Nullable
private Consumer<ByteString> ledgerIdObserver = null;

private Optional<Consumer<String>> contractAccountIdObserver = Optional.empty();
private Optional<Integer> tokenAssociationsCount = Optional.empty();
private boolean assertAliasKeyMatches = false;
Expand Down Expand Up @@ -139,6 +142,11 @@ public HapiGetAccountInfo exposingAliasTo(Consumer<byte[]> obs) {
return this;
}

public HapiGetAccountInfo exposingLedgerIdTo(Consumer<ByteString> obs) {
this.ledgerIdObserver = obs;
return this;
}

public HapiGetAccountInfo exposingContractAccountIdTo(Consumer<String> obs) {
this.contractAccountIdObserver = Optional.of(obs);
return this;
Expand Down Expand Up @@ -240,7 +248,7 @@ protected void assertExpectationsGiven(HapiSpec spec) throws Throwable {
}
assertEquals(actualCount, usedCount);
});
expectedLedgerId.ifPresent(id -> assertEquals(rationalize(id), actualInfo.getLedgerId()));
expectedLedgerId.ifPresent(id -> assertEquals(id, actualInfo.getLedgerId()));

tokenAssociationsCount.ifPresent(count -> assertEquals(count, actualInfo.getTokenRelationshipsCount()));
}
Expand Down Expand Up @@ -275,6 +283,8 @@ protected void submitWith(HapiSpec spec, Transaction payment) throws Throwable {
Optional.ofNullable(aliasObserver)
.ifPresent(cb ->
cb.accept(infoResponse.getAccountInfo().getAlias().toByteArray()));
Optional.ofNullable(ledgerIdObserver)
.ifPresent(cb -> cb.accept(infoResponse.getAccountInfo().getLedgerId()));
contractAccountIdObserver.ifPresent(
cb -> cb.accept(infoResponse.getAccountInfo().getContractAccountID()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ protected void assertExpectationsGiven(HapiSpec spec) throws Throwable {
expiryTest.ifPresent(
p -> Assertions.assertTrue(p.test(actual), String.format("Expiry of %d was not as expected!", actual)));
expectedMemo.ifPresent(e -> Assertions.assertEquals(e, info.getMemo()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(rationalize(id), info.getLedgerId()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(id, info.getLedgerId()));
}

private Query getFileInfoQuery(HapiSpec spec, Transaction payment, boolean costOnly) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ protected void assertExpectationsGiven(HapiSpec spec) {
"Wrong schedule admin key!",
registry);

expectedLedgerId.ifPresent(id -> Assertions.assertEquals(rationalize(id), actualInfo.getLedgerId()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(id, actualInfo.getLedgerId()));
}

private void assertTimestampMatches(String txn, int nanoOffset, Timestamp actual, String errMsg, HapiSpec spec) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ protected void assertExpectationsGiven(HapiSpec spec) {
"Wrong token pause key!",
registry);

expectedLedgerId.ifPresent(id -> Assertions.assertEquals(rationalize(id), actualInfo.getLedgerId()));
expectedLedgerId.ifPresent(id -> Assertions.assertEquals(id, actualInfo.getLedgerId()));
}

private <T, R> void assertFor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected void assertExpectationsGiven(HapiSpec spec) throws Throwable {
"Wrong token id!",
registry);

expectedLedgerId.ifPresent(id -> assertEquals(rationalize(id), actualInfo.getLedgerId()));
expectedLedgerId.ifPresent(id -> assertEquals(id, actualInfo.getLedgerId()));
}

private <T, R> void assertFor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.hedera.services.bdd.spec.assertions.ContractInfoAsserts.contractWith;
import static com.hedera.services.bdd.spec.assertions.TransactionRecordAsserts.recordWith;
import static com.hedera.services.bdd.spec.queries.QueryVerbs.getAccountBalance;
import static com.hedera.services.bdd.spec.queries.QueryVerbs.getAccountInfo;
import static com.hedera.services.bdd.spec.queries.QueryVerbs.getContractInfo;
import static com.hedera.services.bdd.spec.queries.QueryVerbs.getFileContents;
import static com.hedera.services.bdd.spec.queries.QueryVerbs.getTxnRecord;
Expand Down Expand Up @@ -140,6 +141,7 @@
import com.hederahashgraph.api.proto.java.Transaction;
import com.hederahashgraph.api.proto.java.TransactionBody;
import com.hederahashgraph.api.proto.java.TransactionRecord;
import com.swirlds.common.utility.CommonUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -308,6 +310,49 @@ public static CustomSpecAssert withOpContext(CustomSpecAssert.ThrowingConsumer c
return new CustomSpecAssert(custom);
}

private static final ByteString MAINNET_LEDGER_ID = ByteString.copyFrom(new byte[] {0x00});
private static final ByteString TESTNET_LEDGER_ID = ByteString.copyFrom(new byte[] {0x01});
private static final ByteString PREVIEWNET_LEDGER_ID = ByteString.copyFrom(new byte[] {0x02});
private static final ByteString DEVNET_LEDGER_ID = ByteString.copyFrom(new byte[] {0x03});

private static final Set<ByteString> RECOGNIZED_LEDGER_IDS =
Set.of(MAINNET_LEDGER_ID, TESTNET_LEDGER_ID, PREVIEWNET_LEDGER_ID, DEVNET_LEDGER_ID);

/**
* Returns an operation that uses a {@link com.hedera.services.bdd.spec.queries.crypto.HapiGetAccountInfo} query
* against the {@code 0.0.2} account to look up the ledger id of the target network; and then passes the ledger
* id to the given callback.
*
* @param ledgerIdConsumer the callback to pass the ledger id to
* @return the operation exposing the ledger id to the callback
*/
public static HapiSpecOperation exposeTargetLedgerIdTo(@NonNull final Consumer<ByteString> ledgerIdConsumer) {
return getAccountInfo(GENESIS).payingWith(GENESIS).exposingLedgerIdTo(ledgerId -> {
if (!RECOGNIZED_LEDGER_IDS.contains(ledgerId)) {
Assertions.fail(
"Target network is claiming unrecognized ledger id " + CommonUtils.hex(ledgerId.toByteArray()));
}
ledgerIdConsumer.accept(ledgerId);
});
}

/**
* A convenience operation that accepts a factory mapping the target ledger id into a {@link HapiSpecOperation}
* (for example, a query that asserts something about the ledger id); and then,
* <ol>
* <Li>Looks up the ledger id via {@link UtilVerbs#exposeTargetLedgerIdTo(Consumer)}; and,</Li>
* <Li>Calls the given factory with this id, and runs the resulting {@link HapiSpecOperation}.</Li>
* </ol>
*
* @param opFn the factory mapping the ledger id into a {@link HapiSpecOperation}
* @return the operation that looks up the ledger id and runs the resulting {@link HapiSpecOperation}
*/
public static HapiSpecOperation withTargetLedgerId(@NonNull final Function<ByteString, HapiSpecOperation> opFn) {
final AtomicReference<ByteString> targetLedgerId = new AtomicReference<>();
return blockingOrder(
exposeTargetLedgerIdTo(targetLedgerId::set), sourcing(() -> opFn.apply(targetLedgerId.get())));
}

public static BalanceSnapshot balanceSnapshot(String name, String forAccount) {
return new BalanceSnapshot(forAccount, name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,18 @@
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.deleteTopic;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.submitMessageTo;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.updateTopic;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.exposeTargetLedgerIdTo;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.sourcing;
import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_TOPIC_ID;

import com.google.protobuf.ByteString;
import com.hedera.services.bdd.junit.HapiTest;
import com.hedera.services.bdd.junit.HapiTestSuite;
import com.hedera.services.bdd.spec.HapiSpec;
import com.hedera.services.bdd.suites.HapiSuite;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand Down Expand Up @@ -59,6 +63,7 @@ public boolean canRunConcurrent() {
@HapiTest
private HapiSpec allFieldsSetHappyCase() {
// sequenceNumber should be 0 and runningHash should be 48 bytes all 0s.
final AtomicReference<ByteString> targetLedgerId = new AtomicReference<>();
return defaultHapiSpec("AllFieldsSetHappyCase")
.given(
newKeyNamed("adminKey"),
Expand All @@ -73,41 +78,42 @@ private HapiSpec allFieldsSetHappyCase() {
.via("createTopic"))
.when()
.then(
getTopicInfo(TEST_TOPIC)
.hasExpectedLedgerId("0x03")
exposeTargetLedgerIdTo(targetLedgerId::set),
sourcing(() -> getTopicInfo(TEST_TOPIC)
.hasEncodedLedgerId(targetLedgerId.get())
.hasMemo(TESTMEMO)
.hasAdminKey("adminKey")
.hasSubmitKey("submitKey")
.hasAutoRenewAccount("autoRenewAccount")
.hasSeqNo(0)
.hasRunningHash(new byte[48]),
.hasRunningHash(new byte[48])),
getTxnRecord("createTopic").logged(),
submitMessageTo(TEST_TOPIC)
.blankMemo()
.payingWith("payer")
.message(new String("test".getBytes()))
.via("submitMessage"),
getTxnRecord("submitMessage").logged(),
getTopicInfo(TEST_TOPIC)
.hasExpectedLedgerId("0x03")
sourcing(() -> getTopicInfo(TEST_TOPIC)
.hasEncodedLedgerId(targetLedgerId.get())
.hasMemo(TESTMEMO)
.hasAdminKey("adminKey")
.hasSubmitKey("submitKey")
.hasAutoRenewAccount("autoRenewAccount")
.hasSeqNo(1)
.logged(),
.logged()),
updateTopic(TEST_TOPIC)
.topicMemo("Don't worry about the vase")
.via("updateTopic"),
getTxnRecord("updateTopic").logged(),
getTopicInfo(TEST_TOPIC)
.hasExpectedLedgerId("0x03")
sourcing(() -> getTopicInfo(TEST_TOPIC)
.hasEncodedLedgerId(targetLedgerId.get())
.hasMemo("Don't worry about the vase")
.hasAdminKey("adminKey")
.hasSubmitKey("submitKey")
.hasAutoRenewAccount("autoRenewAccount")
.hasSeqNo(1)
.logged(),
.logged()),
deleteTopic(TEST_TOPIC).via("deleteTopic"),
getTxnRecord("deleteTopic").logged(),
getTopicInfo(TEST_TOPIC)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,11 +1121,7 @@ HapiSpec ocToken() {

ctxLog.info("symbol: [{}]", symbol);

Assertions.assertEquals("", symbol, "TokenIssuer's symbol should be fixed value"); // should
// be
// "OCT"
// as
// expected
Assertions.assertEquals("OCT", symbol, "TokenIssuer's symbol should be fixed value");
final var funcDecimals = Function.fromJson(getABIFor(FUNCTION, DECIMALS, contract));

final Integer decimals = getValueFromRegistry(spec, DECIMALS, funcDecimals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.contractCreate;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.uploadInitCode;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.withTargetLedgerId;

import com.hedera.services.bdd.junit.HapiTest;
import com.hedera.services.bdd.junit.HapiTestSuite;
Expand Down Expand Up @@ -68,10 +69,10 @@ private HapiSpec getInfoWorks() {
.entityMemo(MEMO)
.autoRenewSecs(6999999L))
.when()
.then(getContractInfo(contract)
.hasExpectedLedgerId("0x03")
.then(withTargetLedgerId(ledgerId -> getContractInfo(contract)
.hasEncodedLedgerId(ledgerId)
.hasExpectedInfo()
.has(contractWith().memo(MEMO).adminKey("adminKey")));
.has(contractWith().memo(MEMO).adminKey("adminKey"))));
}

@HapiTest
Expand Down
Loading

0 comments on commit a4ee62a

Please sign in to comment.