forked from Qortal/qortal
Add Qortal AT FunctionCodes for getting account level / blocks minted + tests
This commit is contained in:
parent
d9de27e6f2
commit
eb9b94b9c6
@ -205,6 +205,12 @@ public class Account {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns account's blockMinted (0+) or null if account not found in repository. */
|
||||||
|
public Integer getBlocksMinted() throws DataException {
|
||||||
|
return this.repository.getAccountRepository().getMintedBlockCount(this.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns whether account can build reward-shares.
|
/** Returns whether account can build reward-shares.
|
||||||
* <p>
|
* <p>
|
||||||
* To be able to create reward-shares, the account needs to pass at least one of these tests:<br>
|
* To be able to create reward-shares, the account needs to pass at least one of these tests:<br>
|
||||||
|
@ -551,7 +551,7 @@ public class QortalATAPI extends API {
|
|||||||
* <p>
|
* <p>
|
||||||
* Otherwise, assume B is a public key.
|
* Otherwise, assume B is a public key.
|
||||||
*/
|
*/
|
||||||
private Account getAccountFromB(MachineState state) {
|
/*package*/ Account getAccountFromB(MachineState state) {
|
||||||
byte[] bBytes = this.getB(state);
|
byte[] bBytes = this.getB(state);
|
||||||
|
|
||||||
if ((bBytes[0] == Crypto.ADDRESS_VERSION || bBytes[0] == Crypto.AT_ADDRESS_VERSION)
|
if ((bBytes[0] == Crypto.ADDRESS_VERSION || bBytes[0] == Crypto.AT_ADDRESS_VERSION)
|
||||||
|
@ -10,9 +10,11 @@ import org.ciyam.at.ExecutionException;
|
|||||||
import org.ciyam.at.FunctionData;
|
import org.ciyam.at.FunctionData;
|
||||||
import org.ciyam.at.IllegalFunctionCodeException;
|
import org.ciyam.at.IllegalFunctionCodeException;
|
||||||
import org.ciyam.at.MachineState;
|
import org.ciyam.at.MachineState;
|
||||||
|
import org.qortal.account.Account;
|
||||||
import org.qortal.crosschain.Bitcoin;
|
import org.qortal.crosschain.Bitcoin;
|
||||||
import org.qortal.crypto.Crypto;
|
import org.qortal.crypto.Crypto;
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.settings.Settings;
|
import org.qortal.settings.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -160,6 +162,68 @@ public enum QortalFunctionCode {
|
|||||||
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||||
convertAddressInB(Crypto.ADDRESS_VERSION, state);
|
convertAddressInB(Crypto.ADDRESS_VERSION, state);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Returns account level of account in B.<br>
|
||||||
|
* <tt>0x0520</tt><br>
|
||||||
|
* B should contain either Qortal address or public key,<br>
|
||||||
|
* e.g. as a result of calling function {@link org.ciyam.at.FunctionCode#PUT_ADDRESS_FROM_TX_IN_A_INTO_B}</code>.
|
||||||
|
* <p></p>
|
||||||
|
* Returns account level, or -1 if account unknown.
|
||||||
|
* <p></p>
|
||||||
|
* @see QortalATAPI#getAccountFromB(MachineState)
|
||||||
|
*/
|
||||||
|
GET_ACCOUNT_LEVEL_FROM_ACCOUNT_IN_B(0x0520, 0, true) {
|
||||||
|
@Override
|
||||||
|
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||||
|
QortalATAPI api = (QortalATAPI) state.getAPI();
|
||||||
|
Account account = api.getAccountFromB(state);
|
||||||
|
|
||||||
|
Integer accountLevel = null;
|
||||||
|
|
||||||
|
if (account != null) {
|
||||||
|
try {
|
||||||
|
accountLevel = account.getLevel();
|
||||||
|
} catch (DataException e) {
|
||||||
|
throw new RuntimeException("AT API unable to fetch account level?", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
functionData.returnValue = accountLevel != null
|
||||||
|
? accountLevel.longValue()
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Returns account's minted block count of account in B.<br>
|
||||||
|
* <tt>0x0521</tt><br>
|
||||||
|
* B should contain either Qortal address or public key,<br>
|
||||||
|
* e.g. as a result of calling function {@link org.ciyam.at.FunctionCode#PUT_ADDRESS_FROM_TX_IN_A_INTO_B}</code>.
|
||||||
|
* <p></p>
|
||||||
|
* Returns account level, or -1 if account unknown.
|
||||||
|
* <p></p>
|
||||||
|
* @see QortalATAPI#getAccountFromB(MachineState)
|
||||||
|
*/
|
||||||
|
GET_BLOCKS_MINTED_FROM_ACCOUNT_IN_B(0x0521, 0, true) {
|
||||||
|
@Override
|
||||||
|
protected void postCheckExecute(FunctionData functionData, MachineState state, short rawFunctionCode) throws ExecutionException {
|
||||||
|
QortalATAPI api = (QortalATAPI) state.getAPI();
|
||||||
|
Account account = api.getAccountFromB(state);
|
||||||
|
|
||||||
|
Integer blocksMinted = null;
|
||||||
|
|
||||||
|
if (account != null) {
|
||||||
|
try {
|
||||||
|
blocksMinted = account.getBlocksMinted();
|
||||||
|
} catch (DataException e) {
|
||||||
|
throw new RuntimeException("AT API unable to fetch account's minted block count?", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
functionData.returnValue = blocksMinted != null
|
||||||
|
? blocksMinted.longValue()
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final short value;
|
public final short value;
|
||||||
|
@ -76,6 +76,9 @@ public interface AccountRepository {
|
|||||||
*/
|
*/
|
||||||
public void setBlocksMintedAdjustment(AccountData accountData) throws DataException;
|
public void setBlocksMintedAdjustment(AccountData accountData) throws DataException;
|
||||||
|
|
||||||
|
/** Returns account's minted block count or null if account not found. */
|
||||||
|
public Integer getMintedBlockCount(String address) throws DataException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves account's minted block count and public key if present, in repository.
|
* Saves account's minted block count and public key if present, in repository.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -241,6 +241,20 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getMintedBlockCount(String address) throws DataException {
|
||||||
|
String sql = "SELECT blocks_minted FROM Accounts WHERE account = ?";
|
||||||
|
|
||||||
|
try (ResultSet resultSet = this.repository.checkedExecute(sql, address)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return resultSet.getInt(1);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch account's minted block count from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMintedBlockCount(AccountData accountData) throws DataException {
|
public void setMintedBlockCount(AccountData accountData) throws DataException {
|
||||||
HSQLDBSaver saveHelper = new HSQLDBSaver("Accounts");
|
HSQLDBSaver saveHelper = new HSQLDBSaver("Accounts");
|
||||||
|
@ -0,0 +1,186 @@
|
|||||||
|
package org.qortal.test.at.qortalfunctioncodes;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import org.ciyam.at.CompilationException;
|
||||||
|
import org.ciyam.at.FunctionCode;
|
||||||
|
import org.ciyam.at.MachineState;
|
||||||
|
import org.ciyam.at.OpCode;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.qortal.account.Account;
|
||||||
|
import org.qortal.account.PrivateKeyAccount;
|
||||||
|
import org.qortal.at.QortalFunctionCode;
|
||||||
|
import org.qortal.data.at.ATStateData;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.repository.RepositoryManager;
|
||||||
|
import org.qortal.test.common.AtUtils;
|
||||||
|
import org.qortal.test.common.BlockUtils;
|
||||||
|
import org.qortal.test.common.Common;
|
||||||
|
import org.qortal.test.common.TestAccount;
|
||||||
|
import org.qortal.transaction.DeployAtTransaction;
|
||||||
|
import org.qortal.utils.Base58;
|
||||||
|
import org.qortal.utils.BitTwiddling;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
public class GetAccountBlocksMintedTests extends Common {
|
||||||
|
|
||||||
|
private static final Random RANDOM = new Random();
|
||||||
|
private static final long fundingAmount = 1_00000000L;
|
||||||
|
|
||||||
|
private Repository repository = null;
|
||||||
|
private byte[] creationBytes = null;
|
||||||
|
private PrivateKeyAccount deployer;
|
||||||
|
private DeployAtTransaction deployAtTransaction;
|
||||||
|
private String atAddress;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws DataException {
|
||||||
|
Common.useDefaultSettings();
|
||||||
|
|
||||||
|
this.repository = RepositoryManager.getRepository();
|
||||||
|
this.deployer = Common.getTestAccount(repository, "alice");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws DataException {
|
||||||
|
if (this.repository != null)
|
||||||
|
this.repository.close();
|
||||||
|
|
||||||
|
this.repository = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccountBlocksMintedFromAddress() throws DataException {
|
||||||
|
Account alice = Common.getTestAccount(repository, "alice");
|
||||||
|
byte[] accountBytes = Bytes.ensureCapacity(Base58.decode(alice.getAddress()), 32, 0);
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountBlocksMintedAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run - Alice's blocksMinted is incremented AFTER block is processed / AT is run
|
||||||
|
Integer expectedBlocksMinted = alice.getBlocksMinted();
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedBlocksMinted = extractBlocksMinted(repository, atAddress);
|
||||||
|
assertEquals(expectedBlocksMinted, extractedBlocksMinted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccountBlocksMintedFromPublicKey() throws DataException {
|
||||||
|
TestAccount alice = Common.getTestAccount(repository, "alice");
|
||||||
|
byte[] accountBytes = alice.getPublicKey();
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountBlocksMintedAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run - Alice's blocksMinted is incremented AFTER block is processed / AT is run
|
||||||
|
Integer expectedBlocksMinted = alice.getBlocksMinted();
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedBlocksMinted = extractBlocksMinted(repository, atAddress);
|
||||||
|
assertEquals(expectedBlocksMinted, extractedBlocksMinted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUnknownAccountBlocksMinted() throws DataException {
|
||||||
|
byte[] accountBytes = new byte[32];
|
||||||
|
RANDOM.nextBytes(accountBytes);
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountBlocksMintedAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run - Alice's blocksMinted is incremented AFTER block is processed / AT is run
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedBlocksMinted = extractBlocksMinted(repository, atAddress);
|
||||||
|
assertNull(extractedBlocksMinted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] buildGetAccountBlocksMintedAT(byte[] accountBytes) {
|
||||||
|
// Labels for data segment addresses
|
||||||
|
int addrCounter = 0;
|
||||||
|
|
||||||
|
// Beginning of data segment for easy extraction
|
||||||
|
final int addrBlocksMinted = addrCounter++;
|
||||||
|
|
||||||
|
// accountBytes
|
||||||
|
final int addrAccountBytes = addrCounter;
|
||||||
|
addrCounter += 4;
|
||||||
|
|
||||||
|
// Pointer to accountBytes so we can load them into B
|
||||||
|
final int addrAccountBytesPointer = addrCounter++;
|
||||||
|
|
||||||
|
// Data segment
|
||||||
|
ByteBuffer dataByteBuffer = ByteBuffer.allocate(addrCounter * MachineState.VALUE_SIZE);
|
||||||
|
|
||||||
|
// Write accountBytes
|
||||||
|
dataByteBuffer.position(addrAccountBytes * MachineState.VALUE_SIZE);
|
||||||
|
dataByteBuffer.put(accountBytes);
|
||||||
|
|
||||||
|
// Store pointer to addrAccountbytes at addrAccountBytesPointer
|
||||||
|
assertEquals(addrAccountBytesPointer * MachineState.VALUE_SIZE, dataByteBuffer.position());
|
||||||
|
dataByteBuffer.putLong(addrAccountBytes);
|
||||||
|
|
||||||
|
ByteBuffer codeByteBuffer = ByteBuffer.allocate(512);
|
||||||
|
|
||||||
|
// Two-pass version
|
||||||
|
for (int pass = 0; pass < 2; ++pass) {
|
||||||
|
codeByteBuffer.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Initialization */
|
||||||
|
|
||||||
|
// Copy accountBytes from data segment into B, starting at addrAccountBytes (as pointed to by addrAccountBytesPointer)
|
||||||
|
codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.SET_B_IND, addrAccountBytesPointer));
|
||||||
|
|
||||||
|
// Get account's blocks minted count and save into addrBlocksMinted
|
||||||
|
codeByteBuffer.put(OpCode.EXT_FUN_RET.compile(QortalFunctionCode.GET_BLOCKS_MINTED_FROM_ACCOUNT_IN_B.value, addrBlocksMinted));
|
||||||
|
|
||||||
|
// We're done
|
||||||
|
codeByteBuffer.put(OpCode.FIN_IMD.compile());
|
||||||
|
} catch (CompilationException e) {
|
||||||
|
throw new IllegalStateException("Unable to compile AT?", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codeByteBuffer.flip();
|
||||||
|
|
||||||
|
byte[] codeBytes = new byte[codeByteBuffer.limit()];
|
||||||
|
codeByteBuffer.get(codeBytes);
|
||||||
|
|
||||||
|
final short ciyamAtVersion = 2;
|
||||||
|
final short numCallStackPages = 0;
|
||||||
|
final short numUserStackPages = 0;
|
||||||
|
final long minActivationAmount = 0L;
|
||||||
|
|
||||||
|
return MachineState.toCreationBytes(ciyamAtVersion, codeBytes, dataByteBuffer.array(), numCallStackPages, numUserStackPages, minActivationAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractBlocksMinted(Repository repository, String atAddress) throws DataException {
|
||||||
|
// Check AT result
|
||||||
|
ATStateData atStateData = repository.getATRepository().getLatestATState(atAddress);
|
||||||
|
byte[] stateData = atStateData.getStateData();
|
||||||
|
|
||||||
|
byte[] dataBytes = MachineState.extractDataBytes(stateData);
|
||||||
|
|
||||||
|
Long blocksMintedValue = BitTwiddling.longFromBEBytes(dataBytes, 0);
|
||||||
|
if (blocksMintedValue == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return blocksMintedValue.intValue();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
package org.qortal.test.at.qortalfunctioncodes;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import org.ciyam.at.CompilationException;
|
||||||
|
import org.ciyam.at.FunctionCode;
|
||||||
|
import org.ciyam.at.MachineState;
|
||||||
|
import org.ciyam.at.OpCode;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.qortal.account.Account;
|
||||||
|
import org.qortal.account.PrivateKeyAccount;
|
||||||
|
import org.qortal.at.QortalFunctionCode;
|
||||||
|
import org.qortal.data.at.ATStateData;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.repository.RepositoryManager;
|
||||||
|
import org.qortal.test.common.AtUtils;
|
||||||
|
import org.qortal.test.common.BlockUtils;
|
||||||
|
import org.qortal.test.common.Common;
|
||||||
|
import org.qortal.test.common.TestAccount;
|
||||||
|
import org.qortal.transaction.DeployAtTransaction;
|
||||||
|
import org.qortal.utils.Base58;
|
||||||
|
import org.qortal.utils.BitTwiddling;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
public class GetAccountLevelTests extends Common {
|
||||||
|
|
||||||
|
private static final Random RANDOM = new Random();
|
||||||
|
private static final long fundingAmount = 1_00000000L;
|
||||||
|
|
||||||
|
private Repository repository = null;
|
||||||
|
private byte[] creationBytes = null;
|
||||||
|
private PrivateKeyAccount deployer;
|
||||||
|
private DeployAtTransaction deployAtTransaction;
|
||||||
|
private String atAddress;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws DataException {
|
||||||
|
Common.useDefaultSettings();
|
||||||
|
|
||||||
|
this.repository = RepositoryManager.getRepository();
|
||||||
|
this.deployer = Common.getTestAccount(repository, "alice");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws DataException {
|
||||||
|
if (this.repository != null)
|
||||||
|
this.repository.close();
|
||||||
|
|
||||||
|
this.repository = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccountLevelFromAddress() throws DataException {
|
||||||
|
Account dilbert = Common.getTestAccount(repository, "dilbert");
|
||||||
|
byte[] accountBytes = Bytes.ensureCapacity(Base58.decode(dilbert.getAddress()), 32, 0);
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountLevelAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedAccountLevel = extractAccountLevel(repository, atAddress);
|
||||||
|
assertEquals(dilbert.getLevel(), extractedAccountLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAccountLevelFromPublicKey() throws DataException {
|
||||||
|
TestAccount dilbert = Common.getTestAccount(repository, "dilbert");
|
||||||
|
byte[] accountBytes = dilbert.getPublicKey();
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountLevelAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedAccountLevel = extractAccountLevel(repository, atAddress);
|
||||||
|
assertEquals(dilbert.getLevel(), extractedAccountLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUnknownAccountLevel() throws DataException {
|
||||||
|
byte[] accountBytes = new byte[32];
|
||||||
|
RANDOM.nextBytes(accountBytes);
|
||||||
|
|
||||||
|
this.creationBytes = buildGetAccountLevelAT(accountBytes);
|
||||||
|
|
||||||
|
this.deployAtTransaction = AtUtils.doDeployAT(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
|
||||||
|
// Mint a block to allow AT to run
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
Integer extractedAccountLevel = extractAccountLevel(repository, atAddress);
|
||||||
|
assertNull(extractedAccountLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] buildGetAccountLevelAT(byte[] accountBytes) {
|
||||||
|
// Labels for data segment addresses
|
||||||
|
int addrCounter = 0;
|
||||||
|
|
||||||
|
// Beginning of data segment for easy extraction
|
||||||
|
final int addrAccountLevel = addrCounter++;
|
||||||
|
|
||||||
|
// accountBytes
|
||||||
|
final int addrAccountBytes = addrCounter;
|
||||||
|
addrCounter += 4;
|
||||||
|
|
||||||
|
// Pointer to accountBytes so we can load them into B
|
||||||
|
final int addrAccountBytesPointer = addrCounter++;
|
||||||
|
|
||||||
|
// Data segment
|
||||||
|
ByteBuffer dataByteBuffer = ByteBuffer.allocate(addrCounter * MachineState.VALUE_SIZE);
|
||||||
|
|
||||||
|
// Write accountBytes
|
||||||
|
dataByteBuffer.position(addrAccountBytes * MachineState.VALUE_SIZE);
|
||||||
|
dataByteBuffer.put(accountBytes);
|
||||||
|
|
||||||
|
// Store pointer to addrAccountbytes at addrAccountBytesPointer
|
||||||
|
assertEquals(addrAccountBytesPointer * MachineState.VALUE_SIZE, dataByteBuffer.position());
|
||||||
|
dataByteBuffer.putLong(addrAccountBytes);
|
||||||
|
|
||||||
|
ByteBuffer codeByteBuffer = ByteBuffer.allocate(512);
|
||||||
|
|
||||||
|
// Two-pass version
|
||||||
|
for (int pass = 0; pass < 2; ++pass) {
|
||||||
|
codeByteBuffer.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Initialization */
|
||||||
|
|
||||||
|
// Copy accountBytes from data segment into B, starting at addrAccountBytes (as pointed to by addrAccountBytesPointer)
|
||||||
|
codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.SET_B_IND, addrAccountBytesPointer));
|
||||||
|
|
||||||
|
// Get account level and save into addrAccountLevel
|
||||||
|
codeByteBuffer.put(OpCode.EXT_FUN_RET.compile(QortalFunctionCode.GET_ACCOUNT_LEVEL_FROM_ACCOUNT_IN_B.value, addrAccountLevel));
|
||||||
|
|
||||||
|
// We're done
|
||||||
|
codeByteBuffer.put(OpCode.FIN_IMD.compile());
|
||||||
|
} catch (CompilationException e) {
|
||||||
|
throw new IllegalStateException("Unable to compile AT?", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codeByteBuffer.flip();
|
||||||
|
|
||||||
|
byte[] codeBytes = new byte[codeByteBuffer.limit()];
|
||||||
|
codeByteBuffer.get(codeBytes);
|
||||||
|
|
||||||
|
final short ciyamAtVersion = 2;
|
||||||
|
final short numCallStackPages = 0;
|
||||||
|
final short numUserStackPages = 0;
|
||||||
|
final long minActivationAmount = 0L;
|
||||||
|
|
||||||
|
return MachineState.toCreationBytes(ciyamAtVersion, codeBytes, dataByteBuffer.array(), numCallStackPages, numUserStackPages, minActivationAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractAccountLevel(Repository repository, String atAddress) throws DataException {
|
||||||
|
// Check AT result
|
||||||
|
ATStateData atStateData = repository.getATRepository().getLatestATState(atAddress);
|
||||||
|
byte[] stateData = atStateData.getStateData();
|
||||||
|
|
||||||
|
byte[] dataBytes = MachineState.extractDataBytes(stateData);
|
||||||
|
|
||||||
|
Long accountLevelValue = BitTwiddling.longFromBEBytes(dataBytes, 0);
|
||||||
|
if (accountLevelValue == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return accountLevelValue.intValue();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user