Search in sources :

Example 36 with AccountState

use of org.aion.base.AccountState in project aion by aionnetwork.

the class TransactionCreateSpecificationTests method deployInternalAvmContractOnTopOfAddressWithStorageUsingAvmVersion2_DeployAndRequireSuccess.

@Test
public void deployInternalAvmContractOnTopOfAddressWithStorageUsingAvmVersion2_DeployAndRequireSuccess() throws VmFatalException {
    // Deploy AVM contract.
    AionTransaction deployTxAvm = BlockchainTestUtils.deployAvmContractTransaction(AvmContract.DEPLOY_INTERNAL, resourceProvider.factoryForVersion2, SENDER_KEY, BigInteger.ZERO);
    AionAddress contract = TxUtil.calculateContractAddress(deployTxAvm);
    Pair<Block, ImportResult> resultImport = BlockchainTestUtils.addMiningBlock(blockchain, blockchain.getBestBlock(), List.of(deployTxAvm));
    assertThat(resultImport.getRight()).isEqualTo(ImportResult.IMPORTED_BEST);
    // Call AVM contract to deploy new internal AVM contract (version with required success).
    long internalLimit = 1_000_000;
    AionTransaction deployInternal = BlockchainTestUtils.callSimpleAvmContractTransaction(resourceProvider.factoryForVersion2, SENDER_KEY, BigInteger.ONE, contract, "deployAndRequireSuccess", deployTxAvm.getData(), internalLimit);
    AionAddress internalContract = new AionAddress(Hex.decode("a0268090998a99666b72cc452b9307438a34341047d9e0d7b92c9207bf413655"));
    assertThat(blockchain.getRepository().hasAccountState(internalContract)).isFalse();
    // Manipulate the repository to have a non-default storage value.
    RepositoryCache cache = blockchain.getRepository().startTracking();
    cache.addStorageRow(internalContract, ByteArrayWrapper.wrap(RandomUtils.nextBytes(16)), ByteArrayWrapper.wrap(RandomUtils.nextBytes(16)));
    cache.saveVmType(internalContract, InternalVmType.AVM);
    cache.flushTo(cache.getParent(), true);
    // Check assumptions about contract state.
    AccountState contractState = (AccountState) blockchain.getRepository().startTracking().getAccountState(internalContract);
    assertThat(contractState.getBalance()).isEqualTo(BigInteger.ZERO);
    assertThat(contractState.getNonce()).isEqualTo(BigInteger.ZERO);
    assertThat(contractState.getStateRoot()).isNotEqualTo(EMPTY_TRIE_HASH);
    assertThat(contractState.getCodeHash()).isEqualTo(EMPTY_DATA_HASH);
    byte[] oldRoot = contractState.getStateRoot();
    // Next, process the deploy transaction with fork040 enabled.
    AionTxExecSummary result = executeTransaction(deployInternal, true);
    assertThat(result.isFailed()).isTrue();
    assertThat(result.getReceipt().getError()).isEqualTo("reverted");
    assertThat(result.getNrgUsed()).isLessThan(BigInteger.valueOf(deployInternal.getEnergyLimit()));
    assertThat(result.getLogs()).isEmpty();
    InternalTransaction itx = result.getInternalTransactions().get(0);
    assertThat(itx.isCreate).isTrue();
    assertThat(TxUtil.calculateContractAddress(itx)).isEqualTo(internalContract);
    assertThat(itx.isRejected).isTrue();
    assertThat(itx.energyLimit).isEqualTo(internalLimit);
    assertThat(result.getNrgUsed()).isGreaterThan(BigInteger.valueOf(itx.energyLimit));
    contractState = (AccountState) blockchain.getRepository().startTracking().getAccountState(internalContract);
    assertThat(contractState.getBalance()).isEqualTo(BigInteger.ZERO);
    assertThat(contractState.getNonce()).isEqualTo(BigInteger.ZERO);
    assertThat(contractState.getStateRoot()).isEqualTo(oldRoot);
    assertThat(contractState.getCodeHash()).isEqualTo(EMPTY_DATA_HASH);
}
Also used : AionAddress(org.aion.types.AionAddress) ImportResult(org.aion.zero.impl.core.ImportResult) AionTxExecSummary(org.aion.base.AionTxExecSummary) AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock(org.aion.zero.impl.blockchain.AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock) Block(org.aion.zero.impl.types.Block) RepositoryCache(org.aion.base.db.RepositoryCache) AionTransaction(org.aion.base.AionTransaction) AccountState(org.aion.base.AccountState) InternalTransaction(org.aion.types.InternalTransaction) Test(org.junit.Test)

Example 37 with AccountState

use of org.aion.base.AccountState in project aion by aionnetwork.

the class AionRepositoryCacheTest method testLoadAccountState_withExistingAccountFromRepository.

@Test
public void testLoadAccountState_withExistingAccountFromRepository() {
    AionAddress address = new AionAddress(RandomUtils.nextBytes(AionAddress.LENGTH));
    byte[] code = RandomUtils.nextBytes(100);
    byte[] codeHash = h256(code);
    // initialize contract in the repository
    RepositoryCache tempCache = repository.startTracking();
    tempCache.createAccount(address);
    tempCache.saveCode(address, code);
    tempCache.saveVmType(address, InternalVmType.FVM);
    tempCache.addBalance(address, BigInteger.TEN);
    tempCache.flushTo(repository, true);
    AionRepositoryCache tracker = (AionRepositoryCache) cache.startTracking();
    assertThat(tracker.hasAccountState(address)).isTrue();
    assertThat(tracker.hasContractDetails(address)).isTrue();
    assertThat(tracker.cachedAccounts.containsKey(address)).isFalse();
    assertThat(tracker.cachedDetails.containsKey(address)).isFalse();
    // load account state for new address
    AccountState account = tracker.getAccountState(address);
    InnerContractDetails details = (InnerContractDetails) tracker.getContractDetails(address);
    // 1. Ensure new account and details were created
    assertThat(tracker.cachedAccounts.containsKey(address)).isTrue();
    assertThat(tracker.cachedDetails.containsKey(address)).isTrue();
    assertThat(account.getBalance()).isEqualTo(BigInteger.TEN);
    assertThat(account.getNonce()).isEqualTo(BigInteger.ZERO);
    assertThat(account.getCodeHash()).isEqualTo(codeHash);
    assertThat(account.getStateRoot()).isEqualTo(EMPTY_TRIE_HASH);
    assertThat(details.origContract).isNotNull();
    assertThat(details.getCode(codeHash)).isEqualTo(code);
    assertThat(details.getVmType()).isEqualTo(InternalVmType.FVM);
    assertThat(details.isDeleted()).isFalse();
    assertThat(details.isDirty()).isFalse();
    // 2. Ensure that the cache does not contain the account and details
    assertThat(cache.cachedAccounts.containsKey(address)).isFalse();
    assertThat(cache.cachedDetails.containsKey(address)).isFalse();
    // 3. Ensure that the repository does contain the account and details
    assertThat(repository.hasAccountState(address)).isTrue();
    assertThat(repository.hasContractDetails(address)).isTrue();
}
Also used : AionAddress(org.aion.types.AionAddress) RepositoryCache(org.aion.base.db.RepositoryCache) AccountState(org.aion.base.AccountState) Test(org.junit.Test)

Example 38 with AccountState

use of org.aion.base.AccountState in project aion by aionnetwork.

the class AionRepositoryCache method flushTo.

@Override
public void flushTo(Repository other, boolean clearStateAfterFlush) {
    lock.lock();
    try {
        // determine which accounts should get stored
        HashMap<AionAddress, AccountState> cleanedCacheAccounts = new HashMap<>();
        for (Map.Entry<AionAddress, AccountState> entry : cachedAccounts.entrySet()) {
            AccountState account = entry.getValue();
            if (account != null && account.isDirty() && account.isEmpty()) {
                // ignore contract state for empty accounts at storage
                cachedDetails.remove(entry.getKey());
            } else {
                cleanedCacheAccounts.put(entry.getKey(), entry.getValue());
            }
        }
        // determine which contracts should get stored
        for (Map.Entry<AionAddress, ContractDetail> entry : cachedDetails.entrySet()) {
            InnerContractDetails contractDetailsCache = (InnerContractDetails) entry.getValue();
            contractDetailsCache.commit();
            if (contractDetailsCache.origContract == null && other.hasContractDetails(entry.getKey())) {
                // in forked block the contract account might not exist thus it is created without origin,
                // but on the main chain details can contain data which should be merged into a single storage trie
                // so both branches with different stateRoots are valid
                contractDetailsCache.origContract = (ContractDetails) other.getContractDetails(entry.getKey());
                contractDetailsCache.commit();
            }
        }
        other.updateBatch(cleanedCacheAccounts, cachedDetails, cachedTransformedCode);
        if (clearStateAfterFlush) {
            cachedAccounts.clear();
            cachedDetails.clear();
            cachedTransformedCode.clear();
        }
    } finally {
        lock.unlock();
    }
}
Also used : AionAddress(org.aion.types.AionAddress) HashMap(java.util.HashMap) ContractDetail(org.aion.base.db.ContractDetail) AccountState(org.aion.base.AccountState) HashMap(java.util.HashMap) Map(java.util.Map)

Example 39 with AccountState

use of org.aion.base.AccountState in project aion by aionnetwork.

the class AionRepositoryCache method getLocalAccountState.

private AccountState getLocalAccountState(AionAddress address) {
    // check if the account is cached locally
    AccountState accountState = this.cachedAccounts.get(address);
    // when the account is not cached load it from the repository
    if (accountState == null) {
        Pair<AccountState, InnerContractDetails> pair = getAccountStateFromParent(address);
        this.cachedAccounts.put(address, pair.getLeft());
        this.cachedDetails.put(address, pair.getRight());
        accountState = pair.getLeft();
    }
    return accountState;
}
Also used : AccountState(org.aion.base.AccountState)

Example 40 with AccountState

use of org.aion.base.AccountState in project aion by aionnetwork.

the class AionRepositoryImpl method updateBatch.

@Override
public void updateBatch(Map<AionAddress, AccountState> stateCache, Map<AionAddress, ContractDetail> detailsCache, Map<AionAddress, TransformedCodeInfoInterface> transformedCodeCache) {
    rwLock.writeLock().lock();
    try {
        for (Map.Entry<AionAddress, AccountState> entry : stateCache.entrySet()) {
            AionAddress address = entry.getKey();
            AccountState accountState = entry.getValue();
            ContractDetails contractDetails = (ContractDetails) detailsCache.get(address);
            if (accountState.isDeleted()) {
                // TODO-A: batch operations here
                try {
                    worldState.delete(address.toByteArray());
                } catch (Exception e) {
                    LOG.error("key deleted exception [{}]", e.toString());
                }
                if (LOG.isDebugEnabled()) {
                    LOG.debug("key deleted <key={}>", Hex.toHexString(address.toByteArray()));
                }
            } else {
                if (!contractDetails.isDirty() || (contractDetails.getVmType() == InternalVmType.EITHER && !ContractInfo.isPrecompiledContract(address))) {
                    // ContractState class
                    if (accountState.isDirty()) {
                        updateAccountState(address, accountState);
                        if (LOG.isTraceEnabled()) {
                            LOG.trace("update: [{}],nonce: [{}] balance: [{}] [{}]", Hex.toHexString(address.toByteArray()), accountState.getNonce(), accountState.getBalance(), Hex.toHexString(contractDetails.getStorageHash()));
                        }
                    }
                    continue;
                }
                InnerContractDetails contractDetailsCache = (InnerContractDetails) contractDetails;
                if (contractDetailsCache.origContract == null) {
                    contractDetailsCache.origContract = detailsDS.newContractDetails(address, contractDetailsCache.getVmType());
                    contractDetailsCache.commit();
                }
                StoredContractDetails parentDetails = (StoredContractDetails) contractDetailsCache.origContract;
                // this method requires the encoding functionality therefore can be applied only to StoredContractDetails
                detailsDS.update(address, parentDetails);
                accountState.setStateRoot(parentDetails.getStorageHash());
                updateAccountState(address, accountState);
                cachedContractIndex.put(address, Pair.of(ByteArrayWrapper.wrap(accountState.getCodeHash()), parentDetails.getVmType()));
                if (LOG.isTraceEnabled()) {
                    LOG.trace("update: [{}],nonce: [{}] balance: [{}] [{}]", Hex.toHexString(address.toByteArray()), accountState.getNonce(), accountState.getBalance(), Hex.toHexString(parentDetails.getStorageHash()));
                }
            }
        }
        for (Map.Entry<AionAddress, TransformedCodeInfoInterface> entry : transformedCodeCache.entrySet()) {
            for (Map.Entry<ByteArrayWrapper, Map<Integer, byte[]>> infoMap : ((TransformedCodeInfo) entry.getValue()).transformedCodeMap.entrySet()) {
                for (Map.Entry<Integer, byte[]> innerEntry : infoMap.getValue().entrySet()) {
                    setTransformedCode(entry.getKey(), infoMap.getKey().toBytes(), innerEntry.getKey(), innerEntry.getValue());
                }
            }
        }
        LOG.trace("updated: detailsCache.size: {}", detailsCache.size());
        stateCache.clear();
        detailsCache.clear();
        transformedCodeCache.clear();
    } finally {
        rwLock.writeLock().unlock();
    }
}
Also used : TransformedCodeInfoInterface(org.aion.base.db.TransformedCodeInfoInterface) AionAddress(org.aion.types.AionAddress) AccountState(org.aion.base.AccountState) IOException(java.io.IOException) BigInteger(java.math.BigInteger) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

AccountState (org.aion.base.AccountState)71 AionAddress (org.aion.types.AionAddress)54 Test (org.junit.Test)46 AionTransaction (org.aion.base.AionTransaction)40 RepositoryCache (org.aion.base.db.RepositoryCache)38 AionTxExecSummary (org.aion.base.AionTxExecSummary)37 Block (org.aion.zero.impl.types.Block)21 ImportResult (org.aion.zero.impl.core.ImportResult)20 BigInteger (java.math.BigInteger)18 InternalTransaction (org.aion.types.InternalTransaction)17 AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock (org.aion.zero.impl.blockchain.AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock)16 AionTxReceipt (org.aion.base.AionTxReceipt)11 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)10 ArrayList (java.util.ArrayList)8 InternalVmType (org.aion.base.InternalVmType)5 IOException (java.io.IOException)4 HashMap (java.util.HashMap)4 Map (java.util.Map)4 JSONObject (org.json.JSONObject)4 Hex.toHexString (org.aion.util.conversions.Hex.toHexString)3