Skip to content

Commit

Permalink
Merge pull request #136 from onflow/get-account-key-endpoints
Browse files Browse the repository at this point in the history
Get account key endpoints
  • Loading branch information
lealobanov authored Oct 30, 2024
2 parents 56be671 + 0a8e1c9 commit 662759b
Show file tree
Hide file tree
Showing 18 changed files with 1,332 additions and 411 deletions.
5 changes: 5 additions & 0 deletions java-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Below is a list of all Java code examples currently supported in this repo:
- Get account balance
- Get account from the latest block
- Get account from block by height
- Get account key at latest block
- Get account keys at latest block
- Get account key at block height
- Get account keys at block height

#### Get Events

Expand Down Expand Up @@ -80,6 +84,7 @@ Below is a list of all Java code examples currently supported in this repo:

- Get transaction
- Get transaction result
- Get transaction result by index

#### Sending Transactions

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.onflow.examples.java.getAccountKeys;

import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowAccountKey;
import org.onflow.flow.sdk.FlowAddress;

import java.util.List;

public class GetAccountKeysAccessAPIConnector {
private final FlowAccessApi accessAPI;

public GetAccountKeysAccessAPIConnector(FlowAccessApi accessAPI) {
this.accessAPI = accessAPI;
}

public FlowAccountKey getAccountKeyAtLatestBlock(FlowAddress address, int keyIndex) {
FlowAccessApi.AccessApiCallResponse<FlowAccountKey> response = accessAPI.getAccountKeyAtLatestBlock(address, keyIndex);

if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowAccountKey>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

public FlowAccountKey getAccountKeyAtBlockHeight(FlowAddress address, int keyIndex, long height) {
FlowAccessApi.AccessApiCallResponse<FlowAccountKey> response = accessAPI.getAccountKeyAtBlockHeight(address, keyIndex, height);

if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowAccountKey>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

public List<FlowAccountKey> getAccountKeysAtLatestBlock(FlowAddress address) {
FlowAccessApi.AccessApiCallResponse<List<FlowAccountKey>> response = accessAPI.getAccountKeysAtLatestBlock(address);

if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<List<FlowAccountKey>>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

public List<FlowAccountKey> getAccountKeysAtBlockHeight(FlowAddress address, long height) {
FlowAccessApi.AccessApiCallResponse<List<FlowAccountKey>> response = accessAPI.getAccountKeysAtBlockHeight(address, height);

if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<List<FlowAccountKey>>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,14 @@ public FlowTransactionResult getTransactionResult(FlowId txID) {
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

public FlowTransactionResult getTransactionResultByIndex(FlowId blockId, Integer index) {
FlowAccessApi.AccessApiCallResponse<FlowTransactionResult> response = accessAPI.getTransactionResultByIndex(blockId, index);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowTransactionResult>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.onflow.examples.java.getAccountKeys;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.onflow.flow.common.test.FlowEmulatorProjectTest;
import org.onflow.flow.common.test.FlowServiceAccountCredentials;
import org.onflow.flow.common.test.FlowTestClient;
import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowAddress;
import org.onflow.flow.sdk.FlowAccountKey;
import org.onflow.flow.common.test.TestAccount;
import org.onflow.flow.sdk.FlowBlock;

import java.util.List;

@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json")
public class GetAccountKeysAccessAPIConnectorTest {
@FlowTestClient
private FlowAccessApi accessAPI;

@FlowServiceAccountCredentials
private TestAccount serviceAccount;

private GetAccountKeysAccessAPIConnector keysAPIConnector;

@BeforeEach
public void setup() {
keysAPIConnector = new GetAccountKeysAccessAPIConnector(accessAPI);
}

@Test
public void testCanFetchAccountKeyAtLatestBlock() {
FlowAddress address = serviceAccount.getFlowAddress();
int keyIndex = 0;

FlowAccountKey accountKey = keysAPIConnector.getAccountKeyAtLatestBlock(address, keyIndex);

Assertions.assertNotNull(accountKey, "Account key should not be null");
Assertions.assertEquals(keyIndex, accountKey.getSequenceNumber(), "Account key index should match the requested index");
Assertions.assertTrue(accountKey.getWeight() > 0, "Account key weight should be positive");
}

@Test
public void testCanFetchAccountKeyAtSpecificBlockHeight() {
FlowAddress address = serviceAccount.getFlowAddress();
int keyIndex = 0;

FlowAccessApi.AccessApiCallResponse<FlowBlock> latestBlockResponse = accessAPI.getLatestBlock(true, false);

if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) {
FlowBlock latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success<FlowBlock>) latestBlockResponse).getData();
FlowAccountKey accountKey = keysAPIConnector.getAccountKeyAtBlockHeight(address, keyIndex, latestBlock.getHeight());

Assertions.assertNotNull(accountKey, "Account key at specific block height should not be null");
Assertions.assertEquals(keyIndex, accountKey.getSequenceNumber(), "Account key index at specific block height should match requested index");
Assertions.assertTrue(accountKey.getWeight() > 0, "Account key weight should be positive");

} else if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Error error) {
throw new RuntimeException("Failed to retrieve the latest block: " + error.getMessage(), error.getThrowable());
}
}

@Test
public void testCanFetchAllAccountKeysAtLatestBlock() {
FlowAddress address = serviceAccount.getFlowAddress();

List<FlowAccountKey> accountKeys = keysAPIConnector.getAccountKeysAtLatestBlock(address);

Assertions.assertNotNull(accountKeys, "Account keys list should not be null");
Assertions.assertFalse(accountKeys.isEmpty(), "Account keys list should not be empty");
accountKeys.forEach(key -> Assertions.assertTrue(key.getWeight() > 0, "Each account key weight should be positive"));
}

@Test
public void testCanFetchAllAccountKeysAtSpecificBlockHeight() {
FlowAddress address = serviceAccount.getFlowAddress();

FlowAccessApi.AccessApiCallResponse<FlowBlock> latestBlockResponse = accessAPI.getLatestBlock(true, false);

if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) {
FlowBlock latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success<FlowBlock>) latestBlockResponse).getData();
List<FlowAccountKey> accountKeys = keysAPIConnector.getAccountKeysAtBlockHeight(address, latestBlock.getHeight());

Assertions.assertNotNull(accountKeys, "Account keys list at specific block height should not be null");
Assertions.assertFalse(accountKeys.isEmpty(), "Account keys list at specific block height should not be empty");
accountKeys.forEach(key -> Assertions.assertTrue(key.getWeight() > 0, "Each account key weight should be positive"));
} else if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Error error) {
throw new RuntimeException("Failed to retrieve the latest block: " + error.getMessage(), error.getThrowable());
}
}

@Test
public void testAccountKeysMatchAtLatestBlockAndSpecificBlockHeight() {
FlowAddress address = serviceAccount.getFlowAddress();

List<FlowAccountKey> keysAtLatestBlock = keysAPIConnector.getAccountKeysAtLatestBlock(address);

FlowAccessApi.AccessApiCallResponse<FlowBlock> latestBlockResponse = accessAPI.getLatestBlock(true, false);

if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) {
FlowBlock latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success<FlowBlock>) latestBlockResponse).getData();
List<FlowAccountKey> keysAtSpecificHeight = keysAPIConnector.getAccountKeysAtBlockHeight(address, latestBlock.getHeight());

Assertions.assertEquals(keysAtLatestBlock.size(), keysAtSpecificHeight.size(), "Number of account keys should match at latest block and specific block height");

for (int i = 0; i < keysAtLatestBlock.size(); i++) {
Assertions.assertEquals(keysAtLatestBlock.get(i), keysAtSpecificHeight.get(i), "Account key at index " + i + " should match between latest block and specific block height");
}
} else if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Error error) {
throw new RuntimeException("Failed to retrieve the latest block: " + error.getMessage(), error.getThrowable());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@
import org.onflow.flow.common.test.FlowServiceAccountCredentials;
import org.onflow.flow.common.test.FlowTestClient;
import org.onflow.flow.common.test.TestAccount;
import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowId;
import org.onflow.flow.sdk.FlowTransaction;
import org.onflow.flow.sdk.FlowTransactionResult;
import org.onflow.flow.sdk.FlowTransactionStatus;
import org.onflow.flow.sdk.*;
import org.onflow.flow.sdk.crypto.Crypto;
import org.onflow.flow.sdk.crypto.PublicKey;
import org.onflow.flow.sdk.SignatureAlgorithm;

import static org.junit.jupiter.api.Assertions.*;

Expand All @@ -26,6 +21,7 @@ public class GetTransactionAccessAPIConnectorTest {
private FlowAccessApi accessAPI;
private GetTransactionAccessAPIConnector connector;
private FlowId txID;
private FlowBlock block;

@BeforeEach
public void setup() {
Expand All @@ -38,6 +34,14 @@ public void setup() {
serviceAccount.getFlowAddress(),
publicKey
);

FlowAccessApi.AccessApiCallResponse<FlowBlock> response = accessAPI.getLatestBlock(true, false);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
block = ((FlowAccessApi.AccessApiCallResponse.Success<FlowBlock>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

@Test
Expand All @@ -55,4 +59,12 @@ public void canFetchTransactionResult() {
assertNotNull(transactionResult, "Transaction result should not be null");
assertSame(transactionResult.getStatus(), FlowTransactionStatus.SEALED, "Transaction should be sealed");
}

@Test
public void canFetchTransactionResultByIndex() {
FlowTransactionResult transactionResult = connector.getTransactionResultByIndex(block.getId(),0);

assertNotNull(transactionResult, "Transaction result should not be null");
assertSame(transactionResult.getStatus(), FlowTransactionStatus.SEALED, "Transaction should be sealed");
}
}
5 changes: 5 additions & 0 deletions kotlin-example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Below is a list of all Kotlin code examples currently supported in this repo:
- Get account balance
- Get account from the latest block
- Get account from block by height
- Get account key at latest block
- Get account keys at latest block
- Get account key at block height
- Get account keys at block height

#### Get Events

Expand Down Expand Up @@ -81,6 +85,7 @@ Below is a list of all Kotlin code examples currently supported in this repo:

- Get transaction
- Get transaction result
- Get transaction result by index

#### Sending Transactions

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.onflow.examples.kotlin.getAccountKeys

import org.onflow.flow.sdk.*

internal class GetAccountKeysAccessAPIConnector(
private val accessAPI: FlowAccessApi
) {
fun getAccountKeyAtLatestBlock(address: FlowAddress, keyIndex: Int): FlowAccountKey =
when (val response = accessAPI.getAccountKeyAtLatestBlock(address, keyIndex)) {
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}

fun getAccountKeyAtBlockHeight(address: FlowAddress, keyIndex: Int, height: Long): FlowAccountKey =
when (val response = accessAPI.getAccountKeyAtBlockHeight(address, keyIndex, height)) {
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}

fun getAccountKeysAtLatestBlock(address: FlowAddress): List<FlowAccountKey> =
when (val response = accessAPI.getAccountKeysAtLatestBlock(address)) {
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}

fun getAccountKeysAtBlockHeight(address: FlowAddress, height: Long): List<FlowAccountKey> =
when (val response = accessAPI.getAccountKeysAtBlockHeight(address, height)) {
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ class GetTransactionAccessAPIConnector(
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}

fun getTransactionResultByIndex(blockId: FlowId, index: Int): FlowTransactionResult =
when (val response = accessAPI.getTransactionResultByIndex(blockId, index)) {
is FlowAccessApi.AccessApiCallResponse.Success -> response.data
is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
}
}
Loading

0 comments on commit 662759b

Please sign in to comment.