Skip to content

Commit

Permalink
feat: Add multisig and timed integration tests
Browse files Browse the repository at this point in the history
Signed-off-by: gsstoykov <[email protected]>
  • Loading branch information
gsstoykov committed Dec 10, 2024
1 parent 4c54b7c commit 2aa8b4d
Showing 1 changed file with 183 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
#include "AccountBalance.h"
#include "AccountBalanceQuery.h"
#include "AccountCreateTransaction.h"
#include "AccountUpdateTransaction.h"
#include "BaseIntegrationTest.h"
#include "ED25519PrivateKey.h"
#include "PrivateKey.h"
Expand Down Expand Up @@ -184,10 +187,12 @@ TEST_F(ScheduleCreateTransactionIntegrationTests, CanSignScheduleAndWaitForExpir
.getReceipt(getTestClient())
.mAccountId.value());

// Create the transaction
const WrappedTransaction scheduledTransaction(
TransferTransaction().addHbarTransfer(accountId, Hbar(-5LL)).addHbarTransfer(AccountId(2ULL), Hbar(5LL)));

// When
// Schedule the transaction
TransactionReceipt txReceipt;
EXPECT_NO_THROW(txReceipt = ScheduleCreateTransaction()
.setScheduledTransaction(scheduledTransaction)
Expand All @@ -202,10 +207,12 @@ TEST_F(ScheduleCreateTransactionIntegrationTests, CanSignScheduleAndWaitForExpir
ASSERT_TRUE(txReceipt.mScheduleId.has_value());
const ScheduleId scheduleId = txReceipt.mScheduleId.value();

// Check if transaction is scheduled
ScheduleInfo scheduleInfo;
EXPECT_NO_THROW(scheduleInfo =
ScheduleInfoQuery().setScheduleId(txReceipt.mScheduleId.value()).execute(getTestClient()));

// Sign with the key
EXPECT_NO_THROW(txReceipt = ScheduleSignTransaction()
.setScheduleId(scheduleId)
.freezeWith(&getTestClient())
Expand Down Expand Up @@ -242,10 +249,12 @@ TEST_F(ScheduleCreateTransactionIntegrationTests, CannotScheduleOneYearIntoTheFu
.getReceipt(getTestClient())
.mAccountId.value());

// Create the transaction
const WrappedTransaction scheduledTransaction(
TransferTransaction().addHbarTransfer(accountId, Hbar(-5LL)).addHbarTransfer(AccountId(2ULL), Hbar(5LL)));

// When / Then
// Schedule the transaction
TransactionReceipt txReceipt;
EXPECT_THROW(txReceipt = ScheduleCreateTransaction()
.setScheduledTransaction(scheduledTransaction)
Expand Down Expand Up @@ -285,10 +294,12 @@ TEST_F(ScheduleCreateTransactionIntegrationTests, CannotScheduleInThePast)
.getReceipt(getTestClient())
.mAccountId.value());

// Create the transaction
const WrappedTransaction scheduledTransaction(
TransferTransaction().addHbarTransfer(accountId, Hbar(-5LL)).addHbarTransfer(AccountId(2ULL), Hbar(5LL)));

// When / Then
// Schedule the transaction
TransactionReceipt txReceipt;
EXPECT_THROW(txReceipt = ScheduleCreateTransaction()
.setScheduledTransaction(scheduledTransaction)
Expand All @@ -307,4 +318,175 @@ TEST_F(ScheduleCreateTransactionIntegrationTests, CannotScheduleInThePast)
.sign(newKey)
.execute(getTestClient())
.getReceipt(getTestClient()));
}
}

//-----
TEST_F(ScheduleCreateTransactionIntegrationTests, CanSignWithMultisigAndUpdateSigningRequirements)
{
// Given
std::shared_ptr<PrivateKey> operatorKey;

ASSERT_NO_THROW(
operatorKey = ED25519PrivateKey::fromString(
"302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137"));

// Generate three ED25519 private keys.
const std::vector<std::shared_ptr<PrivateKey>> privateKeys = { ED25519PrivateKey::generatePrivateKey(),
ED25519PrivateKey::generatePrivateKey(),
ED25519PrivateKey::generatePrivateKey() };

// Create a Keylist from the list of generated private keys that require 2 of the 3 keys to sign.
auto keys = std::make_shared<KeyList>(KeyList::of({ privateKeys.at(0), privateKeys.at(1), privateKeys.at(2) }));
keys->setThreshold(2);

AccountId accountId;
ASSERT_NO_THROW(accountId = AccountCreateTransaction()
.setKey(keys)
.setInitialBalance(Hbar(10LL))
.execute(getTestClient())
.getReceipt(getTestClient())
.mAccountId.value());

// Create the transaction
const WrappedTransaction scheduledTransaction(
TransferTransaction().addHbarTransfer(accountId, Hbar(-5LL)).addHbarTransfer(AccountId(2ULL), Hbar(5LL)));

// When
// Schedule the transaction
TransactionReceipt txReceipt;
EXPECT_NO_THROW(txReceipt = ScheduleCreateTransaction()
.setScheduledTransaction(scheduledTransaction)
.setExpirationTime(std::chrono::system_clock::now() + std::chrono::hours(1))
.setAdminKey(operatorKey)
.setPayerAccountId(AccountId(2ULL))
.execute(getTestClient())
.getReceipt(getTestClient()));

ASSERT_TRUE(txReceipt.mScheduleId.has_value());
const ScheduleId scheduleId = txReceipt.mScheduleId.value();

// Verify the transaction is not executed
ScheduleInfo scheduleInfo;
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), false);

// Sign with one key
EXPECT_NO_THROW(txReceipt = ScheduleSignTransaction()
.setScheduleId(scheduleId)
.freezeWith(&getTestClient())
.sign(privateKeys[0])
.execute(getTestClient())
.getReceipt(getTestClient()));

// Verify the transaction is still not executed
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), false);

// Update the signing requirements
ASSERT_NO_THROW(AccountUpdateTransaction()
.setAccountId(accountId)
.setKey(privateKeys[0]->getPublicKey())
.freezeWith(&getTestClient())
.sign(privateKeys[0])
.sign(privateKeys[1])
.execute(getTestClient())
.getReceipt(getTestClient()));

// Verify the transaction is still not executed
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), false);

// Then
// Sign with one more key
EXPECT_NO_THROW(txReceipt = ScheduleSignTransaction()
.setScheduleId(scheduleId)
.freezeWith(&getTestClient())
.sign(privateKeys[1])
.execute(getTestClient())
.getReceipt(getTestClient()));

// Verify the transaction is executed
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), true);
}

//-----
TEST_F(ScheduleCreateTransactionIntegrationTests, CanExecuteWithShortExpirationTime)
{
// Given
std::shared_ptr<PrivateKey> operatorKey;
std::shared_ptr<PrivateKey> newKey;
ASSERT_NO_THROW(
operatorKey = ED25519PrivateKey::fromString(
"302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137"));
ASSERT_NO_THROW(newKey = ED25519PrivateKey::generatePrivateKey());

AccountId accountId;
ASSERT_NO_THROW(accountId = AccountCreateTransaction()
.setKey(newKey)
.setInitialBalance(Hbar(10LL))
.execute(getTestClient())
.getReceipt(getTestClient())
.mAccountId.value());

const WrappedTransaction scheduledTransaction(
TransferTransaction().addHbarTransfer(accountId, Hbar(-5LL)).addHbarTransfer(AccountId(2ULL), Hbar(5LL)));

// When
TransactionReceipt txReceipt;
EXPECT_NO_THROW(txReceipt = ScheduleCreateTransaction()
.setScheduledTransaction(scheduledTransaction)
.setWaitForExpiry(true)
.setExpirationTime(std::chrono::system_clock::now() + std::chrono::seconds(5))
.setAdminKey(operatorKey)
.setPayerAccountId(AccountId(2ULL))
.execute(getTestClient())
.getReceipt(getTestClient()));

ASSERT_TRUE(txReceipt.mScheduleId.has_value());
const ScheduleId scheduleId = txReceipt.mScheduleId.value();

ScheduleInfo scheduleInfo;
// Verify the transaction is still not executed
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), false);

EXPECT_NO_THROW(txReceipt = ScheduleSignTransaction()
.setScheduleId(scheduleId)
.freezeWith(&getTestClient())
.sign(newKey)
.execute(getTestClient())
.getReceipt(getTestClient()));

// Verify the transaction is still not executed
EXPECT_NO_THROW(scheduleInfo = ScheduleInfoQuery().setScheduleId(scheduleId).execute(getTestClient()));

ASSERT_EQ(scheduleInfo.mExecutionTime.has_value(), false);

AccountBalance accountBalanceBefore;
EXPECT_NO_THROW(accountBalanceBefore = AccountBalanceQuery().setAccountId(accountId).execute(getTestClient()));

// Then
// Sleep for 5 seconds so transaction can execute
std::this_thread::sleep_for(std::chrono::seconds(6));

// Verify the transaction is executed
AccountBalance accountBalanceAfter;
EXPECT_NO_THROW(accountBalanceAfter = AccountBalanceQuery().setAccountId(accountId).execute(getTestClient()));

ASSERT_NE(accountBalanceBefore.mBalance.toTinybars(), accountBalanceAfter.mBalance.toTinybars());

// Clean up
ASSERT_NO_THROW(txReceipt = AccountDeleteTransaction()
.setDeleteAccountId(accountId)
.setTransferAccountId(AccountId(2ULL))
.freezeWith(&getTestClient())
.sign(newKey)
.execute(getTestClient())
.getReceipt(getTestClient()));
}

0 comments on commit 2aa8b4d

Please sign in to comment.